RsaDigestSigner.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. using System;
  3. using System.Collections;
  4. using System.IO;
  5. using System.Text;
  6. using Org.BouncyCastle.Asn1;
  7. using Org.BouncyCastle.Asn1.Nist;
  8. using Org.BouncyCastle.Asn1.Pkcs;
  9. using Org.BouncyCastle.Asn1.TeleTrust;
  10. using Org.BouncyCastle.Asn1.Utilities;
  11. using Org.BouncyCastle.Asn1.X509;
  12. using Org.BouncyCastle.Crypto.Parameters;
  13. using Org.BouncyCastle.Crypto.Encodings;
  14. using Org.BouncyCastle.Crypto.Engines;
  15. using Org.BouncyCastle.Crypto.Signers;
  16. using Org.BouncyCastle.Security;
  17. using Org.BouncyCastle.Utilities;
  18. namespace Org.BouncyCastle.Crypto.Signers
  19. {
  20. public class RsaDigestSigner
  21. : ISigner
  22. {
  23. private readonly IAsymmetricBlockCipher rsaEngine = new Pkcs1Encoding(new RsaBlindedEngine());
  24. private readonly AlgorithmIdentifier algId;
  25. private readonly IDigest digest;
  26. private bool forSigning;
  27. private static readonly IDictionary oidMap = Org.BouncyCastle.Utilities.Platform.CreateHashtable();
  28. /// <summary>
  29. /// Load oid table.
  30. /// </summary>
  31. static RsaDigestSigner()
  32. {
  33. oidMap["RIPEMD128"] = TeleTrusTObjectIdentifiers.RipeMD128;
  34. oidMap["RIPEMD160"] = TeleTrusTObjectIdentifiers.RipeMD160;
  35. oidMap["RIPEMD256"] = TeleTrusTObjectIdentifiers.RipeMD256;
  36. oidMap["SHA-1"] = X509ObjectIdentifiers.IdSha1;
  37. oidMap["SHA-224"] = NistObjectIdentifiers.IdSha224;
  38. oidMap["SHA-256"] = NistObjectIdentifiers.IdSha256;
  39. oidMap["SHA-384"] = NistObjectIdentifiers.IdSha384;
  40. oidMap["SHA-512"] = NistObjectIdentifiers.IdSha512;
  41. oidMap["MD2"] = PkcsObjectIdentifiers.MD2;
  42. oidMap["MD4"] = PkcsObjectIdentifiers.MD4;
  43. oidMap["MD5"] = PkcsObjectIdentifiers.MD5;
  44. }
  45. public RsaDigestSigner(IDigest digest)
  46. : this(digest, (DerObjectIdentifier)oidMap[digest.AlgorithmName])
  47. {
  48. }
  49. public RsaDigestSigner(IDigest digest, DerObjectIdentifier digestOid)
  50. : this(digest, new AlgorithmIdentifier(digestOid, DerNull.Instance))
  51. {
  52. }
  53. public RsaDigestSigner(IDigest digest, AlgorithmIdentifier algId)
  54. {
  55. this.digest = digest;
  56. this.algId = algId;
  57. }
  58. public virtual string AlgorithmName
  59. {
  60. get { return digest.AlgorithmName + "withRSA"; }
  61. }
  62. /**
  63. * Initialise the signer for signing or verification.
  64. *
  65. * @param forSigning true if for signing, false otherwise
  66. * @param param necessary parameters.
  67. */
  68. public virtual void Init(
  69. bool forSigning,
  70. ICipherParameters parameters)
  71. {
  72. this.forSigning = forSigning;
  73. AsymmetricKeyParameter k;
  74. if (parameters is ParametersWithRandom)
  75. {
  76. k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).Parameters;
  77. }
  78. else
  79. {
  80. k = (AsymmetricKeyParameter)parameters;
  81. }
  82. if (forSigning && !k.IsPrivate)
  83. throw new InvalidKeyException("Signing requires private key.");
  84. if (!forSigning && k.IsPrivate)
  85. throw new InvalidKeyException("Verification requires public key.");
  86. Reset();
  87. rsaEngine.Init(forSigning, parameters);
  88. }
  89. /**
  90. * update the internal digest with the byte b
  91. */
  92. public virtual void Update(
  93. byte input)
  94. {
  95. digest.Update(input);
  96. }
  97. /**
  98. * update the internal digest with the byte array in
  99. */
  100. public virtual void BlockUpdate(
  101. byte[] input,
  102. int inOff,
  103. int length)
  104. {
  105. digest.BlockUpdate(input, inOff, length);
  106. }
  107. /**
  108. * Generate a signature for the message we've been loaded with using
  109. * the key we were initialised with.
  110. */
  111. public virtual byte[] GenerateSignature()
  112. {
  113. if (!forSigning)
  114. throw new InvalidOperationException("RsaDigestSigner not initialised for signature generation.");
  115. byte[] hash = new byte[digest.GetDigestSize()];
  116. digest.DoFinal(hash, 0);
  117. byte[] data = DerEncode(hash);
  118. return rsaEngine.ProcessBlock(data, 0, data.Length);
  119. }
  120. /**
  121. * return true if the internal state represents the signature described
  122. * in the passed in array.
  123. */
  124. public virtual bool VerifySignature(
  125. byte[] signature)
  126. {
  127. if (forSigning)
  128. throw new InvalidOperationException("RsaDigestSigner not initialised for verification");
  129. byte[] hash = new byte[digest.GetDigestSize()];
  130. digest.DoFinal(hash, 0);
  131. byte[] sig;
  132. byte[] expected;
  133. try
  134. {
  135. sig = rsaEngine.ProcessBlock(signature, 0, signature.Length);
  136. expected = DerEncode(hash);
  137. }
  138. catch (Exception)
  139. {
  140. return false;
  141. }
  142. if (sig.Length == expected.Length)
  143. {
  144. return Arrays.ConstantTimeAreEqual(sig, expected);
  145. }
  146. else if (sig.Length == expected.Length - 2) // NULL left out
  147. {
  148. int sigOffset = sig.Length - hash.Length - 2;
  149. int expectedOffset = expected.Length - hash.Length - 2;
  150. expected[1] -= 2; // adjust lengths
  151. expected[3] -= 2;
  152. int nonEqual = 0;
  153. for (int i = 0; i < hash.Length; i++)
  154. {
  155. nonEqual |= (sig[sigOffset + i] ^ expected[expectedOffset + i]);
  156. }
  157. for (int i = 0; i < sigOffset; i++)
  158. {
  159. nonEqual |= (sig[i] ^ expected[i]); // check header less NULL
  160. }
  161. return nonEqual == 0;
  162. }
  163. else
  164. {
  165. return false;
  166. }
  167. }
  168. public virtual void Reset()
  169. {
  170. digest.Reset();
  171. }
  172. private byte[] DerEncode(byte[] hash)
  173. {
  174. if (algId == null)
  175. {
  176. // For raw RSA, the DigestInfo must be prepared externally
  177. return hash;
  178. }
  179. DigestInfo dInfo = new DigestInfo(algId, hash);
  180. return dInfo.GetDerEncoded();
  181. }
  182. }
  183. }
  184. #endif