SM2Signer.cs 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  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.Math;
  7. using BestHTTP.SecureProtocol.Org.BouncyCastle.Math.EC;
  8. using BestHTTP.SecureProtocol.Org.BouncyCastle.Math.EC.Multiplier;
  9. using BestHTTP.SecureProtocol.Org.BouncyCastle.Security;
  10. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  11. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities.Encoders;
  12. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Signers
  13. {
  14. /// <summary>The SM2 Digital Signature algorithm.</summary>
  15. public class SM2Signer
  16. : ISigner
  17. {
  18. private readonly IDsaKCalculator kCalculator = new RandomDsaKCalculator();
  19. private readonly IDigest digest;
  20. private readonly IDsaEncoding encoding;
  21. private ECDomainParameters ecParams;
  22. private ECPoint pubPoint;
  23. private ECKeyParameters ecKey;
  24. private byte[] z;
  25. public SM2Signer()
  26. : this(StandardDsaEncoding.Instance, new SM3Digest())
  27. {
  28. }
  29. public SM2Signer(IDigest digest)
  30. : this(StandardDsaEncoding.Instance, digest)
  31. {
  32. }
  33. public SM2Signer(IDsaEncoding encoding)
  34. : this(encoding, new SM3Digest())
  35. {
  36. }
  37. public SM2Signer(IDsaEncoding encoding, IDigest digest)
  38. {
  39. this.encoding = encoding;
  40. this.digest = digest;
  41. }
  42. public virtual string AlgorithmName
  43. {
  44. get { return "SM2Sign"; }
  45. }
  46. public virtual void Init(bool forSigning, ICipherParameters parameters)
  47. {
  48. ICipherParameters baseParam;
  49. byte[] userID;
  50. if (parameters is ParametersWithID)
  51. {
  52. baseParam = ((ParametersWithID)parameters).Parameters;
  53. userID = ((ParametersWithID)parameters).GetID();
  54. if (userID.Length >= 8192)
  55. throw new ArgumentException("SM2 user ID must be less than 2^16 bits long");
  56. }
  57. else
  58. {
  59. baseParam = parameters;
  60. // the default value, string value is "1234567812345678"
  61. userID = Hex.DecodeStrict("31323334353637383132333435363738");
  62. }
  63. if (forSigning)
  64. {
  65. if (baseParam is ParametersWithRandom)
  66. {
  67. ParametersWithRandom rParam = (ParametersWithRandom)baseParam;
  68. ecKey = (ECKeyParameters)rParam.Parameters;
  69. ecParams = ecKey.Parameters;
  70. kCalculator.Init(ecParams.N, rParam.Random);
  71. }
  72. else
  73. {
  74. ecKey = (ECKeyParameters)baseParam;
  75. ecParams = ecKey.Parameters;
  76. kCalculator.Init(ecParams.N, new SecureRandom());
  77. }
  78. pubPoint = CreateBasePointMultiplier().Multiply(ecParams.G, ((ECPrivateKeyParameters)ecKey).D).Normalize();
  79. }
  80. else
  81. {
  82. ecKey = (ECKeyParameters)baseParam;
  83. ecParams = ecKey.Parameters;
  84. pubPoint = ((ECPublicKeyParameters)ecKey).Q;
  85. }
  86. digest.Reset();
  87. z = GetZ(userID);
  88. digest.BlockUpdate(z, 0, z.Length);
  89. }
  90. public virtual void Update(byte b)
  91. {
  92. digest.Update(b);
  93. }
  94. public virtual void BlockUpdate(byte[] buf, int off, int len)
  95. {
  96. digest.BlockUpdate(buf, off, len);
  97. }
  98. public virtual bool VerifySignature(byte[] signature)
  99. {
  100. try
  101. {
  102. BigInteger[] rs = encoding.Decode(ecParams.N, signature);
  103. return VerifySignature(rs[0], rs[1]);
  104. }
  105. catch (Exception)
  106. {
  107. }
  108. return false;
  109. }
  110. public virtual void Reset()
  111. {
  112. if (z != null)
  113. {
  114. digest.Reset();
  115. digest.BlockUpdate(z, 0, z.Length);
  116. }
  117. }
  118. public virtual byte[] GenerateSignature()
  119. {
  120. byte[] eHash = DigestUtilities.DoFinal(digest);
  121. BigInteger n = ecParams.N;
  122. BigInteger e = CalculateE(n, eHash);
  123. BigInteger d = ((ECPrivateKeyParameters)ecKey).D;
  124. BigInteger r, s;
  125. ECMultiplier basePointMultiplier = CreateBasePointMultiplier();
  126. // 5.2.1 Draft RFC: SM2 Public Key Algorithms
  127. do // generate s
  128. {
  129. BigInteger k;
  130. do // generate r
  131. {
  132. // A3
  133. k = kCalculator.NextK();
  134. // A4
  135. ECPoint p = basePointMultiplier.Multiply(ecParams.G, k).Normalize();
  136. // A5
  137. r = e.Add(p.AffineXCoord.ToBigInteger()).Mod(n);
  138. }
  139. while (r.SignValue == 0 || r.Add(k).Equals(n));
  140. // A6
  141. BigInteger dPlus1ModN = BigIntegers.ModOddInverse(n, d.Add(BigIntegers.One));
  142. s = k.Subtract(r.Multiply(d)).Mod(n);
  143. s = dPlus1ModN.Multiply(s).Mod(n);
  144. }
  145. while (s.SignValue == 0);
  146. // A7
  147. try
  148. {
  149. return encoding.Encode(ecParams.N, r, s);
  150. }
  151. catch (Exception ex)
  152. {
  153. throw new CryptoException("unable to encode signature: " + ex.Message, ex);
  154. }
  155. }
  156. private bool VerifySignature(BigInteger r, BigInteger s)
  157. {
  158. BigInteger n = ecParams.N;
  159. // 5.3.1 Draft RFC: SM2 Public Key Algorithms
  160. // B1
  161. if (r.CompareTo(BigInteger.One) < 0 || r.CompareTo(n) >= 0)
  162. return false;
  163. // B2
  164. if (s.CompareTo(BigInteger.One) < 0 || s.CompareTo(n) >= 0)
  165. return false;
  166. // B3
  167. byte[] eHash = DigestUtilities.DoFinal(digest);
  168. // B4
  169. BigInteger e = CalculateE(n, eHash);
  170. // B5
  171. BigInteger t = r.Add(s).Mod(n);
  172. if (t.SignValue == 0)
  173. return false;
  174. // B6
  175. ECPoint q = ((ECPublicKeyParameters)ecKey).Q;
  176. ECPoint x1y1 = ECAlgorithms.SumOfTwoMultiplies(ecParams.G, s, q, t).Normalize();
  177. if (x1y1.IsInfinity)
  178. return false;
  179. // B7
  180. return r.Equals(e.Add(x1y1.AffineXCoord.ToBigInteger()).Mod(n));
  181. }
  182. private byte[] GetZ(byte[] userID)
  183. {
  184. AddUserID(digest, userID);
  185. AddFieldElement(digest, ecParams.Curve.A);
  186. AddFieldElement(digest, ecParams.Curve.B);
  187. AddFieldElement(digest, ecParams.G.AffineXCoord);
  188. AddFieldElement(digest, ecParams.G.AffineYCoord);
  189. AddFieldElement(digest, pubPoint.AffineXCoord);
  190. AddFieldElement(digest, pubPoint.AffineYCoord);
  191. return DigestUtilities.DoFinal(digest);
  192. }
  193. private void AddUserID(IDigest digest, byte[] userID)
  194. {
  195. int len = userID.Length * 8;
  196. digest.Update((byte)(len >> 8));
  197. digest.Update((byte)len);
  198. digest.BlockUpdate(userID, 0, userID.Length);
  199. }
  200. private void AddFieldElement(IDigest digest, ECFieldElement v)
  201. {
  202. byte[] p = v.GetEncoded();
  203. digest.BlockUpdate(p, 0, p.Length);
  204. }
  205. protected virtual BigInteger CalculateE(BigInteger n, byte[] message)
  206. {
  207. // TODO Should hashes larger than the order be truncated as with ECDSA?
  208. return new BigInteger(1, message);
  209. }
  210. protected virtual ECMultiplier CreateBasePointMultiplier()
  211. {
  212. return new FixedPointCombMultiplier();
  213. }
  214. }
  215. }
  216. #pragma warning restore
  217. #endif