NaccacheSternEngine.cs 9.7 KB

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