平安校园
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

SM2CryptoUtil.cs 11 KiB

2 months ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. 
  2. //
  3. namespace SafeCampus.Core.Utils;
  4. /// <summary>
  5. /// SM2工具类
  6. /// </summary>
  7. public class SM2CryptoUtil
  8. {
  9. #region 获取公钥私钥
  10. /// <summary>
  11. /// 获取公钥私钥
  12. /// </summary>
  13. /// <returns></returns>
  14. public static SM2Model GetKey()
  15. {
  16. var sm2 = SM2.Instance;
  17. var key = sm2.ecc_key_pair_generator.GenerateKeyPair();
  18. var ecpriv = (ECPrivateKeyParameters)key.Private;
  19. var ecpub = (ECPublicKeyParameters)key.Public;
  20. var privateKey = ecpriv.D;
  21. var publicKey = ecpub.Q;
  22. var sM2Model = new SM2Model();
  23. sM2Model.PrivateKey = Encoding.UTF8.GetString(Hex.Encode(privateKey.ToByteArray())).ToUpper();
  24. sM2Model.PublicKey = Encoding.UTF8.GetString(Hex.Encode(publicKey.GetEncoded())).ToUpper();
  25. return sM2Model;
  26. }
  27. #endregion 获取公钥私钥
  28. #region 加密
  29. /// <summary>
  30. /// 加密
  31. /// </summary>
  32. /// <param name="publickey">公钥</param>
  33. /// <param name="sourceData">需要加密的值</param>
  34. /// <returns>加密结果</returns>
  35. public static string Encrypt(string publickey, string sourceData)
  36. {
  37. var data = Encrypt(Hex.Decode(publickey), Encoding.UTF8.GetBytes(sourceData));
  38. return data;
  39. }
  40. /// <summary>
  41. /// 加密
  42. /// </summary>
  43. /// <param name="publicKey">公钥</param>
  44. /// <param name="data">需要加密的值</param>
  45. /// <returns></returns>
  46. public static string Encrypt(byte[] publicKey, byte[] data)
  47. {
  48. if (null == publicKey || publicKey.Length == 0)
  49. {
  50. return null;
  51. }
  52. if (data == null || data.Length == 0)
  53. {
  54. return null;
  55. }
  56. var source = new byte[data.Length];
  57. Array.Copy(data, 0, source, 0,
  58. data.Length);
  59. var cipher = new Cipher();
  60. var sm2 = SM2.Instance;
  61. var userKey = sm2.ecc_curve.DecodePoint(publicKey);
  62. var c1 = cipher.Init_enc(sm2, userKey);
  63. cipher.Encrypt(source);
  64. var c3 = new byte[32];
  65. cipher.Dofinal(c3);
  66. var sc1 = Encoding.UTF8.GetString(Hex.Encode(c1.GetEncoded()));
  67. var sc2 = Encoding.UTF8.GetString(Hex.Encode(source));
  68. var sc3 = Encoding.UTF8.GetString(Hex.Encode(c3));
  69. return (sc1 + sc2 + sc3).ToUpper();
  70. }
  71. #endregion 加密
  72. #region 解密
  73. /// <summary>
  74. ///
  75. /// </summary>
  76. /// <param name="privateKey"></param>
  77. /// <param name="encryptedData"></param>
  78. /// <returns></returns>
  79. public static string Decrypt(string privateKey, string encryptedData)
  80. {
  81. var data = Encoding.UTF8.GetString(Decrypt(Hex.Decode(privateKey), Hex.Decode(encryptedData)));
  82. return data;
  83. }
  84. /// <summary>
  85. /// 解密
  86. /// </summary>
  87. /// <param name="privateKey"></param>
  88. /// <param name="encryptedData"></param>
  89. /// <returns></returns>
  90. public static byte[] Decrypt(byte[] privateKey, byte[] encryptedData)
  91. {
  92. if (null == privateKey || privateKey.Length == 0)
  93. {
  94. return null;
  95. }
  96. if (encryptedData == null || encryptedData.Length == 0)
  97. {
  98. return null;
  99. }
  100. var data = Encoding.UTF8.GetString(Hex.Encode(encryptedData));
  101. var c1Bytes = Hex.Decode(Encoding.UTF8.GetBytes(data.Substring(0, 130)));
  102. var c2Len = encryptedData.Length - 97;
  103. var c2 = Hex.Decode(Encoding.UTF8.GetBytes(data.Substring(130, 2 * c2Len)));
  104. var c3 = Hex.Decode(Encoding.UTF8.GetBytes(data.Substring(130 + 2 * c2Len, 64)));
  105. var sm2 = SM2.Instance;
  106. var userD = new BigInteger(1, privateKey);
  107. //ECPoint c1 = sm2.ecc_curve.DecodePoint(c1Bytes);
  108. var c1 = sm2.ecc_curve.DecodePoint(c1Bytes);
  109. var cipher = new Cipher();
  110. cipher.Init_dec(userD, c1);
  111. cipher.Decrypt(c2);
  112. cipher.Dofinal(c3);
  113. return c2;
  114. }
  115. #endregion 解密
  116. private class Cipher
  117. {
  118. private int ct;
  119. private ECPoint p2;
  120. private SM3Digest sm3keybase;
  121. private SM3Digest sm3c3;
  122. private byte[] key;
  123. private byte keyOff;
  124. public Cipher()
  125. {
  126. ct = 1;
  127. key = new byte[32];
  128. keyOff = 0;
  129. }
  130. public static byte[] byteConvert32Bytes(BigInteger n)
  131. {
  132. byte[] tmpd;
  133. if (n == null)
  134. {
  135. return null;
  136. }
  137. if (n.ToByteArray().Length == 33)
  138. {
  139. tmpd = new byte[32];
  140. Array.Copy(n.ToByteArray(), 1, tmpd, 0,
  141. 32);
  142. }
  143. else if (n.ToByteArray().Length == 32)
  144. {
  145. tmpd = n.ToByteArray();
  146. }
  147. else
  148. {
  149. tmpd = new byte[32];
  150. for (var i = 0; i < 32 - n.ToByteArray().Length; i++)
  151. {
  152. tmpd[i] = 0;
  153. }
  154. Array.Copy(n.ToByteArray(), 0, tmpd, 32 - n.ToByteArray().Length,
  155. n.ToByteArray().Length);
  156. }
  157. return tmpd;
  158. }
  159. private void Reset()
  160. {
  161. sm3keybase = new SM3Digest();
  162. sm3c3 = new SM3Digest();
  163. var p = byteConvert32Bytes(p2.Normalize().XCoord.ToBigInteger());
  164. sm3keybase.BlockUpdate(p, 0, p.Length);
  165. sm3c3.BlockUpdate(p, 0, p.Length);
  166. p = byteConvert32Bytes(p2.Normalize().YCoord.ToBigInteger());
  167. sm3keybase.BlockUpdate(p, 0, p.Length);
  168. ct = 1;
  169. NextKey();
  170. }
  171. private void NextKey()
  172. {
  173. var sm3keycur = new SM3Digest(sm3keybase);
  174. sm3keycur.Update((byte)(ct >> 24 & 0xff));
  175. sm3keycur.Update((byte)(ct >> 16 & 0xff));
  176. sm3keycur.Update((byte)(ct >> 8 & 0xff));
  177. sm3keycur.Update((byte)(ct & 0xff));
  178. sm3keycur.DoFinal(key, 0);
  179. keyOff = 0;
  180. ct++;
  181. }
  182. public ECPoint Init_enc(SM2 sm2, ECPoint userKey)
  183. {
  184. var key = sm2.ecc_key_pair_generator.GenerateKeyPair();
  185. var ecpriv = (ECPrivateKeyParameters)key.Private;
  186. var ecpub = (ECPublicKeyParameters)key.Public;
  187. var k = ecpriv.D;
  188. var c1 = ecpub.Q;
  189. p2 = userKey.Multiply(k);
  190. Reset();
  191. return c1;
  192. }
  193. public void Encrypt(byte[] data)
  194. {
  195. sm3c3.BlockUpdate(data, 0, data.Length);
  196. for (var i = 0; i < data.Length; i++)
  197. {
  198. if (keyOff == key.Length)
  199. {
  200. NextKey();
  201. }
  202. data[i] ^= key[keyOff++];
  203. }
  204. }
  205. public void Init_dec(BigInteger userD, ECPoint c1)
  206. {
  207. p2 = c1.Multiply(userD);
  208. Reset();
  209. }
  210. public void Decrypt(byte[] data)
  211. {
  212. for (var i = 0; i < data.Length; i++)
  213. {
  214. if (keyOff == key.Length)
  215. {
  216. NextKey();
  217. }
  218. data[i] ^= key[keyOff++];
  219. }
  220. sm3c3.BlockUpdate(data, 0, data.Length);
  221. }
  222. public void Dofinal(byte[] c3)
  223. {
  224. var p = byteConvert32Bytes(p2.Normalize().YCoord.ToBigInteger());
  225. sm3c3.BlockUpdate(p, 0, p.Length);
  226. sm3c3.DoFinal(c3, 0);
  227. Reset();
  228. }
  229. }
  230. private class SM2
  231. {
  232. public static SM2 Instance
  233. {
  234. get
  235. {
  236. return new SM2();
  237. }
  238. }
  239. public static SM2 InstanceTest
  240. {
  241. get
  242. {
  243. return new SM2();
  244. }
  245. }
  246. public static readonly string[] sm2_param =
  247. {
  248. "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF",// p,0
  249. "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC",// a,1
  250. "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93",// b,2
  251. "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123",// n,3
  252. "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7",// gx,4
  253. "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"// gy,5
  254. };
  255. public string[] ecc_param = sm2_param;
  256. public readonly BigInteger ecc_p;
  257. public readonly BigInteger ecc_a;
  258. public readonly BigInteger ecc_b;
  259. public readonly BigInteger ecc_n;
  260. public readonly BigInteger ecc_gx;
  261. public readonly BigInteger ecc_gy;
  262. public readonly ECCurve ecc_curve;
  263. public readonly ECPoint ecc_point_g;
  264. public readonly ECDomainParameters ecc_bc_spec;
  265. public readonly ECKeyPairGenerator ecc_key_pair_generator;
  266. private SM2()
  267. {
  268. ecc_param = sm2_param;
  269. ECFieldElement ecc_gx_fieldelement;
  270. ECFieldElement ecc_gy_fieldelement;
  271. ecc_p = new BigInteger(ecc_param[0], 16);
  272. ecc_a = new BigInteger(ecc_param[1], 16);
  273. ecc_b = new BigInteger(ecc_param[2], 16);
  274. ecc_n = new BigInteger(ecc_param[3], 16);
  275. ecc_gx = new BigInteger(ecc_param[4], 16);
  276. ecc_gy = new BigInteger(ecc_param[5], 16);
  277. ecc_gx_fieldelement = new FpFieldElement(ecc_p, ecc_gx);
  278. ecc_gy_fieldelement = new FpFieldElement(ecc_p, ecc_gy);
  279. ecc_curve = new FpCurve(ecc_p, ecc_a, ecc_b);
  280. ecc_point_g = new FpPoint(ecc_curve, ecc_gx_fieldelement, ecc_gy_fieldelement);
  281. ecc_bc_spec = new ECDomainParameters(ecc_curve, ecc_point_g, ecc_n);
  282. ECKeyGenerationParameters ecc_ecgenparam;
  283. ecc_ecgenparam = new ECKeyGenerationParameters(ecc_bc_spec, new SecureRandom());
  284. ecc_key_pair_generator = new ECKeyPairGenerator();
  285. ecc_key_pair_generator.Init(ecc_ecgenparam);
  286. }
  287. public virtual byte[] Sm2GetZ(byte[] userId, ECPoint userKey)
  288. {
  289. var sm3 = new SM3Digest();
  290. byte[] p;
  291. // userId length
  292. var len = userId.Length * 8;
  293. sm3.Update((byte)(len >> 8 & 0x00ff));
  294. sm3.Update((byte)(len & 0x00ff));
  295. // userId
  296. sm3.BlockUpdate(userId, 0, userId.Length);
  297. // a,b
  298. p = ecc_a.ToByteArray();
  299. sm3.BlockUpdate(p, 0, p.Length);
  300. p = ecc_b.ToByteArray();
  301. sm3.BlockUpdate(p, 0, p.Length);
  302. // gx,gy
  303. p = ecc_gx.ToByteArray();
  304. sm3.BlockUpdate(p, 0, p.Length);
  305. p = ecc_gy.ToByteArray();
  306. sm3.BlockUpdate(p, 0, p.Length);
  307. // x,y
  308. p = userKey.AffineXCoord.ToBigInteger().ToByteArray();
  309. sm3.BlockUpdate(p, 0, p.Length);
  310. p = userKey.AffineYCoord.ToBigInteger().ToByteArray();
  311. sm3.BlockUpdate(p, 0, p.Length);
  312. // Z
  313. var md = new byte[sm3.GetDigestSize()];
  314. sm3.DoFinal(md, 0);
  315. return md;
  316. }
  317. }
  318. public class SM2Model
  319. {
  320. /// <summary>
  321. /// 公钥
  322. /// </summary>
  323. public string PublicKey { get; set; }
  324. /// <summary>
  325. /// 私钥
  326. /// </summary>
  327. public string PrivateKey { get; set; }
  328. }
  329. }