OaepEncoding.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Digests;
  5. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  6. using BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
  7. using BestHTTP.SecureProtocol.Org.BouncyCastle.Security;
  8. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  9. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Encodings
  10. {
  11. /**
  12. * Optimal Asymmetric Encryption Padding (OAEP) - see PKCS 1 V 2.
  13. */
  14. public class OaepEncoding
  15. : IAsymmetricBlockCipher
  16. {
  17. private byte[] defHash;
  18. private IDigest mgf1Hash;
  19. private IAsymmetricBlockCipher engine;
  20. private SecureRandom random;
  21. private bool forEncryption;
  22. public OaepEncoding(
  23. IAsymmetricBlockCipher cipher)
  24. : this(cipher, new Sha1Digest(), null)
  25. {
  26. }
  27. public OaepEncoding(
  28. IAsymmetricBlockCipher cipher,
  29. IDigest hash)
  30. : this(cipher, hash, null)
  31. {
  32. }
  33. public OaepEncoding(
  34. IAsymmetricBlockCipher cipher,
  35. IDigest hash,
  36. byte[] encodingParams)
  37. : this(cipher, hash, hash, encodingParams)
  38. {
  39. }
  40. public OaepEncoding(
  41. IAsymmetricBlockCipher cipher,
  42. IDigest hash,
  43. IDigest mgf1Hash,
  44. byte[] encodingParams)
  45. {
  46. this.engine = cipher;
  47. this.mgf1Hash = mgf1Hash;
  48. this.defHash = new byte[hash.GetDigestSize()];
  49. hash.Reset();
  50. if (encodingParams != null)
  51. {
  52. hash.BlockUpdate(encodingParams, 0, encodingParams.Length);
  53. }
  54. hash.DoFinal(defHash, 0);
  55. }
  56. public IAsymmetricBlockCipher GetUnderlyingCipher()
  57. {
  58. return engine;
  59. }
  60. public string AlgorithmName
  61. {
  62. get { return engine.AlgorithmName + "/OAEPPadding"; }
  63. }
  64. public void Init(
  65. bool forEncryption,
  66. ICipherParameters param)
  67. {
  68. if (param is ParametersWithRandom)
  69. {
  70. ParametersWithRandom rParam = (ParametersWithRandom)param;
  71. this.random = rParam.Random;
  72. }
  73. else
  74. {
  75. this.random = new SecureRandom();
  76. }
  77. engine.Init(forEncryption, param);
  78. this.forEncryption = forEncryption;
  79. }
  80. public int GetInputBlockSize()
  81. {
  82. int baseBlockSize = engine.GetInputBlockSize();
  83. if (forEncryption)
  84. {
  85. return baseBlockSize - 1 - 2 * defHash.Length;
  86. }
  87. else
  88. {
  89. return baseBlockSize;
  90. }
  91. }
  92. public int GetOutputBlockSize()
  93. {
  94. int baseBlockSize = engine.GetOutputBlockSize();
  95. if (forEncryption)
  96. {
  97. return baseBlockSize;
  98. }
  99. else
  100. {
  101. return baseBlockSize - 1 - 2 * defHash.Length;
  102. }
  103. }
  104. public byte[] ProcessBlock(
  105. byte[] inBytes,
  106. int inOff,
  107. int inLen)
  108. {
  109. if (forEncryption)
  110. {
  111. return EncodeBlock(inBytes, inOff, inLen);
  112. }
  113. else
  114. {
  115. return DecodeBlock(inBytes, inOff, inLen);
  116. }
  117. }
  118. private byte[] EncodeBlock(
  119. byte[] inBytes,
  120. int inOff,
  121. int inLen)
  122. {
  123. Check.DataLength(inLen > GetInputBlockSize(), "input data too long");
  124. byte[] block = new byte[GetInputBlockSize() + 1 + 2 * defHash.Length];
  125. //
  126. // copy in the message
  127. //
  128. Array.Copy(inBytes, inOff, block, block.Length - inLen, inLen);
  129. //
  130. // add sentinel
  131. //
  132. block[block.Length - inLen - 1] = 0x01;
  133. //
  134. // as the block is already zeroed - there's no need to add PS (the >= 0 pad of 0)
  135. //
  136. //
  137. // add the hash of the encoding params.
  138. //
  139. Array.Copy(defHash, 0, block, defHash.Length, defHash.Length);
  140. //
  141. // generate the seed.
  142. //
  143. byte[] seed = SecureRandom.GetNextBytes(random, defHash.Length);
  144. //
  145. // mask the message block.
  146. //
  147. byte[] mask = MaskGeneratorFunction(seed, 0, seed.Length, block.Length - defHash.Length);
  148. for (int i = defHash.Length; i != block.Length; i++)
  149. {
  150. block[i] ^= mask[i - defHash.Length];
  151. }
  152. //
  153. // add in the seed
  154. //
  155. Array.Copy(seed, 0, block, 0, defHash.Length);
  156. //
  157. // mask the seed.
  158. //
  159. mask = MaskGeneratorFunction(
  160. block, defHash.Length, block.Length - defHash.Length, defHash.Length);
  161. for (int i = 0; i != defHash.Length; i++)
  162. {
  163. block[i] ^= mask[i];
  164. }
  165. return engine.ProcessBlock(block, 0, block.Length);
  166. }
  167. /**
  168. * @exception InvalidCipherTextException if the decrypted block turns out to
  169. * be badly formatted.
  170. */
  171. private byte[] DecodeBlock(
  172. byte[] inBytes,
  173. int inOff,
  174. int inLen)
  175. {
  176. byte[] data = engine.ProcessBlock(inBytes, inOff, inLen);
  177. byte[] block = new byte[engine.GetOutputBlockSize()];
  178. //
  179. // as we may have zeros in our leading bytes for the block we produced
  180. // on encryption, we need to make sure our decrypted block comes back
  181. // the same size.
  182. //
  183. bool wrongData = (block.Length < (2 * defHash.Length) + 1);
  184. if (data.Length <= block.Length)
  185. {
  186. Array.Copy(data, 0, block, block.Length - data.Length, data.Length);
  187. }
  188. else
  189. {
  190. Array.Copy(data, 0, block, 0, block.Length);
  191. wrongData = true;
  192. }
  193. //
  194. // unmask the seed.
  195. //
  196. byte[] mask = MaskGeneratorFunction(
  197. block, defHash.Length, block.Length - defHash.Length, defHash.Length);
  198. for (int i = 0; i != defHash.Length; i++)
  199. {
  200. block[i] ^= mask[i];
  201. }
  202. //
  203. // unmask the message block.
  204. //
  205. mask = MaskGeneratorFunction(block, 0, defHash.Length, block.Length - defHash.Length);
  206. for (int i = defHash.Length; i != block.Length; i++)
  207. {
  208. block[i] ^= mask[i - defHash.Length];
  209. }
  210. //
  211. // check the hash of the encoding params.
  212. // long check to try to avoid this been a source of a timing attack.
  213. //
  214. bool defHashWrong = false;
  215. for (int i = 0; i != defHash.Length; i++)
  216. {
  217. if (defHash[i] != block[defHash.Length + i])
  218. {
  219. defHashWrong = true;
  220. }
  221. }
  222. //
  223. // find the data block
  224. //
  225. int start = block.Length;
  226. for (int index = 2 * defHash.Length; index != block.Length; index++)
  227. {
  228. if (block[index] != 0 & start == block.Length)
  229. {
  230. start = index;
  231. }
  232. }
  233. bool dataStartWrong = (start > (block.Length - 1) | block[start] != 1);
  234. start++;
  235. if (defHashWrong | wrongData | dataStartWrong)
  236. {
  237. Arrays.Fill(block, 0);
  238. throw new InvalidCipherTextException("data wrong");
  239. }
  240. //
  241. // extract the data block
  242. //
  243. byte[] output = new byte[block.Length - start];
  244. Array.Copy(block, start, output, 0, output.Length);
  245. Array.Clear(block, 0, block.Length);
  246. return output;
  247. }
  248. private byte[] MaskGeneratorFunction(
  249. byte[] Z,
  250. int zOff,
  251. int zLen,
  252. int length)
  253. {
  254. if (mgf1Hash is IXof)
  255. {
  256. byte[] mask = new byte[length];
  257. mgf1Hash.BlockUpdate(Z, zOff, zLen);
  258. ((IXof)mgf1Hash).DoFinal(mask, 0, mask.Length);
  259. return mask;
  260. }
  261. else
  262. {
  263. return MaskGeneratorFunction1(Z, zOff, zLen, length);
  264. }
  265. }
  266. /**
  267. * mask generator function, as described in PKCS1v2.
  268. */
  269. private byte[] MaskGeneratorFunction1(
  270. byte[] Z,
  271. int zOff,
  272. int zLen,
  273. int length)
  274. {
  275. byte[] mask = new byte[length];
  276. byte[] hashBuf = new byte[mgf1Hash.GetDigestSize()];
  277. byte[] C = new byte[4];
  278. int counter = 0;
  279. mgf1Hash.Reset();
  280. while (counter < (length / hashBuf.Length))
  281. {
  282. Pack.UInt32_To_BE((uint)counter, C);
  283. mgf1Hash.BlockUpdate(Z, zOff, zLen);
  284. mgf1Hash.BlockUpdate(C, 0, C.Length);
  285. mgf1Hash.DoFinal(hashBuf, 0);
  286. Array.Copy(hashBuf, 0, mask, counter * hashBuf.Length, hashBuf.Length);
  287. counter++;
  288. }
  289. if ((counter * hashBuf.Length) < length)
  290. {
  291. Pack.UInt32_To_BE((uint)counter, C);
  292. mgf1Hash.BlockUpdate(Z, zOff, zLen);
  293. mgf1Hash.BlockUpdate(C, 0, C.Length);
  294. mgf1Hash.DoFinal(hashBuf, 0);
  295. Array.Copy(hashBuf, 0, mask, counter * hashBuf.Length, mask.Length - (counter * hashBuf.Length));
  296. }
  297. return mask;
  298. }
  299. }
  300. }
  301. #pragma warning restore
  302. #endif