SM2Signer.cs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  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.Math;
  7. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Math.EC;
  8. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Math.EC.Multiplier;
  9. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Security;
  10. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  11. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities.Encoders;
  12. namespace Best.HTTP.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 rParam)
  66. {
  67. ecKey = (ECKeyParameters)rParam.Parameters;
  68. ecParams = ecKey.Parameters;
  69. kCalculator.Init(ecParams.N, rParam.Random);
  70. }
  71. else
  72. {
  73. ecKey = (ECKeyParameters)baseParam;
  74. ecParams = ecKey.Parameters;
  75. kCalculator.Init(ecParams.N, CryptoServicesRegistrar.GetSecureRandom());
  76. }
  77. pubPoint = CreateBasePointMultiplier().Multiply(ecParams.G, ((ECPrivateKeyParameters)ecKey).D).Normalize();
  78. }
  79. else
  80. {
  81. ecKey = (ECKeyParameters)baseParam;
  82. ecParams = ecKey.Parameters;
  83. pubPoint = ((ECPublicKeyParameters)ecKey).Q;
  84. }
  85. digest.Reset();
  86. z = GetZ(userID);
  87. digest.BlockUpdate(z, 0, z.Length);
  88. }
  89. public virtual void Update(byte b)
  90. {
  91. digest.Update(b);
  92. }
  93. public virtual void BlockUpdate(byte[] input, int inOff, int inLen)
  94. {
  95. digest.BlockUpdate(input, inOff, inLen);
  96. }
  97. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  98. public virtual void BlockUpdate(ReadOnlySpan<byte> input)
  99. {
  100. digest.BlockUpdate(input);
  101. }
  102. #endif
  103. public virtual bool VerifySignature(byte[] signature)
  104. {
  105. try
  106. {
  107. BigInteger[] rs = encoding.Decode(ecParams.N, signature);
  108. return VerifySignature(rs[0], rs[1]);
  109. }
  110. catch (Exception)
  111. {
  112. }
  113. return false;
  114. }
  115. public virtual void Reset()
  116. {
  117. if (z != null)
  118. {
  119. digest.Reset();
  120. digest.BlockUpdate(z, 0, z.Length);
  121. }
  122. }
  123. public virtual byte[] GenerateSignature()
  124. {
  125. byte[] eHash = DigestUtilities.DoFinal(digest);
  126. BigInteger n = ecParams.N;
  127. BigInteger e = CalculateE(n, eHash);
  128. BigInteger d = ((ECPrivateKeyParameters)ecKey).D;
  129. BigInteger r, s;
  130. ECMultiplier basePointMultiplier = CreateBasePointMultiplier();
  131. // 5.2.1 Draft RFC: SM2 Public Key Algorithms
  132. do // generate s
  133. {
  134. BigInteger k;
  135. do // generate r
  136. {
  137. // A3
  138. k = kCalculator.NextK();
  139. // A4
  140. ECPoint p = basePointMultiplier.Multiply(ecParams.G, k).Normalize();
  141. // A5
  142. r = e.Add(p.AffineXCoord.ToBigInteger()).Mod(n);
  143. }
  144. while (r.SignValue == 0 || r.Add(k).Equals(n));
  145. // A6
  146. BigInteger dPlus1ModN = BigIntegers.ModOddInverse(n, d.Add(BigIntegers.One));
  147. s = k.Subtract(r.Multiply(d)).Mod(n);
  148. s = dPlus1ModN.Multiply(s).Mod(n);
  149. }
  150. while (s.SignValue == 0);
  151. // A7
  152. try
  153. {
  154. return encoding.Encode(ecParams.N, r, s);
  155. }
  156. catch (Exception ex)
  157. {
  158. throw new CryptoException("unable to encode signature: " + ex.Message, ex);
  159. }
  160. }
  161. private bool VerifySignature(BigInteger r, BigInteger s)
  162. {
  163. BigInteger n = ecParams.N;
  164. // 5.3.1 Draft RFC: SM2 Public Key Algorithms
  165. // B1
  166. if (r.CompareTo(BigInteger.One) < 0 || r.CompareTo(n) >= 0)
  167. return false;
  168. // B2
  169. if (s.CompareTo(BigInteger.One) < 0 || s.CompareTo(n) >= 0)
  170. return false;
  171. // B3
  172. byte[] eHash = DigestUtilities.DoFinal(digest);
  173. // B4
  174. BigInteger e = CalculateE(n, eHash);
  175. // B5
  176. BigInteger t = r.Add(s).Mod(n);
  177. if (t.SignValue == 0)
  178. return false;
  179. // B6
  180. ECPoint q = ((ECPublicKeyParameters)ecKey).Q;
  181. ECPoint x1y1 = ECAlgorithms.SumOfTwoMultiplies(ecParams.G, s, q, t).Normalize();
  182. if (x1y1.IsInfinity)
  183. return false;
  184. // B7
  185. return r.Equals(e.Add(x1y1.AffineXCoord.ToBigInteger()).Mod(n));
  186. }
  187. private byte[] GetZ(byte[] userID)
  188. {
  189. AddUserID(digest, userID);
  190. AddFieldElement(digest, ecParams.Curve.A);
  191. AddFieldElement(digest, ecParams.Curve.B);
  192. AddFieldElement(digest, ecParams.G.AffineXCoord);
  193. AddFieldElement(digest, ecParams.G.AffineYCoord);
  194. AddFieldElement(digest, pubPoint.AffineXCoord);
  195. AddFieldElement(digest, pubPoint.AffineYCoord);
  196. return DigestUtilities.DoFinal(digest);
  197. }
  198. private void AddUserID(IDigest digest, byte[] userID)
  199. {
  200. int len = userID.Length * 8;
  201. digest.Update((byte)(len >> 8));
  202. digest.Update((byte)len);
  203. digest.BlockUpdate(userID, 0, userID.Length);
  204. }
  205. private void AddFieldElement(IDigest digest, ECFieldElement v)
  206. {
  207. byte[] p = v.GetEncoded();
  208. digest.BlockUpdate(p, 0, p.Length);
  209. }
  210. protected virtual BigInteger CalculateE(BigInteger n, byte[] message)
  211. {
  212. // TODO Should hashes larger than the order be truncated as with ECDSA?
  213. return new BigInteger(1, message);
  214. }
  215. protected virtual ECMultiplier CreateBasePointMultiplier()
  216. {
  217. return new FixedPointCombMultiplier();
  218. }
  219. }
  220. }
  221. #pragma warning restore
  222. #endif