SM2KeyExchange.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  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.Math;
  8. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Math.EC;
  9. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Security;
  10. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  11. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Agreement
  12. {
  13. /// <summary>
  14. /// SM2 Key Exchange protocol - based on https://tools.ietf.org/html/draft-shen-sm2-ecdsa-02
  15. /// </summary>
  16. public class SM2KeyExchange
  17. {
  18. private readonly IDigest mDigest;
  19. private byte[] mUserID;
  20. private ECPrivateKeyParameters mStaticKey;
  21. private ECPoint mStaticPubPoint;
  22. private ECPoint mEphemeralPubPoint;
  23. private ECDomainParameters mECParams;
  24. private int mW;
  25. private ECPrivateKeyParameters mEphemeralKey;
  26. private bool mInitiator;
  27. public SM2KeyExchange()
  28. : this(new SM3Digest())
  29. {
  30. }
  31. public SM2KeyExchange(IDigest digest)
  32. {
  33. this.mDigest = digest;
  34. }
  35. public virtual void Init(ICipherParameters privParam)
  36. {
  37. SM2KeyExchangePrivateParameters baseParam;
  38. if (privParam is ParametersWithID)
  39. {
  40. baseParam = (SM2KeyExchangePrivateParameters)((ParametersWithID)privParam).Parameters;
  41. mUserID = ((ParametersWithID)privParam).GetID();
  42. }
  43. else
  44. {
  45. baseParam = (SM2KeyExchangePrivateParameters)privParam;
  46. mUserID = new byte[0];
  47. }
  48. mInitiator = baseParam.IsInitiator;
  49. mStaticKey = baseParam.StaticPrivateKey;
  50. mEphemeralKey = baseParam.EphemeralPrivateKey;
  51. mECParams = mStaticKey.Parameters;
  52. mStaticPubPoint = baseParam.StaticPublicPoint;
  53. mEphemeralPubPoint = baseParam.EphemeralPublicPoint;
  54. mW = mECParams.Curve.FieldSize / 2 - 1;
  55. }
  56. public virtual byte[] CalculateKey(int kLen, ICipherParameters pubParam)
  57. {
  58. SM2KeyExchangePublicParameters otherPub;
  59. byte[] otherUserID;
  60. if (pubParam is ParametersWithID)
  61. {
  62. otherPub = (SM2KeyExchangePublicParameters)((ParametersWithID)pubParam).Parameters;
  63. otherUserID = ((ParametersWithID)pubParam).GetID();
  64. }
  65. else
  66. {
  67. otherPub = (SM2KeyExchangePublicParameters)pubParam;
  68. otherUserID = new byte[0];
  69. }
  70. byte[] za = GetZ(mDigest, mUserID, mStaticPubPoint);
  71. byte[] zb = GetZ(mDigest, otherUserID, otherPub.StaticPublicKey.Q);
  72. ECPoint U = CalculateU(otherPub);
  73. byte[] rv;
  74. if (mInitiator)
  75. {
  76. rv = Kdf(U, za, zb, kLen);
  77. }
  78. else
  79. {
  80. rv = Kdf(U, zb, za, kLen);
  81. }
  82. return rv;
  83. }
  84. public virtual byte[][] CalculateKeyWithConfirmation(int kLen, byte[] confirmationTag, ICipherParameters pubParam)
  85. {
  86. SM2KeyExchangePublicParameters otherPub;
  87. byte[] otherUserID;
  88. if (pubParam is ParametersWithID)
  89. {
  90. otherPub = (SM2KeyExchangePublicParameters)((ParametersWithID)pubParam).Parameters;
  91. otherUserID = ((ParametersWithID)pubParam).GetID();
  92. }
  93. else
  94. {
  95. otherPub = (SM2KeyExchangePublicParameters)pubParam;
  96. otherUserID = new byte[0];
  97. }
  98. if (mInitiator && confirmationTag == null)
  99. throw new ArgumentException("if initiating, confirmationTag must be set");
  100. byte[] za = GetZ(mDigest, mUserID, mStaticPubPoint);
  101. byte[] zb = GetZ(mDigest, otherUserID, otherPub.StaticPublicKey.Q);
  102. ECPoint U = CalculateU(otherPub);
  103. byte[] rv;
  104. if (mInitiator)
  105. {
  106. rv = Kdf(U, za, zb, kLen);
  107. byte[] inner = CalculateInnerHash(mDigest, U, za, zb, mEphemeralPubPoint, otherPub.EphemeralPublicKey.Q);
  108. byte[] s1 = S1(mDigest, U, inner);
  109. if (!Arrays.ConstantTimeAreEqual(s1, confirmationTag))
  110. throw new InvalidOperationException("confirmation tag mismatch");
  111. return new byte[][] { rv, S2(mDigest, U, inner)};
  112. }
  113. else
  114. {
  115. rv = Kdf(U, zb, za, kLen);
  116. byte[] inner = CalculateInnerHash(mDigest, U, zb, za, otherPub.EphemeralPublicKey.Q, mEphemeralPubPoint);
  117. return new byte[][] { rv, S1(mDigest, U, inner), S2(mDigest, U, inner) };
  118. }
  119. }
  120. protected virtual ECPoint CalculateU(SM2KeyExchangePublicParameters otherPub)
  121. {
  122. ECDomainParameters dp = mStaticKey.Parameters;
  123. ECPoint p1 = ECAlgorithms.CleanPoint(dp.Curve, otherPub.StaticPublicKey.Q);
  124. ECPoint p2 = ECAlgorithms.CleanPoint(dp.Curve, otherPub.EphemeralPublicKey.Q);
  125. BigInteger x1 = Reduce(mEphemeralPubPoint.AffineXCoord.ToBigInteger());
  126. BigInteger x2 = Reduce(p2.AffineXCoord.ToBigInteger());
  127. BigInteger tA = mStaticKey.D.Add(x1.Multiply(mEphemeralKey.D));
  128. BigInteger k1 = mECParams.H.Multiply(tA).Mod(mECParams.N);
  129. BigInteger k2 = k1.Multiply(x2).Mod(mECParams.N);
  130. return ECAlgorithms.SumOfTwoMultiplies(p1, k1, p2, k2).Normalize();
  131. }
  132. protected virtual byte[] Kdf(ECPoint u, byte[] za, byte[] zb, int klen)
  133. {
  134. int digestSize = mDigest.GetDigestSize();
  135. byte[] buf = new byte[System.Math.Max(4, digestSize)];
  136. byte[] rv = new byte[(klen + 7) / 8];
  137. int off = 0;
  138. IMemoable memo = mDigest as IMemoable;
  139. IMemoable copy = null;
  140. if (memo != null)
  141. {
  142. AddFieldElement(mDigest, u.AffineXCoord);
  143. AddFieldElement(mDigest, u.AffineYCoord);
  144. mDigest.BlockUpdate(za, 0, za.Length);
  145. mDigest.BlockUpdate(zb, 0, zb.Length);
  146. copy = memo.Copy();
  147. }
  148. uint ct = 0;
  149. while (off < rv.Length)
  150. {
  151. if (memo != null)
  152. {
  153. memo.Reset(copy);
  154. }
  155. else
  156. {
  157. AddFieldElement(mDigest, u.AffineXCoord);
  158. AddFieldElement(mDigest, u.AffineYCoord);
  159. mDigest.BlockUpdate(za, 0, za.Length);
  160. mDigest.BlockUpdate(zb, 0, zb.Length);
  161. }
  162. Pack.UInt32_To_BE(++ct, buf, 0);
  163. mDigest.BlockUpdate(buf, 0, 4);
  164. mDigest.DoFinal(buf, 0);
  165. int copyLen = System.Math.Min(digestSize, rv.Length - off);
  166. Array.Copy(buf, 0, rv, off, copyLen);
  167. off += copyLen;
  168. }
  169. return rv;
  170. }
  171. //x1~=2^w+(x1 AND (2^w-1))
  172. private BigInteger Reduce(BigInteger x)
  173. {
  174. return x.And(BigInteger.One.ShiftLeft(mW).Subtract(BigInteger.One)).SetBit(mW);
  175. }
  176. private byte[] S1(IDigest digest, ECPoint u, byte[] inner)
  177. {
  178. digest.Update((byte)0x02);
  179. AddFieldElement(digest, u.AffineYCoord);
  180. digest.BlockUpdate(inner, 0, inner.Length);
  181. return DigestUtilities.DoFinal(digest);
  182. }
  183. private byte[] CalculateInnerHash(IDigest digest, ECPoint u, byte[] za, byte[] zb, ECPoint p1, ECPoint p2)
  184. {
  185. AddFieldElement(digest, u.AffineXCoord);
  186. digest.BlockUpdate(za, 0, za.Length);
  187. digest.BlockUpdate(zb, 0, zb.Length);
  188. AddFieldElement(digest, p1.AffineXCoord);
  189. AddFieldElement(digest, p1.AffineYCoord);
  190. AddFieldElement(digest, p2.AffineXCoord);
  191. AddFieldElement(digest, p2.AffineYCoord);
  192. return DigestUtilities.DoFinal(digest);
  193. }
  194. private byte[] S2(IDigest digest, ECPoint u, byte[] inner)
  195. {
  196. digest.Update((byte)0x03);
  197. AddFieldElement(digest, u.AffineYCoord);
  198. digest.BlockUpdate(inner, 0, inner.Length);
  199. return DigestUtilities.DoFinal(digest);
  200. }
  201. private byte[] GetZ(IDigest digest, byte[] userID, ECPoint pubPoint)
  202. {
  203. AddUserID(digest, userID);
  204. AddFieldElement(digest, mECParams.Curve.A);
  205. AddFieldElement(digest, mECParams.Curve.B);
  206. AddFieldElement(digest, mECParams.G.AffineXCoord);
  207. AddFieldElement(digest, mECParams.G.AffineYCoord);
  208. AddFieldElement(digest, pubPoint.AffineXCoord);
  209. AddFieldElement(digest, pubPoint.AffineYCoord);
  210. return DigestUtilities.DoFinal(digest);
  211. }
  212. private void AddUserID(IDigest digest, byte[] userID)
  213. {
  214. uint len = (uint)(userID.Length * 8);
  215. digest.Update((byte)(len >> 8));
  216. digest.Update((byte)len);
  217. digest.BlockUpdate(userID, 0, userID.Length);
  218. }
  219. private void AddFieldElement(IDigest digest, ECFieldElement v)
  220. {
  221. byte[] p = v.GetEncoded();
  222. digest.BlockUpdate(p, 0, p.Length);
  223. }
  224. }
  225. }
  226. #pragma warning restore
  227. #endif