Crypto.cs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927
  1. using System.Text;
  2. using Org.BouncyCastle.Crypto.Parameters;
  3. using Org.BouncyCastle.Crypto;
  4. using Org.BouncyCastle.Security;
  5. using System.Security.Cryptography;
  6. using Masuit.Tools.Security;
  7. using Org.BouncyCastle.Asn1.GM;
  8. using Org.BouncyCastle.Asn1.X9;
  9. using Org.BouncyCastle.Asn1;
  10. using Org.BouncyCastle.Crypto.Digests;
  11. using Org.BouncyCastle.Crypto.Engines;
  12. using Org.BouncyCastle.Crypto.Generators;
  13. using Org.BouncyCastle.Utilities.Encoders;
  14. using Org.BouncyCastle.Utilities;
  15. using Org.BouncyCastle.X509;
  16. using Org.BouncyCastle.Math;
  17. namespace EasyTemplate.Tool;
  18. public class Crypto
  19. {
  20. public static readonly string? aeskey = Setting.Get<string>("cryptogram:aesKey");//AESKey
  21. public static readonly string? deskey = Setting.Get<string>("cryptogram:descKey");//DESCKey
  22. public static readonly string? rsaPublicKey = Setting.Get<string>("cryptogram:rsaPublicKey");//RSAPublicKey
  23. public static readonly string? rsaPrivateKey = Setting.Get<string>("cryptogram:rsaPrivateKey");//RSAPrivateKey
  24. public static readonly string? sm2PublicKey = Setting.Get<string>("cryptogram:sm2PublicKey"); // 公钥
  25. public static readonly string? sm2PrivateKey = Setting.Get<string>("cryptogram:sm2PrivateKey"); // 私钥
  26. public static readonly string? sm4Key = Setting.Get<string>("cryptogram:sm4Key");//SM4Key
  27. public static readonly string? sm4IV = Setting.Get<string>("cryptogram:sm4IV");//SM4IV
  28. public static string Encrypt(string plain)
  29. => (Global.CrypType?.ToLower()) switch
  30. {
  31. "md5" => MD5Encrypt(plain),
  32. "aes" => AESEncrypt(plain),
  33. "des" => DESEncrypt(plain),
  34. "rsa" => RSAEncrypt(plain),
  35. "sm2" => SM2Encrypt(plain),
  36. "sm4" => SM4EncryptCBC(plain),
  37. _ => plain,
  38. };
  39. public static string Decrypt(string cipher)
  40. => (Global.CrypType?.ToLower()) switch
  41. {
  42. "aes" => AESDecrypt(cipher),
  43. "des" => DESDecrypt(cipher),
  44. "rsa" => RSADecrypt(cipher),
  45. "sm2" => SM2Decrypt(cipher),
  46. "sm4" => SM4DecryptCBC(cipher),
  47. _ => cipher,
  48. };
  49. public static string MD5Encrypt(string plain)
  50. => plain.MDString();
  51. public static string AESEncrypt(string plain)
  52. => plain.AESEncrypt(aeskey);
  53. public static string AESDecrypt(string cipher)
  54. => cipher.AESDecrypt(aeskey);
  55. public static string DESEncrypt(string plain)
  56. => plain.DesEncrypt(deskey);
  57. public static string DESDecrypt(string cipher)
  58. => cipher.DesDecrypt(deskey);
  59. public static string TokenDESEncrypt(string originalValue, string key)
  60. {
  61. return TokenDESEncrypt(originalValue, key, key);
  62. }
  63. public static string TokenDESEncrypt(string originalValue, string key, string IV)
  64. {
  65. if (string.IsNullOrEmpty(originalValue))
  66. {
  67. originalValue = string.Empty;
  68. }
  69. key += "abcdefgh";
  70. IV += "01234567";
  71. key = key.Substring(0, 8);
  72. IV = IV.Substring(0, 8);
  73. string result = string.Empty;
  74. SymmetricAlgorithm symmetricAlgorithm;
  75. ICryptoTransform cryptoTransform;
  76. using (MemoryStream memoryStream = new MemoryStream())
  77. {
  78. symmetricAlgorithm = new DESCryptoServiceProvider();
  79. symmetricAlgorithm.Key = Encoding.UTF8.GetBytes(key);
  80. symmetricAlgorithm.IV = Encoding.UTF8.GetBytes(IV);
  81. cryptoTransform = symmetricAlgorithm.CreateEncryptor();
  82. byte[] bytes = Encoding.UTF8.GetBytes(originalValue);
  83. CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write);
  84. cryptoStream.Write(bytes, 0, bytes.Length);
  85. cryptoStream.FlushFinalBlock();
  86. cryptoStream.Dispose();
  87. result = Convert.ToBase64String(memoryStream.ToArray());
  88. }
  89. cryptoTransform.Dispose();
  90. symmetricAlgorithm.Clear();
  91. return result;
  92. }
  93. public static string TokenDESDecrypt(string encryptedValue, string key)
  94. {
  95. return TokenDESDecrypt(encryptedValue, key, key);
  96. }
  97. public static string TokenDESDecrypt(string encryptedValue, string key, string IV)
  98. {
  99. key += "abcdefgh";
  100. IV += "01234567";
  101. key = key.Substring(0, 8);
  102. IV = IV.Substring(0, 8);
  103. SymmetricAlgorithm symmetricAlgorithm = new DESCryptoServiceProvider();
  104. symmetricAlgorithm.Key = Encoding.UTF8.GetBytes(key);
  105. symmetricAlgorithm.IV = Encoding.UTF8.GetBytes(IV);
  106. ICryptoTransform cryptoTransform = symmetricAlgorithm.CreateDecryptor();
  107. byte[] array = Convert.FromBase64String(encryptedValue);
  108. MemoryStream memoryStream = new MemoryStream();
  109. CryptoStream cryptoStream = new CryptoStream(memoryStream, cryptoTransform, CryptoStreamMode.Write);
  110. cryptoStream.Write(array, 0, array.Length);
  111. cryptoStream.FlushFinalBlock();
  112. cryptoStream.Dispose();
  113. memoryStream.Dispose();
  114. cryptoTransform.Dispose();
  115. symmetricAlgorithm.Clear();
  116. return Encoding.UTF8.GetString(memoryStream.ToArray());
  117. }
  118. public static string RSAEncrypt(string plain)
  119. => plain.RSAEncrypt(rsaPublicKey);
  120. public static string RSADecrypt(string cipher)
  121. => cipher.RSADecrypt(rsaPrivateKey);
  122. public static string SM2Encrypt(string plain)
  123. => GMUtil.SM2Encrypt(sm2PublicKey, plain);
  124. public static string SM2Decrypt(string cipher)
  125. {
  126. try
  127. {
  128. return GMUtil.SM2Decrypt(sm2PrivateKey, cipher);
  129. }
  130. catch (Exception)
  131. {
  132. return string.Empty;
  133. }
  134. }
  135. public static string SM4EncryptECB(string plain)
  136. => GMUtil.SM4EncryptECB(sm4Key, plain);
  137. public static string SM4DecryptECB(string cipher)
  138. {
  139. try
  140. {
  141. return GMUtil.SM2Decrypt(sm4Key, cipher);
  142. }
  143. catch (Exception)
  144. {
  145. return string.Empty;
  146. }
  147. }
  148. public static string SM4EncryptCBC(string plain)
  149. => GMUtil.SM4EncryptCBC(sm4Key, sm4IV, plain);
  150. public static string SM4DecryptCBC(string cipher)
  151. {
  152. try
  153. {
  154. return GMUtil.SM4DecryptCBC(sm4Key, sm4IV, cipher);
  155. }
  156. catch (Exception)
  157. {
  158. return string.Empty;
  159. }
  160. }
  161. /// <summary>
  162. /// 签名
  163. /// </summary>
  164. /// <param name="halg">算法如:SHA256</param>
  165. /// <param name="text">明文内容</param>
  166. /// <param name="privateKey">私钥</param>
  167. /// <returns>签名内容</returns>
  168. public static string RSASign(string halg, string text, string privateKey)
  169. {
  170. string encryptedContent;
  171. using var rsa = new System.Security.Cryptography.RSACryptoServiceProvider();
  172. rsa.FromXmlString(privateKey);
  173. var encryptedData = rsa.SignData(Encoding.Default.GetBytes(text), halg);
  174. encryptedContent = Convert.ToBase64String(encryptedData);
  175. return encryptedContent;
  176. }
  177. /// <summary>
  178. /// 校验
  179. /// </summary>
  180. /// <param name="halg">算法如:SHA256</param>
  181. /// <param name="text">明文内容</param>
  182. /// <param name="publicKey">公钥</param>
  183. /// <param name="sign">签名内容</param>
  184. /// <returns>是否一致</returns>
  185. public static bool RSAVerify(string halg, string text, string publicKey, string sign)
  186. {
  187. using var rsa = new System.Security.Cryptography.RSACryptoServiceProvider();
  188. rsa.FromXmlString(publicKey);
  189. return rsa.VerifyData(Encoding.Default.GetBytes(text), halg, Convert.FromBase64String(sign));
  190. }
  191. /// <summary>
  192. /// 公钥格式的转换
  193. /// </summary>
  194. /// <param name="publicKey"></param>
  195. /// <returns></returns>
  196. public static string RSAPublicKeyToXml(string publicKey)
  197. {
  198. try
  199. {
  200. if (string.IsNullOrWhiteSpace(publicKey))
  201. {
  202. return "";
  203. }
  204. if (publicKey.Contains("<RSAKeyValue>"))
  205. {
  206. return publicKey;
  207. }
  208. RsaKeyParameters publicKeyParam;
  209. //尝试进行java格式的密钥读取
  210. try
  211. {
  212. publicKeyParam = (RsaKeyParameters)PublicKeyFactory.CreateKey(Convert.FromBase64String(publicKey));
  213. }
  214. catch
  215. {
  216. publicKeyParam = null;
  217. }
  218. //非java格式密钥进行pem格式的密钥读取
  219. if (publicKeyParam == null)
  220. {
  221. try
  222. {
  223. var pemKey = publicKey;
  224. if (!pemKey.Contains("BEGIN RSA PRIVATE KEY"))
  225. {
  226. pemKey = @"-----BEGIN RSA PRIVATE KEY-----
  227. " + publicKey + @"
  228. -----END RSA PRIVATE KEY-----";
  229. }
  230. var array = Encoding.ASCII.GetBytes(pemKey);
  231. var stream = new MemoryStream(array);
  232. var reader = new StreamReader(stream);
  233. var pemReader = new Org.BouncyCastle.OpenSsl.PemReader(reader);
  234. publicKeyParam = (RsaKeyParameters)pemReader.ReadObject();
  235. }
  236. catch
  237. {
  238. publicKeyParam = null;
  239. }
  240. }
  241. //如果都解析失败,则返回原串
  242. if (publicKeyParam == null)
  243. {
  244. return publicKey;
  245. }
  246. //输出XML格式密钥
  247. return $@"<RSAKeyValue><Modulus>{Convert.ToBase64String(publicKeyParam.Modulus.ToByteArrayUnsigned())}</Modulus><Exponent>{Convert.ToBase64String(publicKeyParam.Exponent.ToByteArrayUnsigned())}</Exponent></RSAKeyValue>";
  248. }
  249. catch
  250. {
  251. return "";
  252. }
  253. }
  254. /// <summary>
  255. /// 私钥格式转换
  256. /// </summary>
  257. /// <param name="privateKey"></param>
  258. /// <returns></returns>
  259. public static string RSAPrivateKeyToXml(string privateKey)
  260. {
  261. try
  262. {
  263. if (string.IsNullOrWhiteSpace(privateKey))
  264. {
  265. return "";
  266. }
  267. if (privateKey.Contains("<RSAKeyValue>"))
  268. {
  269. return privateKey;
  270. }
  271. RsaPrivateCrtKeyParameters privateKeyParam;
  272. //尝试进行java格式的密钥读取
  273. try
  274. {
  275. privateKeyParam = (RsaPrivateCrtKeyParameters)PrivateKeyFactory.CreateKey(Convert.FromBase64String(privateKey));
  276. }
  277. catch
  278. {
  279. privateKeyParam = null;
  280. }
  281. //非java格式密钥进行pem格式的密钥读取
  282. if (privateKeyParam == null)
  283. {
  284. try
  285. {
  286. var pemKey = privateKey;
  287. if (!pemKey.Contains("BEGIN RSA PRIVATE KEY"))
  288. {
  289. pemKey = @"-----BEGIN RSA PRIVATE KEY-----
  290. " + privateKey + @"
  291. -----END RSA PRIVATE KEY-----";
  292. }
  293. var array = Encoding.ASCII.GetBytes(pemKey);
  294. var stream = new MemoryStream(array);
  295. var reader = new StreamReader(stream);
  296. var pemReader = new Org.BouncyCastle.OpenSsl.PemReader(reader);
  297. var keyPair = (AsymmetricCipherKeyPair)pemReader.ReadObject();
  298. privateKeyParam = (RsaPrivateCrtKeyParameters)keyPair.Private;
  299. }
  300. catch
  301. {
  302. privateKeyParam = null;
  303. }
  304. }
  305. //如果都解析失败,则返回原串
  306. if (privateKeyParam == null)
  307. {
  308. return privateKey;
  309. }
  310. //输出XML格式密钥
  311. return $@"<RSAKeyValue><Modulus>{Convert.ToBase64String(privateKeyParam.Modulus.ToByteArrayUnsigned())}</Modulus><Exponent>{Convert.ToBase64String(privateKeyParam.PublicExponent.ToByteArrayUnsigned())}</Exponent><P>{Convert.ToBase64String(privateKeyParam.P.ToByteArrayUnsigned())}</P><Q>{Convert.ToBase64String(privateKeyParam.Q.ToByteArrayUnsigned())}</Q><DP>{Convert.ToBase64String(privateKeyParam.DP.ToByteArrayUnsigned())}</DP><DQ>{Convert.ToBase64String(privateKeyParam.DQ.ToByteArrayUnsigned())}</DQ><InverseQ>{Convert.ToBase64String(privateKeyParam.QInv.ToByteArrayUnsigned())}</InverseQ><D>{Convert.ToBase64String(privateKeyParam.Exponent.ToByteArrayUnsigned())}</D></RSAKeyValue>";
  312. }
  313. catch
  314. {
  315. return "";
  316. }
  317. }
  318. }
  319. public class GM
  320. {
  321. private static X9ECParameters x9ECParameters = GMNamedCurves.GetByName("sm2p256v1");
  322. private static ECDomainParameters ecDomainParameters = new(x9ECParameters.Curve, x9ECParameters.G, x9ECParameters.N);
  323. /**
  324. *
  325. * @param msg
  326. * @param userId
  327. * @param privateKey
  328. * @return r||s,直接拼接byte数组的rs
  329. */
  330. public static byte[] SignSm3WithSm2(byte[] msg, byte[] userId, AsymmetricKeyParameter privateKey)
  331. {
  332. return RsAsn1ToPlainByteArray(SignSm3WithSm2Asn1Rs(msg, userId, privateKey));
  333. }
  334. /**
  335. * @param msg
  336. * @param userId
  337. * @param privateKey
  338. * @return rs in <b>asn1 format</b>
  339. */
  340. public static byte[] SignSm3WithSm2Asn1Rs(byte[] msg, byte[] userId, AsymmetricKeyParameter privateKey)
  341. {
  342. ISigner signer = SignerUtilities.GetSigner("SM3withSM2");
  343. signer.Init(true, new ParametersWithID(privateKey, userId));
  344. signer.BlockUpdate(msg, 0, msg.Length);
  345. byte[] sig = signer.GenerateSignature();
  346. return sig;
  347. }
  348. /**
  349. *
  350. * @param msg
  351. * @param userId
  352. * @param rs r||s,直接拼接byte数组的rs
  353. * @param publicKey
  354. * @return
  355. */
  356. public static bool VerifySm3WithSm2(byte[] msg, byte[] userId, byte[] rs, AsymmetricKeyParameter publicKey)
  357. {
  358. if (rs == null || msg == null || userId == null) return false;
  359. if (rs.Length != RS_LEN * 2) return false;
  360. return VerifySm3WithSm2Asn1Rs(msg, userId, RsPlainByteArrayToAsn1(rs), publicKey);
  361. }
  362. /**
  363. *
  364. * @param msg
  365. * @param userId
  366. * @param rs in <b>asn1 format</b>
  367. * @param publicKey
  368. * @return
  369. */
  370. public static bool VerifySm3WithSm2Asn1Rs(byte[] msg, byte[] userId, byte[] sign, AsymmetricKeyParameter publicKey)
  371. {
  372. ISigner signer = SignerUtilities.GetSigner("SM3withSM2");
  373. signer.Init(false, new ParametersWithID(publicKey, userId));
  374. signer.BlockUpdate(msg, 0, msg.Length);
  375. return signer.VerifySignature(sign);
  376. }
  377. /**
  378. * bc加解密使用旧标c1||c2||c3,此方法在加密后调用,将结果转化为c1||c3||c2
  379. * @param c1c2c3
  380. * @return
  381. */
  382. private static byte[] ChangeC1C2C3ToC1C3C2(byte[] c1c2c3)
  383. {
  384. int c1Len = (x9ECParameters.Curve.FieldSize + 7) / 8 * 2 + 1; //sm2p256v1的这个固定65。可看GMNamedCurves、ECCurve代码。
  385. const int c3Len = 32; //new SM3Digest().getDigestSize();
  386. byte[] result = new byte[c1c2c3.Length];
  387. Buffer.BlockCopy(c1c2c3, 0, result, 0, c1Len); //c1
  388. Buffer.BlockCopy(c1c2c3, c1c2c3.Length - c3Len, result, c1Len, c3Len); //c3
  389. Buffer.BlockCopy(c1c2c3, c1Len, result, c1Len + c3Len, c1c2c3.Length - c1Len - c3Len); //c2
  390. return result;
  391. }
  392. /**
  393. * bc加解密使用旧标c1||c3||c2,此方法在解密前调用,将密文转化为c1||c2||c3再去解密
  394. * @param c1c3c2
  395. * @return
  396. */
  397. private static byte[] ChangeC1C3C2ToC1C2C3(byte[] c1c3c2)
  398. {
  399. int c1Len = (x9ECParameters.Curve.FieldSize + 7) / 8 * 2 + 1; //sm2p256v1的这个固定65。可看GMNamedCurves、ECCurve代码。
  400. const int c3Len = 32; //new SM3Digest().GetDigestSize();
  401. byte[] result = new byte[c1c3c2.Length];
  402. Buffer.BlockCopy(c1c3c2, 0, result, 0, c1Len); //c1: 0->65
  403. Buffer.BlockCopy(c1c3c2, c1Len + c3Len, result, c1Len, c1c3c2.Length - c1Len - c3Len); //c2
  404. Buffer.BlockCopy(c1c3c2, c1Len, result, c1c3c2.Length - c3Len, c3Len); //c3
  405. return result;
  406. }
  407. /**
  408. * c1||c3||c2
  409. * @param data
  410. * @param key
  411. * @return
  412. */
  413. public static byte[] Sm2Decrypt(byte[] data, AsymmetricKeyParameter key)
  414. {
  415. return Sm2DecryptOld(ChangeC1C3C2ToC1C2C3(data), key);
  416. }
  417. /**
  418. * c1||c3||c2
  419. * @param data
  420. * @param key
  421. * @return
  422. */
  423. public static byte[] Sm2Encrypt(byte[] data, AsymmetricKeyParameter key)
  424. {
  425. return ChangeC1C2C3ToC1C3C2(Sm2EncryptOld(data, key));
  426. }
  427. /**
  428. * c1||c2||c3
  429. * @param data
  430. * @param key
  431. * @return
  432. */
  433. public static byte[] Sm2EncryptOld(byte[] data, AsymmetricKeyParameter pubkey)
  434. {
  435. SM2Engine sm2Engine = new SM2Engine();
  436. sm2Engine.Init(true, new ParametersWithRandom(pubkey, new SecureRandom()));
  437. return sm2Engine.ProcessBlock(data, 0, data.Length);
  438. }
  439. /**
  440. * c1||c2||c3
  441. * @param data
  442. * @param key
  443. * @return
  444. */
  445. public static byte[] Sm2DecryptOld(byte[] data, AsymmetricKeyParameter key)
  446. {
  447. SM2Engine sm2Engine = new SM2Engine();
  448. sm2Engine.Init(false, key);
  449. return sm2Engine.ProcessBlock(data, 0, data.Length);
  450. }
  451. /**
  452. * @param bytes
  453. * @return
  454. */
  455. public static byte[] Sm3(byte[] bytes)
  456. {
  457. SM3Digest digest = new();
  458. digest.BlockUpdate(bytes, 0, bytes.Length);
  459. byte[] result = DigestUtilities.DoFinal(digest);
  460. return result;
  461. }
  462. private const int RS_LEN = 32;
  463. private static byte[] BigIntToFixexLengthBytes(BigInteger rOrS)
  464. {
  465. // for sm2p256v1, n is 00fffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123,
  466. // r and s are the result of mod n, so they should be less than n and have length<=32
  467. byte[] rs = rOrS.ToByteArray();
  468. if (rs.Length == RS_LEN) return rs;
  469. else if (rs.Length == RS_LEN + 1 && rs[0] == 0) return Arrays.CopyOfRange(rs, 1, RS_LEN + 1);
  470. else if (rs.Length < RS_LEN)
  471. {
  472. byte[] result = new byte[RS_LEN];
  473. Arrays.Fill(result, (byte)0);
  474. Buffer.BlockCopy(rs, 0, result, RS_LEN - rs.Length, rs.Length);
  475. return result;
  476. }
  477. else
  478. {
  479. throw new ArgumentException("err rs: " + Hex.ToHexString(rs));
  480. }
  481. }
  482. /**
  483. * BC的SM3withSM2签名得到的结果的rs是asn1格式的,这个方法转化成直接拼接r||s
  484. * @param rsDer rs in asn1 format
  485. * @return sign result in plain byte array
  486. */
  487. private static byte[] RsAsn1ToPlainByteArray(byte[] rsDer)
  488. {
  489. Asn1Sequence seq = Asn1Sequence.GetInstance(rsDer);
  490. byte[] r = BigIntToFixexLengthBytes(DerInteger.GetInstance(seq[0]).Value);
  491. byte[] s = BigIntToFixexLengthBytes(DerInteger.GetInstance(seq[1]).Value);
  492. byte[] result = new byte[RS_LEN * 2];
  493. Buffer.BlockCopy(r, 0, result, 0, r.Length);
  494. Buffer.BlockCopy(s, 0, result, RS_LEN, s.Length);
  495. return result;
  496. }
  497. /**
  498. * BC的SM3withSM2验签需要的rs是asn1格式的,这个方法将直接拼接r||s的字节数组转化成asn1格式
  499. * @param sign in plain byte array
  500. * @return rs result in asn1 format
  501. */
  502. private static byte[] RsPlainByteArrayToAsn1(byte[] sign)
  503. {
  504. if (sign.Length != RS_LEN * 2) throw new ArgumentException("err rs. ");
  505. BigInteger r = new BigInteger(1, Arrays.CopyOfRange(sign, 0, RS_LEN));
  506. BigInteger s = new BigInteger(1, Arrays.CopyOfRange(sign, RS_LEN, RS_LEN * 2));
  507. Asn1EncodableVector v = new Asn1EncodableVector
  508. {
  509. new DerInteger(r),
  510. new DerInteger(s)
  511. };
  512. return new DerSequence(v).GetEncoded("DER");
  513. }
  514. // 生成公私匙对
  515. public static AsymmetricCipherKeyPair GenerateKeyPair()
  516. {
  517. ECKeyPairGenerator kpGen = new();
  518. kpGen.Init(new ECKeyGenerationParameters(ecDomainParameters, new SecureRandom()));
  519. return kpGen.GenerateKeyPair();
  520. }
  521. public static ECPrivateKeyParameters GetPrivatekeyFromD(BigInteger d)
  522. {
  523. return new ECPrivateKeyParameters(d, ecDomainParameters);
  524. }
  525. public static ECPublicKeyParameters GetPublickeyFromXY(BigInteger x, BigInteger y)
  526. {
  527. return new ECPublicKeyParameters(x9ECParameters.Curve.CreatePoint(x, y), ecDomainParameters);
  528. }
  529. public static AsymmetricKeyParameter GetPublickeyFromX509File(FileInfo file)
  530. {
  531. FileStream fileStream = null;
  532. try
  533. {
  534. //file.DirectoryName + "\\" + file.Name
  535. fileStream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read);
  536. X509Certificate certificate = new X509CertificateParser().ReadCertificate(fileStream);
  537. return certificate.GetPublicKey();
  538. }
  539. catch (Exception)
  540. {
  541. //log.Error(file.Name + "读取失败,异常:" + e);
  542. }
  543. finally
  544. {
  545. if (fileStream != null)
  546. fileStream.Close();
  547. }
  548. return null;
  549. }
  550. public class Sm2Cert
  551. {
  552. public AsymmetricKeyParameter privateKey;
  553. public AsymmetricKeyParameter publicKey;
  554. public string certId;
  555. }
  556. private static byte[] ToByteArray(int i)
  557. {
  558. byte[] byteArray = new byte[4];
  559. byteArray[0] = (byte)(i >> 24);
  560. byteArray[1] = (byte)((i & 0xFFFFFF) >> 16);
  561. byteArray[2] = (byte)((i & 0xFFFF) >> 8);
  562. byteArray[3] = (byte)(i & 0xFF);
  563. return byteArray;
  564. }
  565. /**
  566. * 字节数组拼接
  567. *
  568. * @param params
  569. * @return
  570. */
  571. private static byte[] Join(params byte[][] byteArrays)
  572. {
  573. List<byte> byteSource = new();
  574. for (int i = 0; i < byteArrays.Length; i++)
  575. {
  576. byteSource.AddRange(byteArrays[i]);
  577. }
  578. byte[] data = byteSource.ToArray();
  579. return data;
  580. }
  581. /**
  582. * 密钥派生函数
  583. *
  584. * @param Z
  585. * @param klen
  586. * 生成klen字节数长度的密钥
  587. * @return
  588. */
  589. private static byte[] KDF(byte[] Z, int klen)
  590. {
  591. int ct = 1;
  592. int end = (int)Math.Ceiling(klen * 1.0 / 32);
  593. List<byte> byteSource = new();
  594. for (int i = 1; i < end; i++)
  595. {
  596. byteSource.AddRange(Sm3(Join(Z, ToByteArray(ct))));
  597. ct++;
  598. }
  599. byte[] last = Sm3(Join(Z, ToByteArray(ct)));
  600. if (klen % 32 == 0)
  601. {
  602. byteSource.AddRange(last);
  603. }
  604. else
  605. byteSource.AddRange(Arrays.CopyOfRange(last, 0, klen % 32));
  606. return byteSource.ToArray();
  607. }
  608. public static byte[] Sm4DecryptCBC(byte[] keyBytes, byte[] cipher, byte[] iv, string algo)
  609. {
  610. if (keyBytes.Length != 16) throw new ArgumentException("err key length");
  611. if (cipher.Length % 16 != 0 && algo.Contains("NoPadding")) throw new ArgumentException("err data length");
  612. KeyParameter key = ParameterUtilities.CreateKeyParameter("SM4", keyBytes);
  613. IBufferedCipher c = CipherUtilities.GetCipher(algo);
  614. if (iv == null) iv = ZeroIv(algo);
  615. c.Init(false, new ParametersWithIV(key, iv));
  616. return c.DoFinal(cipher);
  617. }
  618. public static byte[] Sm4EncryptCBC(byte[] keyBytes, byte[] plain, byte[] iv, string algo)
  619. {
  620. if (keyBytes.Length != 16) throw new ArgumentException("err key length");
  621. if (plain.Length % 16 != 0 && algo.Contains("NoPadding")) throw new ArgumentException("err data length");
  622. KeyParameter key = ParameterUtilities.CreateKeyParameter("SM4", keyBytes);
  623. IBufferedCipher c = CipherUtilities.GetCipher(algo);
  624. if (iv == null) iv = ZeroIv(algo);
  625. c.Init(true, new ParametersWithIV(key, iv));
  626. return c.DoFinal(plain);
  627. }
  628. public static byte[] Sm4EncryptECB(byte[] keyBytes, byte[] plain, string algo)
  629. {
  630. if (keyBytes.Length != 16) throw new ArgumentException("err key length");
  631. //NoPadding 的情况下需要校验数据长度是16的倍数.
  632. if (plain.Length % 16 != 0 && algo.Contains("NoPadding")) throw new ArgumentException("err data length");
  633. KeyParameter key = ParameterUtilities.CreateKeyParameter("SM4", keyBytes);
  634. IBufferedCipher c = CipherUtilities.GetCipher(algo);
  635. c.Init(true, key);
  636. return c.DoFinal(plain);
  637. }
  638. public static byte[] Sm4DecryptECB(byte[] keyBytes, byte[] cipher, string algo)
  639. {
  640. if (keyBytes.Length != 16) throw new ArgumentException("err key length");
  641. if (cipher.Length % 16 != 0 && algo.Contains("NoPadding")) throw new ArgumentException("err data length");
  642. KeyParameter key = ParameterUtilities.CreateKeyParameter("SM4", keyBytes);
  643. IBufferedCipher c = CipherUtilities.GetCipher(algo);
  644. c.Init(false, key);
  645. return c.DoFinal(cipher);
  646. }
  647. public const string SM4_ECB_NOPADDING = "SM4/ECB/NoPadding";
  648. public const string SM4_CBC_NOPADDING = "SM4/CBC/NoPadding";
  649. public const string SM4_CBC_PKCS7PADDING = "SM4/CBC/PKCS7Padding";
  650. /**
  651. * cfca官网CSP沙箱导出的sm2文件
  652. * @param pem 二进制原文
  653. * @param pwd 密码
  654. * @return
  655. */
  656. public static Sm2Cert ReadSm2File(byte[] pem, string pwd)
  657. {
  658. Sm2Cert sm2Cert = new();
  659. Asn1Sequence asn1Sequence = (Asn1Sequence)Asn1Object.FromByteArray(pem);
  660. // ASN1Integer asn1Integer = (ASN1Integer) asn1Sequence.getObjectAt(0); //version=1
  661. Asn1Sequence priSeq = (Asn1Sequence)asn1Sequence[1];//private key
  662. Asn1Sequence pubSeq = (Asn1Sequence)asn1Sequence[2];//public key and x509 cert
  663. // ASN1ObjectIdentifier sm2DataOid = (ASN1ObjectIdentifier) priSeq.getObjectAt(0);
  664. // ASN1ObjectIdentifier sm4AlgOid = (ASN1ObjectIdentifier) priSeq.getObjectAt(1);
  665. Asn1OctetString priKeyAsn1 = (Asn1OctetString)priSeq[2];
  666. byte[] key = KDF(System.Text.Encoding.UTF8.GetBytes(pwd), 32);
  667. byte[] priKeyD = Sm4DecryptCBC(Arrays.CopyOfRange(key, 16, 32),
  668. priKeyAsn1.GetOctets(),
  669. Arrays.CopyOfRange(key, 0, 16), SM4_CBC_PKCS7PADDING);
  670. sm2Cert.privateKey = GetPrivatekeyFromD(new BigInteger(1, priKeyD));
  671. // log.Info(Hex.toHexString(priKeyD));
  672. // ASN1ObjectIdentifier sm2DataOidPub = (ASN1ObjectIdentifier) pubSeq.getObjectAt(0);
  673. Asn1OctetString pubKeyX509 = (Asn1OctetString)pubSeq[1];
  674. X509Certificate x509 = new X509CertificateParser().ReadCertificate(pubKeyX509.GetOctets());
  675. sm2Cert.publicKey = x509.GetPublicKey();
  676. sm2Cert.certId = x509.SerialNumber.ToString(10); //这里转10进制,有啥其他进制要求的自己改改
  677. return sm2Cert;
  678. }
  679. /**
  680. *
  681. * @param cert
  682. * @return
  683. */
  684. public static Sm2Cert ReadSm2X509Cert(byte[] cert)
  685. {
  686. Sm2Cert sm2Cert = new();
  687. X509Certificate x509 = new X509CertificateParser().ReadCertificate(cert);
  688. sm2Cert.publicKey = x509.GetPublicKey();
  689. sm2Cert.certId = x509.SerialNumber.ToString(10); //这里转10进制,有啥其他进制要求的自己改改
  690. return sm2Cert;
  691. }
  692. public static byte[] ZeroIv(string algo)
  693. {
  694. IBufferedCipher cipher = CipherUtilities.GetCipher(algo);
  695. int blockSize = cipher.GetBlockSize();
  696. byte[] iv = new byte[blockSize];
  697. Arrays.Fill(iv, (byte)0);
  698. return iv;
  699. }
  700. }
  701. /// <summary>
  702. /// GM工具类
  703. /// </summary>
  704. public class GMUtil
  705. {
  706. /// <summary>
  707. /// SM2加密
  708. /// </summary>
  709. /// <param name="publicKeyHex"></param>
  710. /// <param name="data_string"></param>
  711. /// <returns></returns>
  712. public static string SM2Encrypt(string publicKeyHex, string data_string)
  713. {
  714. // 如果是130位公钥,.NET使用的话,把开头的04截取掉
  715. if (publicKeyHex.Length == 130)
  716. {
  717. publicKeyHex = publicKeyHex.Substring(2, 128);
  718. }
  719. // 公钥X,前64位
  720. string x = publicKeyHex.Substring(0, 64);
  721. // 公钥Y,后64位
  722. string y = publicKeyHex.Substring(64);
  723. // 获取公钥对象
  724. AsymmetricKeyParameter publicKey1 = GM.GetPublickeyFromXY(new BigInteger(x, 16), new BigInteger(y, 16));
  725. // Sm2Encrypt: C1C3C2
  726. // Sm2EncryptOld: C1C2C3
  727. byte[] digestByte = GM.Sm2Encrypt(Encoding.UTF8.GetBytes(data_string), publicKey1);
  728. string strSM2 = Hex.ToHexString(digestByte);
  729. return strSM2;
  730. }
  731. /// <summary>
  732. /// SM2解密
  733. /// </summary>
  734. /// <param name="privateKey_string"></param>
  735. /// <param name="encryptedData_string"></param>
  736. /// <returns></returns>
  737. public static string SM2Decrypt(string privateKey_string, string encryptedData_string)
  738. {
  739. if (!encryptedData_string.StartsWith("04"))
  740. encryptedData_string = "04" + encryptedData_string;
  741. BigInteger d = new(privateKey_string, 16);
  742. // 先拿到私钥对象,用ECPrivateKeyParameters 或 AsymmetricKeyParameter 都可以
  743. // ECPrivateKeyParameters bcecPrivateKey = GmUtil.GetPrivatekeyFromD(d);
  744. AsymmetricKeyParameter bcecPrivateKey = GM.GetPrivatekeyFromD(d);
  745. byte[] byToDecrypt = Hex.Decode(encryptedData_string);
  746. byte[] byDecrypted = GM.Sm2Decrypt(byToDecrypt, bcecPrivateKey);
  747. string strDecrypted = Encoding.UTF8.GetString(byDecrypted);
  748. return strDecrypted;
  749. }
  750. /// <summary>
  751. /// SM4加密(ECB)
  752. /// </summary>
  753. /// <param name="key_string"></param>
  754. /// <param name="plainText"></param>
  755. /// <returns></returns>
  756. public static string SM4EncryptECB(string key_string, string plainText)
  757. {
  758. byte[] key = Hex.Decode(key_string);
  759. byte[] bs = GM.Sm4EncryptECB(key, Encoding.UTF8.GetBytes(plainText), GM.SM4_CBC_PKCS7PADDING);//NoPadding 的情况下需要校验数据长度是16的倍数. 使用 HandleSm4Padding 处理
  760. return Hex.ToHexString(bs);
  761. }
  762. /// <summary>
  763. /// SM4解密(ECB)
  764. /// </summary>
  765. /// <param name="key_string"></param>
  766. /// <param name="cipherText"></param>
  767. /// <returns></returns>
  768. public static string SM4DecryptECB(string key_string, string cipherText)
  769. {
  770. byte[] key = Hex.Decode(key_string);
  771. byte[] bs = GM.Sm4DecryptECB(key, Hex.Decode(cipherText), GM.SM4_CBC_PKCS7PADDING);
  772. return Encoding.UTF8.GetString(bs);
  773. }
  774. /// <summary>
  775. /// SM4加密(CBC)
  776. /// </summary>
  777. /// <param name="key_string"></param>
  778. /// <param name="iv_string"></param>
  779. /// <param name="plainText"></param>
  780. /// <returns></returns>
  781. public static string SM4EncryptCBC(string key_string, string iv_string, string plainText)
  782. {
  783. byte[] key = Hex.Decode(key_string);
  784. byte[] iv = Hex.Decode(iv_string);
  785. byte[] bs = GM.Sm4EncryptCBC(key, Encoding.UTF8.GetBytes(plainText), iv, GM.SM4_CBC_PKCS7PADDING);
  786. return Hex.ToHexString(bs);
  787. }
  788. /// <summary>
  789. /// SM4解密(CBC)
  790. /// </summary>
  791. /// <param name="key_string"></param>
  792. /// <param name="iv_string"></param>
  793. /// <param name="cipherText"></param>
  794. /// <returns></returns>
  795. public static string SM4DecryptCBC(string key_string, string iv_string, string cipherText)
  796. {
  797. byte[] key = Hex.Decode(key_string);
  798. byte[] iv = Hex.Decode(iv_string);
  799. byte[] bs = GM.Sm4DecryptCBC(key, Hex.Decode(cipherText), iv, GM.SM4_CBC_PKCS7PADDING);
  800. return Encoding.UTF8.GetString(bs);
  801. }
  802. /// <summary>
  803. /// 补足 16 进制字符串的 0 字符,返回不带 0x 的16进制字符串
  804. /// </summary>
  805. /// <param name="input"></param>
  806. /// <param name="mode">1表示加密,0表示解密</param>
  807. /// <returns></returns>
  808. private static byte[] HandleSm4Padding(byte[] input, int mode)
  809. {
  810. if (input == null)
  811. {
  812. return null;
  813. }
  814. byte[] ret = (byte[])null;
  815. if (mode == 1)
  816. {
  817. int p = 16 - input.Length % 16;
  818. ret = new byte[input.Length + p];
  819. Array.Copy(input, 0, ret, 0, input.Length);
  820. for (int i = 0; i < p; i++)
  821. {
  822. ret[input.Length + i] = (byte)p;
  823. }
  824. }
  825. else
  826. {
  827. int p = input[input.Length - 1];
  828. ret = new byte[input.Length - p];
  829. Array.Copy(input, 0, ret, 0, input.Length - p);
  830. }
  831. return ret;
  832. }
  833. }