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