PssSigner.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  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.Security;
  7. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  8. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Signers
  9. {
  10. /// <summary> RSA-PSS as described in Pkcs# 1 v 2.1.
  11. /// <p>
  12. /// Note: the usual value for the salt length is the number of
  13. /// bytes in the hash function.</p>
  14. /// </summary>
  15. public class PssSigner
  16. : ISigner
  17. {
  18. public const byte TrailerImplicit = (byte)0xBC;
  19. private readonly IDigest contentDigest1, contentDigest2;
  20. private readonly IDigest mgfDigest;
  21. private readonly IAsymmetricBlockCipher cipher;
  22. private SecureRandom random;
  23. private int hLen;
  24. private int mgfhLen;
  25. private int sLen;
  26. private bool sSet;
  27. private int emBits;
  28. private byte[] salt;
  29. private byte[] mDash;
  30. private byte[] block;
  31. private byte trailer;
  32. public static PssSigner CreateRawSigner(
  33. IAsymmetricBlockCipher cipher,
  34. IDigest digest)
  35. {
  36. return new PssSigner(cipher, new NullDigest(), digest, digest, digest.GetDigestSize(), null, TrailerImplicit);
  37. }
  38. public static PssSigner CreateRawSigner(
  39. IAsymmetricBlockCipher cipher,
  40. IDigest contentDigest,
  41. IDigest mgfDigest,
  42. int saltLen,
  43. byte trailer)
  44. {
  45. return new PssSigner(cipher, new NullDigest(), contentDigest, mgfDigest, saltLen, null, trailer);
  46. }
  47. public PssSigner(
  48. IAsymmetricBlockCipher cipher,
  49. IDigest digest)
  50. : this(cipher, digest, digest.GetDigestSize())
  51. {
  52. }
  53. /// <summary>Basic constructor</summary>
  54. /// <param name="cipher">the asymmetric cipher to use.</param>
  55. /// <param name="digest">the digest to use.</param>
  56. /// <param name="saltLen">the length of the salt to use (in bytes).</param>
  57. public PssSigner(
  58. IAsymmetricBlockCipher cipher,
  59. IDigest digest,
  60. int saltLen)
  61. : this(cipher, digest, saltLen, TrailerImplicit)
  62. {
  63. }
  64. /// <summary>Basic constructor</summary>
  65. /// <param name="cipher">the asymmetric cipher to use.</param>
  66. /// <param name="digest">the digest to use.</param>
  67. /// <param name="salt">the fixed salt to be used.</param>
  68. public PssSigner(
  69. IAsymmetricBlockCipher cipher,
  70. IDigest digest,
  71. byte[] salt)
  72. : this(cipher, digest, digest, digest, salt.Length, salt, TrailerImplicit)
  73. {
  74. }
  75. public PssSigner(
  76. IAsymmetricBlockCipher cipher,
  77. IDigest contentDigest,
  78. IDigest mgfDigest,
  79. int saltLen)
  80. : this(cipher, contentDigest, mgfDigest, saltLen, TrailerImplicit)
  81. {
  82. }
  83. public PssSigner(
  84. IAsymmetricBlockCipher cipher,
  85. IDigest contentDigest,
  86. IDigest mgfDigest,
  87. byte[] salt)
  88. : this(cipher, contentDigest, contentDigest, mgfDigest, salt.Length, salt, TrailerImplicit)
  89. {
  90. }
  91. public PssSigner(
  92. IAsymmetricBlockCipher cipher,
  93. IDigest digest,
  94. int saltLen,
  95. byte trailer)
  96. : this(cipher, digest, digest, saltLen, trailer)
  97. {
  98. }
  99. public PssSigner(
  100. IAsymmetricBlockCipher cipher,
  101. IDigest contentDigest,
  102. IDigest mgfDigest,
  103. int saltLen,
  104. byte trailer)
  105. : this(cipher, contentDigest, contentDigest, mgfDigest, saltLen, null, trailer)
  106. {
  107. }
  108. private PssSigner(
  109. IAsymmetricBlockCipher cipher,
  110. IDigest contentDigest1,
  111. IDigest contentDigest2,
  112. IDigest mgfDigest,
  113. int saltLen,
  114. byte[] salt,
  115. byte trailer)
  116. {
  117. this.cipher = cipher;
  118. this.contentDigest1 = contentDigest1;
  119. this.contentDigest2 = contentDigest2;
  120. this.mgfDigest = mgfDigest;
  121. this.hLen = contentDigest2.GetDigestSize();
  122. this.mgfhLen = mgfDigest.GetDigestSize();
  123. this.sLen = saltLen;
  124. this.sSet = salt != null;
  125. if (sSet)
  126. {
  127. this.salt = salt;
  128. }
  129. else
  130. {
  131. this.salt = new byte[saltLen];
  132. }
  133. this.mDash = new byte[8 + saltLen + hLen];
  134. this.trailer = trailer;
  135. }
  136. public virtual string AlgorithmName
  137. {
  138. get { return mgfDigest.AlgorithmName + "withRSAandMGF1"; }
  139. }
  140. public virtual void Init(
  141. bool forSigning,
  142. ICipherParameters parameters)
  143. {
  144. if (parameters is ParametersWithRandom)
  145. {
  146. ParametersWithRandom p = (ParametersWithRandom) parameters;
  147. parameters = p.Parameters;
  148. random = p.Random;
  149. }
  150. else
  151. {
  152. if (forSigning)
  153. {
  154. random = new SecureRandom();
  155. }
  156. }
  157. cipher.Init(forSigning, parameters);
  158. RsaKeyParameters kParam;
  159. if (parameters is RsaBlindingParameters)
  160. {
  161. kParam = ((RsaBlindingParameters) parameters).PublicKey;
  162. }
  163. else
  164. {
  165. kParam = (RsaKeyParameters) parameters;
  166. }
  167. emBits = kParam.Modulus.BitLength - 1;
  168. if (emBits < (8 * hLen + 8 * sLen + 9))
  169. throw new ArgumentException("key too small for specified hash and salt lengths");
  170. block = new byte[(emBits + 7) / 8];
  171. }
  172. /// <summary> clear possible sensitive data</summary>
  173. private void ClearBlock(
  174. byte[] block)
  175. {
  176. Array.Clear(block, 0, block.Length);
  177. }
  178. /// <summary> update the internal digest with the byte b</summary>
  179. public virtual void Update(
  180. byte input)
  181. {
  182. contentDigest1.Update(input);
  183. }
  184. /// <summary> update the internal digest with the byte array in</summary>
  185. public virtual void BlockUpdate(
  186. byte[] input,
  187. int inOff,
  188. int length)
  189. {
  190. contentDigest1.BlockUpdate(input, inOff, length);
  191. }
  192. /// <summary> reset the internal state</summary>
  193. public virtual void Reset()
  194. {
  195. contentDigest1.Reset();
  196. }
  197. /// <summary> Generate a signature for the message we've been loaded with using
  198. /// the key we were initialised with.
  199. /// </summary>
  200. public virtual byte[] GenerateSignature()
  201. {
  202. contentDigest1.DoFinal(mDash, mDash.Length - hLen - sLen);
  203. if (sLen != 0)
  204. {
  205. if (!sSet)
  206. {
  207. random.NextBytes(salt);
  208. }
  209. salt.CopyTo(mDash, mDash.Length - sLen);
  210. }
  211. byte[] h = new byte[hLen];
  212. contentDigest2.BlockUpdate(mDash, 0, mDash.Length);
  213. contentDigest2.DoFinal(h, 0);
  214. block[block.Length - sLen - 1 - hLen - 1] = (byte) (0x01);
  215. salt.CopyTo(block, block.Length - sLen - hLen - 1);
  216. byte[] dbMask = MaskGeneratorFunction(h, 0, h.Length, block.Length - hLen - 1);
  217. for (int i = 0; i != dbMask.Length; i++)
  218. {
  219. block[i] ^= dbMask[i];
  220. }
  221. h.CopyTo(block, block.Length - hLen - 1);
  222. uint firstByteMask = 0xFFU >> ((block.Length * 8) - emBits);
  223. block[0] &= (byte)firstByteMask;
  224. block[block.Length - 1] = trailer;
  225. byte[] b = cipher.ProcessBlock(block, 0, block.Length);
  226. ClearBlock(block);
  227. return b;
  228. }
  229. /// <summary> return true if the internal state represents the signature described
  230. /// in the passed in array.
  231. /// </summary>
  232. public virtual bool VerifySignature(
  233. byte[] signature)
  234. {
  235. contentDigest1.DoFinal(mDash, mDash.Length - hLen - sLen);
  236. byte[] b = cipher.ProcessBlock(signature, 0, signature.Length);
  237. Arrays.Fill(block, 0, block.Length - b.Length, 0);
  238. b.CopyTo(block, block.Length - b.Length);
  239. uint firstByteMask = 0xFFU >> ((block.Length * 8) - emBits);
  240. if (block[0] != (byte)(block[0] & firstByteMask)
  241. || block[block.Length - 1] != trailer)
  242. {
  243. ClearBlock(block);
  244. return false;
  245. }
  246. byte[] dbMask = MaskGeneratorFunction(block, block.Length - hLen - 1, hLen, block.Length - hLen - 1);
  247. for (int i = 0; i != dbMask.Length; i++)
  248. {
  249. block[i] ^= dbMask[i];
  250. }
  251. block[0] &= (byte)firstByteMask;
  252. for (int i = 0; i != block.Length - hLen - sLen - 2; i++)
  253. {
  254. if (block[i] != 0)
  255. {
  256. ClearBlock(block);
  257. return false;
  258. }
  259. }
  260. if (block[block.Length - hLen - sLen - 2] != 0x01)
  261. {
  262. ClearBlock(block);
  263. return false;
  264. }
  265. if (sSet)
  266. {
  267. Array.Copy(salt, 0, mDash, mDash.Length - sLen, sLen);
  268. }
  269. else
  270. {
  271. Array.Copy(block, block.Length - sLen - hLen - 1, mDash, mDash.Length - sLen, sLen);
  272. }
  273. contentDigest2.BlockUpdate(mDash, 0, mDash.Length);
  274. contentDigest2.DoFinal(mDash, mDash.Length - hLen);
  275. for (int i = block.Length - hLen - 1, j = mDash.Length - hLen; j != mDash.Length; i++, j++)
  276. {
  277. if ((block[i] ^ mDash[j]) != 0)
  278. {
  279. ClearBlock(mDash);
  280. ClearBlock(block);
  281. return false;
  282. }
  283. }
  284. ClearBlock(mDash);
  285. ClearBlock(block);
  286. return true;
  287. }
  288. /// <summary> int to octet string.</summary>
  289. private void ItoOSP(
  290. int i,
  291. byte[] sp)
  292. {
  293. sp[0] = (byte)((uint) i >> 24);
  294. sp[1] = (byte)((uint) i >> 16);
  295. sp[2] = (byte)((uint) i >> 8);
  296. sp[3] = (byte)((uint) i >> 0);
  297. }
  298. private byte[] MaskGeneratorFunction(
  299. byte[] Z,
  300. int zOff,
  301. int zLen,
  302. int length)
  303. {
  304. if (mgfDigest is IXof)
  305. {
  306. byte[] mask = new byte[length];
  307. mgfDigest.BlockUpdate(Z, zOff, zLen);
  308. ((IXof)mgfDigest).DoFinal(mask, 0, mask.Length);
  309. return mask;
  310. }
  311. else
  312. {
  313. return MaskGeneratorFunction1(Z, zOff, zLen, length);
  314. }
  315. }
  316. /// <summary> mask generator function, as described in Pkcs1v2.</summary>
  317. private byte[] MaskGeneratorFunction1(
  318. byte[] Z,
  319. int zOff,
  320. int zLen,
  321. int length)
  322. {
  323. byte[] mask = new byte[length];
  324. byte[] hashBuf = new byte[mgfhLen];
  325. byte[] C = new byte[4];
  326. int counter = 0;
  327. mgfDigest.Reset();
  328. while (counter < (length / mgfhLen))
  329. {
  330. ItoOSP(counter, C);
  331. mgfDigest.BlockUpdate(Z, zOff, zLen);
  332. mgfDigest.BlockUpdate(C, 0, C.Length);
  333. mgfDigest.DoFinal(hashBuf, 0);
  334. hashBuf.CopyTo(mask, counter * mgfhLen);
  335. ++counter;
  336. }
  337. if ((counter * mgfhLen) < length)
  338. {
  339. ItoOSP(counter, C);
  340. mgfDigest.BlockUpdate(Z, zOff, zLen);
  341. mgfDigest.BlockUpdate(C, 0, C.Length);
  342. mgfDigest.DoFinal(hashBuf, 0);
  343. Array.Copy(hashBuf, 0, mask, counter * mgfhLen, mask.Length - (counter * mgfhLen));
  344. }
  345. return mask;
  346. }
  347. }
  348. }
  349. #pragma warning restore
  350. #endif