NaccacheSternEngine.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.Collections;
  5. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  6. using BestHTTP.SecureProtocol.Org.BouncyCastle.Math;
  7. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  8. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Engines
  9. {
  10. /**
  11. * NaccacheStern Engine. For details on this cipher, please see
  12. * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf
  13. */
  14. public class NaccacheSternEngine
  15. : IAsymmetricBlockCipher
  16. {
  17. private bool forEncryption;
  18. private NaccacheSternKeyParameters key;
  19. private IList[] lookup = null;
  20. public string AlgorithmName
  21. {
  22. get { return "NaccacheStern"; }
  23. }
  24. /**
  25. * Initializes this algorithm. Must be called before all other Functions.
  26. *
  27. * @see org.bouncycastle.crypto.AsymmetricBlockCipher#init(bool,
  28. * org.bouncycastle.crypto.CipherParameters)
  29. */
  30. public virtual void Init(
  31. bool forEncryption,
  32. ICipherParameters parameters)
  33. {
  34. this.forEncryption = forEncryption;
  35. if (parameters is ParametersWithRandom)
  36. {
  37. parameters = ((ParametersWithRandom) parameters).Parameters;
  38. }
  39. key = (NaccacheSternKeyParameters)parameters;
  40. // construct lookup table for faster decryption if necessary
  41. if (!this.forEncryption)
  42. {
  43. NaccacheSternPrivateKeyParameters priv = (NaccacheSternPrivateKeyParameters)key;
  44. IList primes = priv.SmallPrimesList;
  45. lookup = new IList[primes.Count];
  46. for (int i = 0; i < primes.Count; i++)
  47. {
  48. BigInteger actualPrime = (BigInteger) primes[i];
  49. int actualPrimeValue = actualPrime.IntValue;
  50. lookup[i] = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateArrayList(actualPrimeValue);
  51. lookup[i].Add(BigInteger.One);
  52. BigInteger accJ = BigInteger.Zero;
  53. for (int j = 1; j < actualPrimeValue; j++)
  54. {
  55. // BigInteger bigJ = BigInteger.ValueOf(j);
  56. // accJ = priv.PhiN.Multiply(bigJ);
  57. accJ = accJ.Add(priv.PhiN);
  58. BigInteger comp = accJ.Divide(actualPrime);
  59. lookup[i].Add(priv.G.ModPow(comp, priv.Modulus));
  60. }
  61. }
  62. }
  63. }
  64. public virtual bool Debug
  65. {
  66. set {}
  67. }
  68. /**
  69. * Returns the input block size of this algorithm.
  70. *
  71. * @see org.bouncycastle.crypto.AsymmetricBlockCipher#GetInputBlockSize()
  72. */
  73. public virtual int GetInputBlockSize()
  74. {
  75. if (forEncryption)
  76. {
  77. // We can only encrypt values up to lowerSigmaBound
  78. return (key.LowerSigmaBound + 7) / 8 - 1;
  79. }
  80. else
  81. {
  82. // We pad to modulus-size bytes for easier decryption.
  83. // return key.Modulus.ToByteArray().Length;
  84. return key.Modulus.BitLength / 8 + 1;
  85. }
  86. }
  87. /**
  88. * Returns the output block size of this algorithm.
  89. *
  90. * @see org.bouncycastle.crypto.AsymmetricBlockCipher#GetOutputBlockSize()
  91. */
  92. public virtual int GetOutputBlockSize()
  93. {
  94. if (forEncryption)
  95. {
  96. // encrypted Data is always padded up to modulus size
  97. // return key.Modulus.ToByteArray().Length;
  98. return key.Modulus.BitLength / 8 + 1;
  99. }
  100. else
  101. {
  102. // decrypted Data has upper limit lowerSigmaBound
  103. return (key.LowerSigmaBound + 7) / 8 - 1;
  104. }
  105. }
  106. /**
  107. * Process a single Block using the Naccache-Stern algorithm.
  108. *
  109. * @see org.bouncycastle.crypto.AsymmetricBlockCipher#ProcessBlock(byte[],
  110. * int, int)
  111. */
  112. public virtual byte[] ProcessBlock(
  113. byte[] inBytes,
  114. int inOff,
  115. int length)
  116. {
  117. if (key == null)
  118. throw new InvalidOperationException("NaccacheStern engine not initialised");
  119. if (length > (GetInputBlockSize() + 1))
  120. throw new DataLengthException("input too large for Naccache-Stern cipher.\n");
  121. if (!forEncryption)
  122. {
  123. // At decryption make sure that we receive padded data blocks
  124. if (length < GetInputBlockSize())
  125. {
  126. throw new InvalidCipherTextException("BlockLength does not match modulus for Naccache-Stern cipher.\n");
  127. }
  128. }
  129. // transform input into BigInteger
  130. BigInteger input = new BigInteger(1, inBytes, inOff, length);
  131. byte[] output;
  132. if (forEncryption)
  133. {
  134. output = Encrypt(input);
  135. }
  136. else
  137. {
  138. IList plain = BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Platform.CreateArrayList();
  139. NaccacheSternPrivateKeyParameters priv = (NaccacheSternPrivateKeyParameters)key;
  140. IList primes = priv.SmallPrimesList;
  141. // Get Chinese Remainders of CipherText
  142. for (int i = 0; i < primes.Count; i++)
  143. {
  144. BigInteger exp = input.ModPow(priv.PhiN.Divide((BigInteger)primes[i]), priv.Modulus);
  145. IList al = lookup[i];
  146. if (lookup[i].Count != ((BigInteger)primes[i]).IntValue)
  147. {
  148. throw new InvalidCipherTextException("Error in lookup Array for "
  149. + ((BigInteger)primes[i]).IntValue
  150. + ": Size mismatch. Expected ArrayList with length "
  151. + ((BigInteger)primes[i]).IntValue + " but found ArrayList of length "
  152. + lookup[i].Count);
  153. }
  154. int lookedup = al.IndexOf(exp);
  155. if (lookedup == -1)
  156. {
  157. throw new InvalidCipherTextException("Lookup failed");
  158. }
  159. plain.Add(BigInteger.ValueOf(lookedup));
  160. }
  161. BigInteger test = chineseRemainder(plain, primes);
  162. // Should not be used as an oracle, so reencrypt output to see
  163. // if it corresponds to input
  164. // this breaks probabilisic encryption, so disable it. Anyway, we do
  165. // use the first n primes for key generation, so it is pretty easy
  166. // to guess them. But as stated in the paper, this is not a security
  167. // breach. So we can just work with the correct sigma.
  168. // if ((key.G.ModPow(test, key.Modulus)).Equals(input)) {
  169. // output = test.ToByteArray();
  170. // } else {
  171. // output = null;
  172. // }
  173. output = test.ToByteArray();
  174. }
  175. return output;
  176. }
  177. /**
  178. * Encrypts a BigInteger aka Plaintext with the public key.
  179. *
  180. * @param plain
  181. * The BigInteger to encrypt
  182. * @return The byte[] representation of the encrypted BigInteger (i.e.
  183. * crypted.toByteArray())
  184. */
  185. public virtual byte[] Encrypt(
  186. BigInteger plain)
  187. {
  188. // Always return modulus size values 0-padded at the beginning
  189. // 0-padding at the beginning is correctly parsed by BigInteger :)
  190. // byte[] output = key.Modulus.ToByteArray();
  191. // Array.Clear(output, 0, output.Length);
  192. byte[] output = new byte[key.Modulus.BitLength / 8 + 1];
  193. byte[] tmp = key.G.ModPow(plain, key.Modulus).ToByteArray();
  194. Array.Copy(tmp, 0, output, output.Length - tmp.Length, tmp.Length);
  195. return output;
  196. }
  197. /**
  198. * Adds the contents of two encrypted blocks mod sigma
  199. *
  200. * @param block1
  201. * the first encrypted block
  202. * @param block2
  203. * the second encrypted block
  204. * @return encrypt((block1 + block2) mod sigma)
  205. * @throws InvalidCipherTextException
  206. */
  207. public virtual byte[] AddCryptedBlocks(
  208. byte[] block1,
  209. byte[] block2)
  210. {
  211. // check for correct blocksize
  212. if (forEncryption)
  213. {
  214. if ((block1.Length > GetOutputBlockSize())
  215. || (block2.Length > GetOutputBlockSize()))
  216. {
  217. throw new InvalidCipherTextException(
  218. "BlockLength too large for simple addition.\n");
  219. }
  220. }
  221. else
  222. {
  223. if ((block1.Length > GetInputBlockSize())
  224. || (block2.Length > GetInputBlockSize()))
  225. {
  226. throw new InvalidCipherTextException(
  227. "BlockLength too large for simple addition.\n");
  228. }
  229. }
  230. // calculate resulting block
  231. BigInteger m1Crypt = new BigInteger(1, block1);
  232. BigInteger m2Crypt = new BigInteger(1, block2);
  233. BigInteger m1m2Crypt = m1Crypt.Multiply(m2Crypt);
  234. m1m2Crypt = m1m2Crypt.Mod(key.Modulus);
  235. //byte[] output = key.Modulus.ToByteArray();
  236. //Array.Clear(output, 0, output.Length);
  237. byte[] output = new byte[key.Modulus.BitLength / 8 + 1];
  238. byte[] m1m2CryptBytes = m1m2Crypt.ToByteArray();
  239. Array.Copy(m1m2CryptBytes, 0, output,
  240. output.Length - m1m2CryptBytes.Length, m1m2CryptBytes.Length);
  241. return output;
  242. }
  243. /**
  244. * Convenience Method for data exchange with the cipher.
  245. *
  246. * Determines blocksize and splits data to blocksize.
  247. *
  248. * @param data the data to be processed
  249. * @return the data after it went through the NaccacheSternEngine.
  250. * @throws InvalidCipherTextException
  251. */
  252. public virtual byte[] ProcessData(
  253. byte[] data)
  254. {
  255. if (data.Length > GetInputBlockSize())
  256. {
  257. int inBlocksize = GetInputBlockSize();
  258. int outBlocksize = GetOutputBlockSize();
  259. int datapos = 0;
  260. int retpos = 0;
  261. byte[] retval = new byte[(data.Length / inBlocksize + 1) * outBlocksize];
  262. while (datapos < data.Length)
  263. {
  264. byte[] tmp;
  265. if (datapos + inBlocksize < data.Length)
  266. {
  267. tmp = ProcessBlock(data, datapos, inBlocksize);
  268. datapos += inBlocksize;
  269. }
  270. else
  271. {
  272. tmp = ProcessBlock(data, datapos, data.Length - datapos);
  273. datapos += data.Length - datapos;
  274. }
  275. if (tmp != null)
  276. {
  277. tmp.CopyTo(retval, retpos);
  278. retpos += tmp.Length;
  279. }
  280. else
  281. {
  282. throw new InvalidCipherTextException("cipher returned null");
  283. }
  284. }
  285. byte[] ret = new byte[retpos];
  286. Array.Copy(retval, 0, ret, 0, retpos);
  287. return ret;
  288. }
  289. else
  290. {
  291. return ProcessBlock(data, 0, data.Length);
  292. }
  293. }
  294. /**
  295. * Computes the integer x that is expressed through the given primes and the
  296. * congruences with the chinese remainder theorem (CRT).
  297. *
  298. * @param congruences
  299. * the congruences c_i
  300. * @param primes
  301. * the primes p_i
  302. * @return an integer x for that x % p_i == c_i
  303. */
  304. private static BigInteger chineseRemainder(IList congruences, IList primes)
  305. {
  306. BigInteger retval = BigInteger.Zero;
  307. BigInteger all = BigInteger.One;
  308. for (int i = 0; i < primes.Count; i++)
  309. {
  310. all = all.Multiply((BigInteger)primes[i]);
  311. }
  312. for (int i = 0; i < primes.Count; i++)
  313. {
  314. BigInteger a = (BigInteger)primes[i];
  315. BigInteger b = all.Divide(a);
  316. BigInteger b2 = b.ModInverse(a);
  317. BigInteger tmp = b.Multiply(b2);
  318. tmp = tmp.Multiply((BigInteger)congruences[i]);
  319. retval = retval.Add(tmp);
  320. }
  321. return retval.Mod(all);
  322. }
  323. }
  324. }
  325. #pragma warning restore
  326. #endif