OaepEncoding.cs 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Digests;
  5. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  6. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
  7. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Security;
  8. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  9. namespace Best.HTTP.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 string AlgorithmName => engine.AlgorithmName + "/OAEPPadding";
  57. public IAsymmetricBlockCipher UnderlyingCipher => engine;
  58. public void Init(bool forEncryption, ICipherParameters parameters)
  59. {
  60. if (parameters is ParametersWithRandom withRandom)
  61. {
  62. this.random = withRandom.Random;
  63. }
  64. else
  65. {
  66. this.random = CryptoServicesRegistrar.GetSecureRandom();
  67. }
  68. engine.Init(forEncryption, parameters);
  69. this.forEncryption = forEncryption;
  70. }
  71. public int GetInputBlockSize()
  72. {
  73. int baseBlockSize = engine.GetInputBlockSize();
  74. if (forEncryption)
  75. {
  76. return baseBlockSize - 1 - 2 * defHash.Length;
  77. }
  78. else
  79. {
  80. return baseBlockSize;
  81. }
  82. }
  83. public int GetOutputBlockSize()
  84. {
  85. int baseBlockSize = engine.GetOutputBlockSize();
  86. if (forEncryption)
  87. {
  88. return baseBlockSize;
  89. }
  90. else
  91. {
  92. return baseBlockSize - 1 - 2 * defHash.Length;
  93. }
  94. }
  95. public byte[] ProcessBlock(
  96. byte[] inBytes,
  97. int inOff,
  98. int inLen)
  99. {
  100. if (forEncryption)
  101. {
  102. return EncodeBlock(inBytes, inOff, inLen);
  103. }
  104. else
  105. {
  106. return DecodeBlock(inBytes, inOff, inLen);
  107. }
  108. }
  109. private byte[] EncodeBlock(
  110. byte[] inBytes,
  111. int inOff,
  112. int inLen)
  113. {
  114. Check.DataLength(inLen > GetInputBlockSize(), "input data too long");
  115. byte[] block = new byte[GetInputBlockSize() + 1 + 2 * defHash.Length];
  116. //
  117. // copy in the message
  118. //
  119. Array.Copy(inBytes, inOff, block, block.Length - inLen, inLen);
  120. //
  121. // add sentinel
  122. //
  123. block[block.Length - inLen - 1] = 0x01;
  124. //
  125. // as the block is already zeroed - there's no need to add PS (the >= 0 pad of 0)
  126. //
  127. //
  128. // add the hash of the encoding params.
  129. //
  130. Array.Copy(defHash, 0, block, defHash.Length, defHash.Length);
  131. //
  132. // generate the seed.
  133. //
  134. byte[] seed = SecureRandom.GetNextBytes(random, defHash.Length);
  135. //
  136. // mask the message block.
  137. //
  138. byte[] mask = MaskGeneratorFunction(seed, 0, seed.Length, block.Length - defHash.Length);
  139. for (int i = defHash.Length; i != block.Length; i++)
  140. {
  141. block[i] ^= mask[i - defHash.Length];
  142. }
  143. //
  144. // add in the seed
  145. //
  146. Array.Copy(seed, 0, block, 0, defHash.Length);
  147. //
  148. // mask the seed.
  149. //
  150. mask = MaskGeneratorFunction(
  151. block, defHash.Length, block.Length - defHash.Length, defHash.Length);
  152. for (int i = 0; i != defHash.Length; i++)
  153. {
  154. block[i] ^= mask[i];
  155. }
  156. return engine.ProcessBlock(block, 0, block.Length);
  157. }
  158. /**
  159. * @exception InvalidCipherTextException if the decrypted block turns out to
  160. * be badly formatted.
  161. */
  162. private byte[] DecodeBlock(
  163. byte[] inBytes,
  164. int inOff,
  165. int inLen)
  166. {
  167. byte[] data = engine.ProcessBlock(inBytes, inOff, inLen);
  168. byte[] block = new byte[engine.GetOutputBlockSize()];
  169. //
  170. // as we may have zeros in our leading bytes for the block we produced
  171. // on encryption, we need to make sure our decrypted block comes back
  172. // the same size.
  173. //
  174. // i.e. wrong when block.length < (2 * defHash.length) + 1
  175. int wrongMask = (block.Length - ((2 * defHash.Length) + 1)) >> 31;
  176. if (data.Length <= block.Length)
  177. {
  178. Array.Copy(data, 0, block, block.Length - data.Length, data.Length);
  179. }
  180. else
  181. {
  182. Array.Copy(data, 0, block, 0, block.Length);
  183. wrongMask |= 1;
  184. }
  185. //
  186. // unmask the seed.
  187. //
  188. byte[] mask = MaskGeneratorFunction(
  189. block, defHash.Length, block.Length - defHash.Length, defHash.Length);
  190. for (int i = 0; i != defHash.Length; i++)
  191. {
  192. block[i] ^= mask[i];
  193. }
  194. //
  195. // unmask the message block.
  196. //
  197. mask = MaskGeneratorFunction(block, 0, defHash.Length, block.Length - defHash.Length);
  198. for (int i = defHash.Length; i != block.Length; i++)
  199. {
  200. block[i] ^= mask[i - defHash.Length];
  201. }
  202. //
  203. // check the hash of the encoding params.
  204. // long check to try to avoid this been a source of a timing attack.
  205. //
  206. for (int i = 0; i != defHash.Length; i++)
  207. {
  208. wrongMask |= defHash[i] ^ block[defHash.Length + i];
  209. }
  210. //
  211. // find the data block
  212. //
  213. int start = -1;
  214. for (int index = 2 * defHash.Length; index != block.Length; index++)
  215. {
  216. int octet = block[index];
  217. // i.e. mask will be 0xFFFFFFFF if octet is non-zero and start is (still) negative, else 0.
  218. int shouldSetMask = (-octet & start) >> 31;
  219. start += index & shouldSetMask;
  220. }
  221. wrongMask |= start >> 31;
  222. ++start;
  223. wrongMask |= block[start] ^ 1;
  224. if (wrongMask != 0)
  225. {
  226. Arrays.Fill(block, 0);
  227. throw new InvalidCipherTextException("data wrong");
  228. }
  229. ++start;
  230. //
  231. // extract the data block
  232. //
  233. byte[] output = new byte[block.Length - start];
  234. Array.Copy(block, start, output, 0, output.Length);
  235. Array.Clear(block, 0, block.Length);
  236. return output;
  237. }
  238. private byte[] MaskGeneratorFunction(
  239. byte[] Z,
  240. int zOff,
  241. int zLen,
  242. int length)
  243. {
  244. if (mgf1Hash is IXof)
  245. {
  246. byte[] mask = new byte[length];
  247. mgf1Hash.BlockUpdate(Z, zOff, zLen);
  248. ((IXof)mgf1Hash).OutputFinal(mask, 0, mask.Length);
  249. return mask;
  250. }
  251. else
  252. {
  253. return MaskGeneratorFunction1(Z, zOff, zLen, length);
  254. }
  255. }
  256. /**
  257. * mask generator function, as described in PKCS1v2.
  258. */
  259. private byte[] MaskGeneratorFunction1(
  260. byte[] Z,
  261. int zOff,
  262. int zLen,
  263. int length)
  264. {
  265. byte[] mask = new byte[length];
  266. byte[] hashBuf = new byte[mgf1Hash.GetDigestSize()];
  267. byte[] C = new byte[4];
  268. int counter = 0;
  269. mgf1Hash.Reset();
  270. while (counter < (length / hashBuf.Length))
  271. {
  272. Pack.UInt32_To_BE((uint)counter, C);
  273. mgf1Hash.BlockUpdate(Z, zOff, zLen);
  274. mgf1Hash.BlockUpdate(C, 0, C.Length);
  275. mgf1Hash.DoFinal(hashBuf, 0);
  276. Array.Copy(hashBuf, 0, mask, counter * hashBuf.Length, hashBuf.Length);
  277. counter++;
  278. }
  279. if ((counter * hashBuf.Length) < length)
  280. {
  281. Pack.UInt32_To_BE((uint)counter, C);
  282. mgf1Hash.BlockUpdate(Z, zOff, zLen);
  283. mgf1Hash.BlockUpdate(C, 0, C.Length);
  284. mgf1Hash.DoFinal(hashBuf, 0);
  285. Array.Copy(hashBuf, 0, mask, counter * hashBuf.Length, mask.Length - (counter * hashBuf.Length));
  286. }
  287. return mask;
  288. }
  289. }
  290. }
  291. #pragma warning restore
  292. #endif