SM2Engine.cs 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  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.Crypto.Utilities;
  7. using BestHTTP.SecureProtocol.Org.BouncyCastle.Math;
  8. using BestHTTP.SecureProtocol.Org.BouncyCastle.Math.EC;
  9. using BestHTTP.SecureProtocol.Org.BouncyCastle.Math.EC.Multiplier;
  10. using BestHTTP.SecureProtocol.Org.BouncyCastle.Security;
  11. using BestHTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  12. namespace BestHTTP.SecureProtocol.Org.BouncyCastle.Crypto.Engines
  13. {
  14. /// <summary>
  15. /// SM2 public key encryption engine - based on https://tools.ietf.org/html/draft-shen-sm2-ecdsa-02.
  16. /// </summary>
  17. public class SM2Engine
  18. {
  19. private readonly IDigest mDigest;
  20. private bool mForEncryption;
  21. private ECKeyParameters mECKey;
  22. private ECDomainParameters mECParams;
  23. private int mCurveLength;
  24. private SecureRandom mRandom;
  25. public SM2Engine()
  26. : this(new SM3Digest())
  27. {
  28. }
  29. public SM2Engine(IDigest digest)
  30. {
  31. this.mDigest = digest;
  32. }
  33. public virtual void Init(bool forEncryption, ICipherParameters param)
  34. {
  35. this.mForEncryption = forEncryption;
  36. if (forEncryption)
  37. {
  38. ParametersWithRandom rParam = (ParametersWithRandom)param;
  39. mECKey = (ECKeyParameters)rParam.Parameters;
  40. mECParams = mECKey.Parameters;
  41. ECPoint s = ((ECPublicKeyParameters)mECKey).Q.Multiply(mECParams.H);
  42. if (s.IsInfinity)
  43. throw new ArgumentException("invalid key: [h]Q at infinity");
  44. mRandom = rParam.Random;
  45. }
  46. else
  47. {
  48. mECKey = (ECKeyParameters)param;
  49. mECParams = mECKey.Parameters;
  50. }
  51. mCurveLength = (mECParams.Curve.FieldSize + 7) / 8;
  52. }
  53. public virtual byte[] ProcessBlock(byte[] input, int inOff, int inLen)
  54. {
  55. if (mForEncryption)
  56. {
  57. return Encrypt(input, inOff, inLen);
  58. }
  59. else
  60. {
  61. return Decrypt(input, inOff, inLen);
  62. }
  63. }
  64. protected virtual ECMultiplier CreateBasePointMultiplier()
  65. {
  66. return new FixedPointCombMultiplier();
  67. }
  68. private byte[] Encrypt(byte[] input, int inOff, int inLen)
  69. {
  70. byte[] c2 = new byte[inLen];
  71. Array.Copy(input, inOff, c2, 0, c2.Length);
  72. ECMultiplier multiplier = CreateBasePointMultiplier();
  73. byte[] c1;
  74. ECPoint kPB;
  75. do
  76. {
  77. BigInteger k = NextK();
  78. ECPoint c1P = multiplier.Multiply(mECParams.G, k).Normalize();
  79. c1 = c1P.GetEncoded(false);
  80. kPB = ((ECPublicKeyParameters)mECKey).Q.Multiply(k).Normalize();
  81. Kdf(mDigest, kPB, c2);
  82. }
  83. while (NotEncrypted(c2, input, inOff));
  84. AddFieldElement(mDigest, kPB.AffineXCoord);
  85. mDigest.BlockUpdate(input, inOff, inLen);
  86. AddFieldElement(mDigest, kPB.AffineYCoord);
  87. byte[] c3 = DigestUtilities.DoFinal(mDigest);
  88. return Arrays.ConcatenateAll(c1, c2, c3);
  89. }
  90. private byte[] Decrypt(byte[] input, int inOff, int inLen)
  91. {
  92. byte[] c1 = new byte[mCurveLength * 2 + 1];
  93. Array.Copy(input, inOff, c1, 0, c1.Length);
  94. ECPoint c1P = mECParams.Curve.DecodePoint(c1);
  95. ECPoint s = c1P.Multiply(mECParams.H);
  96. if (s.IsInfinity)
  97. throw new InvalidCipherTextException("[h]C1 at infinity");
  98. c1P = c1P.Multiply(((ECPrivateKeyParameters)mECKey).D).Normalize();
  99. byte[] c2 = new byte[inLen - c1.Length - mDigest.GetDigestSize()];
  100. Array.Copy(input, inOff + c1.Length, c2, 0, c2.Length);
  101. Kdf(mDigest, c1P, c2);
  102. AddFieldElement(mDigest, c1P.AffineXCoord);
  103. mDigest.BlockUpdate(c2, 0, c2.Length);
  104. AddFieldElement(mDigest, c1P.AffineYCoord);
  105. byte[] c3 = DigestUtilities.DoFinal(mDigest);
  106. int check = 0;
  107. for (int i = 0; i != c3.Length; i++)
  108. {
  109. check |= c3[i] ^ input[inOff + c1.Length + c2.Length + i];
  110. }
  111. Arrays.Fill(c1, 0);
  112. Arrays.Fill(c3, 0);
  113. if (check != 0)
  114. {
  115. Arrays.Fill(c2, 0);
  116. throw new InvalidCipherTextException("invalid cipher text");
  117. }
  118. return c2;
  119. }
  120. private bool NotEncrypted(byte[] encData, byte[] input, int inOff)
  121. {
  122. for (int i = 0; i != encData.Length; i++)
  123. {
  124. if (encData[i] != input[inOff + i])
  125. {
  126. return false;
  127. }
  128. }
  129. return true;
  130. }
  131. private void Kdf(IDigest digest, ECPoint c1, byte[] encData)
  132. {
  133. int digestSize = digest.GetDigestSize();
  134. byte[] buf = new byte[System.Math.Max(4, digestSize)];
  135. int off = 0;
  136. IMemoable memo = digest as IMemoable;
  137. IMemoable copy = null;
  138. if (memo != null)
  139. {
  140. AddFieldElement(digest, c1.AffineXCoord);
  141. AddFieldElement(digest, c1.AffineYCoord);
  142. copy = memo.Copy();
  143. }
  144. uint ct = 0;
  145. while (off < encData.Length)
  146. {
  147. if (memo != null)
  148. {
  149. memo.Reset(copy);
  150. }
  151. else
  152. {
  153. AddFieldElement(digest, c1.AffineXCoord);
  154. AddFieldElement(digest, c1.AffineYCoord);
  155. }
  156. Pack.UInt32_To_BE(++ct, buf, 0);
  157. digest.BlockUpdate(buf, 0, 4);
  158. digest.DoFinal(buf, 0);
  159. int xorLen = System.Math.Min(digestSize, encData.Length - off);
  160. Xor(encData, buf, off, xorLen);
  161. off += xorLen;
  162. }
  163. }
  164. private void Xor(byte[] data, byte[] kdfOut, int dOff, int dRemaining)
  165. {
  166. for (int i = 0; i != dRemaining; i++)
  167. {
  168. data[dOff + i] ^= kdfOut[i];
  169. }
  170. }
  171. private BigInteger NextK()
  172. {
  173. int qBitLength = mECParams.N.BitLength;
  174. BigInteger k;
  175. do
  176. {
  177. k = new BigInteger(qBitLength, mRandom);
  178. }
  179. while (k.SignValue == 0 || k.CompareTo(mECParams.N) >= 0);
  180. return k;
  181. }
  182. private void AddFieldElement(IDigest digest, ECFieldElement v)
  183. {
  184. byte[] p = v.GetEncoded();
  185. digest.BlockUpdate(p, 0, p.Length);
  186. }
  187. }
  188. }
  189. #pragma warning restore
  190. #endif