经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Java » 查看文章
C#.NET 国密SM2 加密解密 与JAVA互通 ver:20230805
来源:cnblogs  作者:runliuv  时间:2023/8/7 9:15:39  对本文有异议

C#.NET 国密SM2 加密解密 与JAVA互通 ver:20230805

 

.NET 环境:.NET6 控制台程序(.net core)。

JAVA 环境:JAVA8,带maven 的JAVA控制台程序。

 

简要解析:
1.最好要到对方源码(DEMO+JAR包也可以),可以用IDEA反编译(Ctrl+鼠标左键),看它过程逻辑和加密结果格式。

2.加密结果顺序:早期是 C1C2C3,后期是C1C3C2 ,双方得约定好。

3.加密结果:BASE64字符串或16进制字符串 ,双方得约定好。

4. .NET BC库SM2加密结果会带04,如果JAVA 那边报 Invalid point encoding 错误,删除加密结果前的04。如果对方要的是BASE64的加密结果,我们可以先转16进制字符串,裁掉04,再转BASE64。
string newCipherText = Hex.ToHexString(bysm2keyEncrypted);
if (newCipherText.StartsWith("04"))
{
newCipherText = newCipherText.Substring(2);
}

5. .NET BC库解密,密文前要加 “04”,否则会报 Invalid point encoding XX 。如果加密结果是BASE64的,先把BASE64转16进制字符串,再判断是否04开头。
如果JAVA源码,固定截取的头2位,那么就不用判断是否04开头了,直接写死:javaSM2 = "04" + javaSM2;

 

生成一组国密公私钥:

私钥:FAB8BBE670FAE338C9E9382B9FB6485225C11A3ECB84C938F10F20A93B6215F0

公钥:049EF573019D9A03B16B0BE44FC8A5B4E8E098F56034C97B312282DD0B4810AFC3CC759673ED0FC9B9DC7E6FA38F0E2B121E02654BF37EA6B63FAF2A0D6013EADF

 本例是:C1C3C2。

//GmUtil.Sm2Encrypt 对应 C1C3C2
// GmUtil.Sm2EncryptOld :C1C2C3

 

.NET 代码:

GmUtil 工具类,需要nuget下载 Portable.BouncyCastle 1.9.0 版本:

  1. using Org.BouncyCastle.Asn1;
  2. using Org.BouncyCastle.Asn1.GM;
  3. using Org.BouncyCastle.Asn1.X9;
  4. using Org.BouncyCastle.Crypto;
  5. using Org.BouncyCastle.Crypto.Digests;
  6. using Org.BouncyCastle.Crypto.Engines;
  7. using Org.BouncyCastle.Crypto.Generators;
  8. using Org.BouncyCastle.Crypto.Parameters;
  9. using Org.BouncyCastle.Math;
  10. using Org.BouncyCastle.Security;
  11. using Org.BouncyCastle.Utilities;
  12. using Org.BouncyCastle.Utilities.Encoders;
  13. using Org.BouncyCastle.X509;
  14. using System;
  15. using System.Collections.Generic;
  16. using System.IO;
  17. namespace CommonUtils
  18. {
  19. /**
  20. * need lib:
  21. * BouncyCastle.Crypto.dll(http://www.bouncycastle.org/csharp/index.html
  22. * 用BC的注意点:
  23. * 这个版本的BC对SM3withSM2的结果为asn1格式的r和s,如果需要直接拼接的r||s需要自己转换。下面rsAsn1ToPlainByteArray、rsPlainByteArrayToAsn1就在干这事。
  24. * 这个版本的BC对SM2的结果为C1||C2||C3,据说为旧标准,新标准为C1||C3||C2,用新标准的需要自己转换。下面(被注释掉的)changeC1C2C3ToC1C3C2、changeC1C3C2ToC1C2C3就在干这事。java版的高版本有加上C1C3C2,csharp版没准以后也会加,但目前还没有,java版的目前可以初始化时“ SM2Engine sm2Engine = new SM2Engine(SM2Engine.Mode.C1C3C2);”。
  25. *
  26. * 按要求国密算法仅允许使用加密机,本demo国密算法仅供学习使用,请不要用于生产用途。
  27. */
  28. public class GmUtil
  29. {
  30. //private static readonly ILog log = LogManager.GetLogger(typeof(GmUtil));
  31.  
  32. private static X9ECParameters x9ECParameters = GMNamedCurves.GetByName("sm2p256v1");
  33. private static ECDomainParameters ecDomainParameters = new ECDomainParameters(x9ECParameters.Curve, x9ECParameters.G, x9ECParameters.N);
  34. /**
  35. *
  36. * @param msg
  37. * @param userId
  38. * @param privateKey
  39. * @return r||s,直接拼接byte数组的rs
  40. */
  41. public static byte[] SignSm3WithSm2(byte[] msg, byte[] userId, AsymmetricKeyParameter privateKey)
  42. {
  43. return RsAsn1ToPlainByteArray(SignSm3WithSm2Asn1Rs(msg, userId, privateKey));
  44. }
  45. /**
  46. * @param msg
  47. * @param userId
  48. * @param privateKey
  49. * @return rs in <b>asn1 format</b>
  50. */
  51. public static byte[] SignSm3WithSm2Asn1Rs(byte[] msg, byte[] userId, AsymmetricKeyParameter privateKey)
  52. {
  53. try
  54. {
  55. ISigner signer = SignerUtilities.GetSigner("SM3withSM2");
  56. signer.Init(true, new ParametersWithID(privateKey, userId));
  57. signer.BlockUpdate(msg, 0, msg.Length);
  58. byte[] sig = signer.GenerateSignature();
  59. return sig;
  60. }
  61. catch (Exception e)
  62. {
  63. //log.Error("SignSm3WithSm2Asn1Rs error: " + e.Message, e);
  64. return null;
  65. }
  66. }
  67. /**
  68. *
  69. * @param msg
  70. * @param userId
  71. * @param rs r||s,直接拼接byte数组的rs
  72. * @param publicKey
  73. * @return
  74. */
  75. public static bool VerifySm3WithSm2(byte[] msg, byte[] userId, byte[] rs, AsymmetricKeyParameter publicKey)
  76. {
  77. if (rs == null || msg == null || userId == null) return false;
  78. if (rs.Length != RS_LEN * 2) return false;
  79. return VerifySm3WithSm2Asn1Rs(msg, userId, RsPlainByteArrayToAsn1(rs), publicKey);
  80. }
  81. /**
  82. *
  83. * @param msg
  84. * @param userId
  85. * @param rs in <b>asn1 format</b>
  86. * @param publicKey
  87. * @return
  88. */
  89.  
  90. public static bool VerifySm3WithSm2Asn1Rs(byte[] msg, byte[] userId, byte[] sign, AsymmetricKeyParameter publicKey)
  91. {
  92. try
  93. {
  94. ISigner signer = SignerUtilities.GetSigner("SM3withSM2");
  95. signer.Init(false, new ParametersWithID(publicKey, userId));
  96. signer.BlockUpdate(msg, 0, msg.Length);
  97. return signer.VerifySignature(sign);
  98. }
  99. catch (Exception e)
  100. {
  101. //log.Error("VerifySm3WithSm2Asn1Rs error: " + e.Message, e);
  102. return false;
  103. }
  104. }
  105. /**
  106. * bc加解密使用旧标c1||c2||c3,此方法在加密后调用,将结果转化为c1||c3||c2
  107. * @param c1c2c3
  108. * @return
  109. */
  110. private static byte[] ChangeC1C2C3ToC1C3C2(byte[] c1c2c3)
  111. {
  112. int c1Len = (x9ECParameters.Curve.FieldSize + 7) / 8 * 2 + 1; //sm2p256v1的这个固定65。可看GMNamedCurves、ECCurve代码。
  113. const int c3Len = 32; //new SM3Digest().getDigestSize();
  114. byte[] result = new byte[c1c2c3.Length];
  115. Buffer.BlockCopy(c1c2c3, 0, result, 0, c1Len); //c1
  116. Buffer.BlockCopy(c1c2c3, c1c2c3.Length - c3Len, result, c1Len, c3Len); //c3
  117. Buffer.BlockCopy(c1c2c3, c1Len, result, c1Len + c3Len, c1c2c3.Length - c1Len - c3Len); //c2
  118. return result;
  119. }
  120. /**
  121. * bc加解密使用旧标c1||c3||c2,此方法在解密前调用,将密文转化为c1||c2||c3再去解密
  122. * @param c1c3c2
  123. * @return
  124. */
  125. private static byte[] ChangeC1C3C2ToC1C2C3(byte[] c1c3c2)
  126. {
  127. int c1Len = (x9ECParameters.Curve.FieldSize + 7) / 8 * 2 + 1; //sm2p256v1的这个固定65。可看GMNamedCurves、ECCurve代码。
  128. const int c3Len = 32; //new SM3Digest().GetDigestSize();
  129. byte[] result = new byte[c1c3c2.Length];
  130. Buffer.BlockCopy(c1c3c2, 0, result, 0, c1Len); //c1: 0->65
  131. Buffer.BlockCopy(c1c3c2, c1Len + c3Len, result, c1Len, c1c3c2.Length - c1Len - c3Len); //c2
  132. Buffer.BlockCopy(c1c3c2, c1Len, result, c1c3c2.Length - c3Len, c3Len); //c3
  133. return result;
  134. }
  135. /**
  136. * c1||c3||c2
  137. * @param data
  138. * @param key
  139. * @return
  140. */
  141. public static byte[] Sm2Decrypt(byte[] data, AsymmetricKeyParameter key)
  142. {
  143. return Sm2DecryptOld(ChangeC1C3C2ToC1C2C3(data), key);
  144. }
  145. /**
  146. * c1||c3||c2
  147. * @param data
  148. * @param key
  149. * @return
  150. */
  151.  
  152. public static byte[] Sm2Encrypt(byte[] data, AsymmetricKeyParameter key)
  153. {
  154. return ChangeC1C2C3ToC1C3C2(Sm2EncryptOld(data, key));
  155. }
  156. /**
  157. * c1||c2||c3
  158. * @param data
  159. * @param key
  160. * @return
  161. */
  162. public static byte[] Sm2EncryptOld(byte[] data, AsymmetricKeyParameter pubkey)
  163. {
  164. try
  165. {
  166. SM2Engine sm2Engine = new SM2Engine();
  167. sm2Engine.Init(true, new ParametersWithRandom(pubkey, new SecureRandom()));
  168. return sm2Engine.ProcessBlock(data, 0, data.Length);
  169. }
  170. catch (Exception e)
  171. {
  172. //log.Error("Sm2EncryptOld error: " + e.Message, e);
  173. return null;
  174. }
  175. }
  176. /**
  177. * c1||c2||c3
  178. * @param data
  179. * @param key
  180. * @return
  181. */
  182. public static byte[] Sm2DecryptOld(byte[] data, AsymmetricKeyParameter key)
  183. {
  184. try
  185. {
  186. SM2Engine sm2Engine = new SM2Engine();
  187. sm2Engine.Init(false, key);
  188. return sm2Engine.ProcessBlock(data, 0, data.Length);
  189. }
  190. catch (Exception e)
  191. {
  192. //log.Error("Sm2DecryptOld error: " + e.Message, e);
  193. return null;
  194. }
  195. }
  196. /**
  197. * @param bytes
  198. * @return
  199. */
  200. public static byte[] Sm3(byte[] bytes)
  201. {
  202. try
  203. {
  204. SM3Digest digest = new SM3Digest();
  205. digest.BlockUpdate(bytes, 0, bytes.Length);
  206. byte[] result = DigestUtilities.DoFinal(digest);
  207. return result;
  208. }
  209. catch (Exception e)
  210. {
  211. //log.Error("Sm3 error: " + e.Message, e);
  212. return null;
  213. }
  214. }
  215. private const int RS_LEN = 32;
  216. private static byte[] BigIntToFixexLengthBytes(BigInteger rOrS)
  217. {
  218. // for sm2p256v1, n is 00fffffffeffffffffffffffffffffffff7203df6b21c6052b53bbf40939d54123,
  219. // r and s are the result of mod n, so they should be less than n and have length<=32
  220. byte[] rs = rOrS.ToByteArray();
  221. if (rs.Length == RS_LEN) return rs;
  222. else if (rs.Length == RS_LEN + 1 && rs[0] == 0) return Arrays.CopyOfRange(rs, 1, RS_LEN + 1);
  223. else if (rs.Length < RS_LEN)
  224. {
  225. byte[] result = new byte[RS_LEN];
  226. Arrays.Fill(result, (byte)0);
  227. Buffer.BlockCopy(rs, 0, result, RS_LEN - rs.Length, rs.Length);
  228. return result;
  229. }
  230. else
  231. {
  232. throw new ArgumentException("err rs: " + Hex.ToHexString(rs));
  233. }
  234. }
  235. /**
  236. * BC的SM3withSM2签名得到的结果的rs是asn1格式的,这个方法转化成直接拼接r||s
  237. * @param rsDer rs in asn1 format
  238. * @return sign result in plain byte array
  239. */
  240. private static byte[] RsAsn1ToPlainByteArray(byte[] rsDer)
  241. {
  242. Asn1Sequence seq = Asn1Sequence.GetInstance(rsDer);
  243. byte[] r = BigIntToFixexLengthBytes(DerInteger.GetInstance(seq[0]).Value);
  244. byte[] s = BigIntToFixexLengthBytes(DerInteger.GetInstance(seq[1]).Value);
  245. byte[] result = new byte[RS_LEN * 2];
  246. Buffer.BlockCopy(r, 0, result, 0, r.Length);
  247. Buffer.BlockCopy(s, 0, result, RS_LEN, s.Length);
  248. return result;
  249. }
  250. /**
  251. * BC的SM3withSM2验签需要的rs是asn1格式的,这个方法将直接拼接r||s的字节数组转化成asn1格式
  252. * @param sign in plain byte array
  253. * @return rs result in asn1 format
  254. */
  255. private static byte[] RsPlainByteArrayToAsn1(byte[] sign)
  256. {
  257. if (sign.Length != RS_LEN * 2) throw new ArgumentException("err rs. ");
  258. BigInteger r = new BigInteger(1, Arrays.CopyOfRange(sign, 0, RS_LEN));
  259. BigInteger s = new BigInteger(1, Arrays.CopyOfRange(sign, RS_LEN, RS_LEN * 2));
  260. Asn1EncodableVector v = new Asn1EncodableVector();
  261. v.Add(new DerInteger(r));
  262. v.Add(new DerInteger(s));
  263. try
  264. {
  265. return new DerSequence(v).GetEncoded("DER");
  266. }
  267. catch (IOException e)
  268. {
  269. //log.Error("RsPlainByteArrayToAsn1 error: " + e.Message, e);
  270. return null;
  271. }
  272. }
  273. public static AsymmetricCipherKeyPair GenerateKeyPair()
  274. {
  275. try
  276. {
  277. ECKeyPairGenerator kpGen = new ECKeyPairGenerator();
  278. kpGen.Init(new ECKeyGenerationParameters(ecDomainParameters, new SecureRandom()));
  279. return kpGen.GenerateKeyPair();
  280. }
  281. catch (Exception e)
  282. {
  283. //log.Error("generateKeyPair error: " + e.Message, e);
  284. return null;
  285. }
  286. }
  287. public static ECPrivateKeyParameters GetPrivatekeyFromD(BigInteger d)
  288. {
  289. return new ECPrivateKeyParameters(d, ecDomainParameters);
  290. }
  291. public static ECPublicKeyParameters GetPublickeyFromXY(BigInteger x, BigInteger y)
  292. {
  293. return new ECPublicKeyParameters(x9ECParameters.Curve.CreatePoint(x, y), ecDomainParameters);
  294. }
  295. public static AsymmetricKeyParameter GetPublickeyFromX509File(FileInfo file)
  296. {
  297. FileStream fileStream = null;
  298. try
  299. {
  300. //file.DirectoryName + "\\" + file.Name
  301. fileStream = new FileStream(file.FullName, FileMode.Open, FileAccess.Read);
  302. X509Certificate certificate = new X509CertificateParser().ReadCertificate(fileStream);
  303. return certificate.GetPublicKey();
  304. }
  305. catch (Exception e)
  306. {
  307. //log.Error(file.Name + "读取失败,异常:" + e);
  308. }
  309. finally
  310. {
  311. if (fileStream != null)
  312. fileStream.Close();
  313. }
  314. return null;
  315. }
  316. public class Sm2Cert
  317. {
  318. public AsymmetricKeyParameter privateKey;
  319. public AsymmetricKeyParameter publicKey;
  320. public String certId;
  321. }
  322. private static byte[] ToByteArray(int i)
  323. {
  324. byte[] byteArray = new byte[4];
  325. byteArray[0] = (byte)(i >> 24);
  326. byteArray[1] = (byte)((i & 0xFFFFFF) >> 16);
  327. byteArray[2] = (byte)((i & 0xFFFF) >> 8);
  328. byteArray[3] = (byte)(i & 0xFF);
  329. return byteArray;
  330. }
  331. /**
  332. * 字节数组拼接
  333. *
  334. * @param params
  335. * @return
  336. */
  337. private static byte[] Join(params byte[][] byteArrays)
  338. {
  339. List<byte> byteSource = new List<byte>();
  340. for (int i = 0; i < byteArrays.Length; i++)
  341. {
  342. byteSource.AddRange(byteArrays[i]);
  343. }
  344. byte[] data = byteSource.ToArray();
  345. return data;
  346. }
  347. /**
  348. * 密钥派生函数
  349. *
  350. * @param Z
  351. * @param klen
  352. * 生成klen字节数长度的密钥
  353. * @return
  354. */
  355. private static byte[] KDF(byte[] Z, int klen)
  356. {
  357. int ct = 1;
  358. int end = (int)Math.Ceiling(klen * 1.0 / 32);
  359. List<byte> byteSource = new List<byte>();
  360. try
  361. {
  362. for (int i = 1; i < end; i++)
  363. {
  364. byteSource.AddRange(GmUtil.Sm3(Join(Z, ToByteArray(ct))));
  365. ct++;
  366. }
  367. byte[] last = GmUtil.Sm3(Join(Z, ToByteArray(ct)));
  368. if (klen % 32 == 0)
  369. {
  370. byteSource.AddRange(last);
  371. }
  372. else
  373. byteSource.AddRange(Arrays.CopyOfRange(last, 0, klen % 32));
  374. return byteSource.ToArray();
  375. }
  376. catch (Exception e)
  377. {
  378. //log.Error("KDF error: " + e.Message, e);
  379. }
  380. return null;
  381. }
  382. public static byte[] Sm4DecryptCBC(byte[] keyBytes, byte[] cipher, byte[] iv, String algo)
  383. {
  384. if (keyBytes.Length != 16) throw new ArgumentException("err key length");
  385. if (cipher.Length % 16 != 0 && algo.Contains("NoPadding")) throw new ArgumentException("err data length");
  386. try
  387. {
  388. KeyParameter key = ParameterUtilities.CreateKeyParameter("SM4", keyBytes);
  389. IBufferedCipher c = CipherUtilities.GetCipher(algo);
  390. if (iv == null) iv = ZeroIv(algo);
  391. c.Init(false, new ParametersWithIV(key, iv));
  392. return c.DoFinal(cipher);
  393. }
  394. catch (Exception e)
  395. {
  396. //log.Error("Sm4DecryptCBC error: " + e.Message, e);
  397. return null;
  398. }
  399. }
  400. public static byte[] Sm4EncryptCBC(byte[] keyBytes, byte[] plain, byte[] iv, String algo)
  401. {
  402. if (keyBytes.Length != 16) throw new ArgumentException("err key length");
  403. if (plain.Length % 16 != 0 && algo.Contains("NoPadding")) throw new ArgumentException("err data length");
  404. try
  405. {
  406. KeyParameter key = ParameterUtilities.CreateKeyParameter("SM4", keyBytes);
  407. IBufferedCipher c = CipherUtilities.GetCipher(algo);
  408. if (iv == null) iv = ZeroIv(algo);
  409. c.Init(true, new ParametersWithIV(key, iv));
  410. return c.DoFinal(plain);
  411. }
  412. catch (Exception e)
  413. {
  414. //log.Error("Sm4EncryptCBC error: " + e.Message, e);
  415. return null;
  416. }
  417. }
  418. public static byte[] Sm4EncryptECB(byte[] keyBytes, byte[] plain, string algo)
  419. {
  420. if (keyBytes.Length != 16) throw new ArgumentException("err key length");
  421. //NoPadding 的情况下需要校验数据长度是16的倍数.
  422. if (plain.Length % 16 != 0 && algo.Contains("NoPadding")) throw new ArgumentException("err data length");
  423. try
  424. {
  425. KeyParameter key = ParameterUtilities.CreateKeyParameter("SM4", keyBytes);
  426. IBufferedCipher c = CipherUtilities.GetCipher(algo);
  427. c.Init(true, key);
  428. return c.DoFinal(plain);
  429. }
  430. catch (Exception e)
  431. {
  432. //log.Error("Sm4EncryptECB error: " + e.Message, e);
  433. return null;
  434. }
  435. }
  436. public static byte[] Sm4DecryptECB(byte[] keyBytes, byte[] cipher, string algo)
  437. {
  438. if (keyBytes.Length != 16) throw new ArgumentException("err key length");
  439. if (cipher.Length % 16 != 0 && algo.Contains("NoPadding")) throw new ArgumentException("err data length");
  440. try
  441. {
  442. KeyParameter key = ParameterUtilities.CreateKeyParameter("SM4", keyBytes);
  443. IBufferedCipher c = CipherUtilities.GetCipher(algo);
  444. c.Init(false, key);
  445. return c.DoFinal(cipher);
  446. }
  447. catch (Exception e)
  448. {
  449. //log.Error("Sm4DecryptECB error: " + e.Message, e);
  450. return null;
  451. }
  452. }
  453. public const String SM4_ECB_NOPADDING = "SM4/ECB/NoPadding";
  454. public const String SM4_CBC_NOPADDING = "SM4/CBC/NoPadding";
  455. public const String SM4_CBC_PKCS7PADDING = "SM4/CBC/PKCS7Padding";
  456. /**
  457. * cfca官网CSP沙箱导出的sm2文件
  458. * @param pem 二进制原文
  459. * @param pwd 密码
  460. * @return
  461. */
  462. public static Sm2Cert readSm2File(byte[] pem, String pwd)
  463. {
  464. Sm2Cert sm2Cert = new Sm2Cert();
  465. try
  466. {
  467. Asn1Sequence asn1Sequence = (Asn1Sequence)Asn1Object.FromByteArray(pem);
  468. // ASN1Integer asn1Integer = (ASN1Integer) asn1Sequence.getObjectAt(0); //version=1
  469. Asn1Sequence priSeq = (Asn1Sequence)asn1Sequence[1];//private key
  470. Asn1Sequence pubSeq = (Asn1Sequence)asn1Sequence[2];//public key and x509 cert
  471. // ASN1ObjectIdentifier sm2DataOid = (ASN1ObjectIdentifier) priSeq.getObjectAt(0);
  472. // ASN1ObjectIdentifier sm4AlgOid = (ASN1ObjectIdentifier) priSeq.getObjectAt(1);
  473. Asn1OctetString priKeyAsn1 = (Asn1OctetString)priSeq[2];
  474. byte[] key = KDF(System.Text.Encoding.UTF8.GetBytes(pwd), 32);
  475. byte[] priKeyD = Sm4DecryptCBC(Arrays.CopyOfRange(key, 16, 32),
  476. priKeyAsn1.GetOctets(),
  477. Arrays.CopyOfRange(key, 0, 16), SM4_CBC_PKCS7PADDING);
  478. sm2Cert.privateKey = GetPrivatekeyFromD(new BigInteger(1, priKeyD));
  479. // log.Info(Hex.toHexString(priKeyD));
  480. // ASN1ObjectIdentifier sm2DataOidPub = (ASN1ObjectIdentifier) pubSeq.getObjectAt(0);
  481. Asn1OctetString pubKeyX509 = (Asn1OctetString)pubSeq[1];
  482. X509Certificate x509 = (X509Certificate)new X509CertificateParser().ReadCertificate(pubKeyX509.GetOctets());
  483. sm2Cert.publicKey = x509.GetPublicKey();
  484. sm2Cert.certId = x509.SerialNumber.ToString(10); //这里转10进账,有啥其他进制要求的自己改改
  485. return sm2Cert;
  486. }
  487. catch (Exception e)
  488. {
  489. //log.Error("readSm2File error: " + e.Message, e);
  490. return null;
  491. }
  492. }
  493. /**
  494. *
  495. * @param cert
  496. * @return
  497. */
  498. public static Sm2Cert ReadSm2X509Cert(byte[] cert)
  499. {
  500. Sm2Cert sm2Cert = new Sm2Cert();
  501. try
  502. {
  503. X509Certificate x509 = new X509CertificateParser().ReadCertificate(cert);
  504. sm2Cert.publicKey = x509.GetPublicKey();
  505. sm2Cert.certId = x509.SerialNumber.ToString(10); //这里转10进账,有啥其他进制要求的自己改改
  506. return sm2Cert;
  507. }
  508. catch (Exception e)
  509. {
  510. //log.Error("ReadSm2X509Cert error: " + e.Message, e);
  511. return null;
  512. }
  513. }
  514. public static byte[] ZeroIv(String algo)
  515. {
  516. try
  517. {
  518. IBufferedCipher cipher = CipherUtilities.GetCipher(algo);
  519. int blockSize = cipher.GetBlockSize();
  520. byte[] iv = new byte[blockSize];
  521. Arrays.Fill(iv, (byte)0);
  522. return iv;
  523. }
  524. catch (Exception e)
  525. {
  526. //log.Error("ZeroIv error: " + e.Message, e);
  527. return null;
  528. }
  529. }
  530. public static void Main2(string[] s)
  531. {
  532. // 随便看看
  533. //log.Info("GMNamedCurves: ");
  534. foreach (string e in GMNamedCurves.Names)
  535. {
  536. //log.Info(e);
  537. }
  538. //log.Info("sm2p256v1 n:" + x9ECParameters.N);
  539. //log.Info("sm2p256v1 nHex:" + Hex.ToHexString(x9ECParameters.N.ToByteArray()));
  540. // 生成公私钥对 ---------------------
  541. AsymmetricCipherKeyPair kp = GmUtil.GenerateKeyPair();
  542. //log.Info("private key d: " + ((ECPrivateKeyParameters)kp.Private).D);
  543. //log.Info("public key q:" + ((ECPublicKeyParameters)kp.Public).Q); //{x, y, zs...}
  544. //签名验签
  545. byte[] msg = System.Text.Encoding.UTF8.GetBytes("message digest");
  546. byte[] userId = System.Text.Encoding.UTF8.GetBytes("userId");
  547. byte[] sig = SignSm3WithSm2(msg, userId, kp.Private);
  548. //log.Info("testSignSm3WithSm2: " + Hex.ToHexString(sig));
  549. //log.Info("testVerifySm3WithSm2: " + VerifySm3WithSm2(msg, userId, sig, kp.Public));
  550. // 由d生成私钥 ---------------------
  551. BigInteger d = new BigInteger("097b5230ef27c7df0fa768289d13ad4e8a96266f0fcb8de40d5942af4293a54a", 16);
  552. ECPrivateKeyParameters bcecPrivateKey = GetPrivatekeyFromD(d);
  553. //log.Info("testGetFromD: " + bcecPrivateKey.D.ToString(16));
  554. //公钥X坐标PublicKeyXHex: 59cf9940ea0809a97b1cbffbb3e9d96d0fe842c1335418280bfc51dd4e08a5d4
  555. //公钥Y坐标PublicKeyYHex: 9a7f77c578644050e09a9adc4245d1e6eba97554bc8ffd4fe15a78f37f891ff8
  556. AsymmetricKeyParameter publicKey = GetPublickeyFromX509File(new FileInfo("d:/certs/69629141652.cer"));
  557. //log.Info(publicKey);
  558. AsymmetricKeyParameter publicKey1 = GetPublickeyFromXY(new BigInteger("59cf9940ea0809a97b1cbffbb3e9d96d0fe842c1335418280bfc51dd4e08a5d4", 16), new BigInteger("9a7f77c578644050e09a9adc4245d1e6eba97554bc8ffd4fe15a78f37f891ff8", 16));
  559. //log.Info("testReadFromX509File: " + ((ECPublicKeyParameters)publicKey).Q);
  560. //log.Info("testGetFromXY: " + ((ECPublicKeyParameters)publicKey1).Q);
  561. //log.Info("testPubKey: " + publicKey.Equals(publicKey1));
  562. //log.Info("testPubKey: " + ((ECPublicKeyParameters)publicKey).Q.Equals(((ECPublicKeyParameters)publicKey1).Q));
  563. // sm2 encrypt and decrypt test ---------------------
  564. AsymmetricCipherKeyPair kp2 = GenerateKeyPair();
  565. AsymmetricKeyParameter publicKey2 = kp2.Public;
  566. AsymmetricKeyParameter privateKey2 = kp2.Private;
  567. byte[] bs = Sm2Encrypt(System.Text.Encoding.UTF8.GetBytes("s"), publicKey2);
  568. //log.Info("testSm2Enc dec: " + Hex.ToHexString(bs));
  569. bs = Sm2Decrypt(bs, privateKey2);
  570. //log.Info("testSm2Enc dec: " + System.Text.Encoding.UTF8.GetString(bs));
  571. // sm4 encrypt and decrypt test ---------------------
  572. //0123456789abcdeffedcba9876543210 + 0123456789abcdeffedcba9876543210 -> 681edf34d206965e86b3e94f536e4246
  573. byte[] plain = Hex.Decode("0123456789abcdeffedcba98765432100123456789abcdeffedcba98765432100123456789abcdeffedcba9876543210");
  574. byte[] key = Hex.Decode("0123456789abcdeffedcba9876543210");
  575. byte[] cipher = Hex.Decode("595298c7c6fd271f0402f804c33d3f66");
  576. bs = Sm4EncryptECB(key, plain, GmUtil.SM4_ECB_NOPADDING);
  577. //log.Info("testSm4EncEcb: " + Hex.ToHexString(bs)); ;
  578. bs = Sm4DecryptECB(key, bs, GmUtil.SM4_ECB_NOPADDING);
  579. //log.Info("testSm4DecEcb: " + Hex.ToHexString(bs));
  580. //读.sm2文件
  581. String sm2 = "MIIDHQIBATBHBgoqgRzPVQYBBAIBBgcqgRzPVQFoBDDW5/I9kZhObxXE9Vh1CzHdZhIhxn+3byBU\nUrzmGRKbDRMgI3hJKdvpqWkM5G4LNcIwggLNBgoqgRzPVQYBBAIBBIICvTCCArkwggJdoAMCAQIC\nBRA2QSlgMAwGCCqBHM9VAYN1BQAwXDELMAkGA1UEBhMCQ04xMDAuBgNVBAoMJ0NoaW5hIEZpbmFu\nY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEbMBkGA1UEAwwSQ0ZDQSBURVNUIFNNMiBPQ0Ex\nMB4XDTE4MTEyNjEwMTQxNVoXDTIwMTEyNjEwMTQxNVowcjELMAkGA1UEBhMCY24xEjAQBgNVBAoM\nCUNGQ0EgT0NBMTEOMAwGA1UECwwFQ1VQUkExFDASBgNVBAsMC0VudGVycHJpc2VzMSkwJwYDVQQD\nDCAwNDFAWnRlc3RAMDAwMTAwMDA6U0lHTkAwMDAwMDAwMTBZMBMGByqGSM49AgEGCCqBHM9VAYIt\nA0IABDRNKhvnjaMUShsM4MJ330WhyOwpZEHoAGfqxFGX+rcL9x069dyrmiF3+2ezwSNh1/6YqfFZ\nX9koM9zE5RG4USmjgfMwgfAwHwYDVR0jBBgwFoAUa/4Y2o9COqa4bbMuiIM6NKLBMOEwSAYDVR0g\nBEEwPzA9BghggRyG7yoBATAxMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmNmY2EuY29tLmNuL3Vz\nL3VzLTE0Lmh0bTA4BgNVHR8EMTAvMC2gK6AphidodHRwOi8vdWNybC5jZmNhLmNvbS5jbi9TTTIv\nY3JsNDI4NS5jcmwwCwYDVR0PBAQDAgPoMB0GA1UdDgQWBBREhx9VlDdMIdIbhAxKnGhPx8FcHDAd\nBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwDAYIKoEcz1UBg3UFAANIADBFAiEAgWvQi3h6\niW4jgF4huuXfhWInJmTTYr2EIAdG8V4M8fYCIBixygdmfPL9szcK2pzCYmIb6CBzo5SMv50Odycc\nVfY6";
  582. bs = Convert.FromBase64String(sm2);
  583. String pwd = "cfca1234";
  584. GmUtil.Sm2Cert sm2Cert = GmUtil.readSm2File(bs, pwd);
  585. //log.Info("testReadSm2File, pubkey: " + ((ECPublicKeyParameters)sm2Cert.publicKey).Q.ToString());
  586. //log.Info("testReadSm2File, prikey: " + Hex.ToHexString(((ECPrivateKeyParameters)sm2Cert.privateKey).D.ToByteArray()));
  587. //log.Info("testReadSm2File, certId: " + sm2Cert.certId);
  588. bs = Sm2Encrypt(System.Text.Encoding.UTF8.GetBytes("s"), ((ECPublicKeyParameters)sm2Cert.publicKey));
  589. //log.Info("testSm2Enc dec: " + Hex.ToHexString(bs));
  590. bs = Sm2Decrypt(bs, ((ECPrivateKeyParameters)sm2Cert.privateKey));
  591. //log.Info("testSm2Enc dec: " + System.Text.Encoding.UTF8.GetString(bs));
  592. msg = System.Text.Encoding.UTF8.GetBytes("message digest");
  593. userId = System.Text.Encoding.UTF8.GetBytes("userId");
  594. sig = SignSm3WithSm2(msg, userId, ((ECPrivateKeyParameters)sm2Cert.privateKey));
  595. //log.Info("testSignSm3WithSm2: " + Hex.ToHexString(sig));
  596. //log.Info("testVerifySm3WithSm2: " + VerifySm3WithSm2(msg, userId, sig, ((ECPublicKeyParameters)sm2Cert.publicKey)));
  597. }
  598. }
  599. }

.NET使用:

  1. using CommonUtils;
  2. using Org.BouncyCastle.Crypto;
  3. using Org.BouncyCastle.Math;
  4. using Org.BouncyCastle.Utilities.Encoders;
  5. using System.Text;
  6. void TestSM2Enc()
  7. {
  8. String privateKeyHex = "FAB8BBE670FAE338C9E9382B9FB6485225C11A3ECB84C938F10F20A93B6215F0";
  9. //完整公钥128位“9EF573019D9A03B16B0BE44FC8A5B4E8E098F56034C97B312282DD0B4810AFC3CC759673ED0FC9B9DC7E6FA38F0E2B121E02654BF37EA6B63FAF2A0D6013EADF”
  10. //完整公钥130位,比128位开头多了04“049EF573019D9A03B16B0BE44FC8A5B4E8E098F56034C97B312282DD0B4810AFC3CC759673ED0FC9B9DC7E6FA38F0E2B121E02654BF37EA6B63FAF2A0D6013EADF”
  11. string pubKeyHex = "049EF573019D9A03B16B0BE44FC8A5B4E8E098F56034C97B312282DD0B4810AFC3CC759673ED0FC9B9DC7E6FA38F0E2B121E02654BF37EA6B63FAF2A0D6013EADF";
  12. //如果是130位公钥,.NET 使用的话,把开头的04截取掉。
  13. if (pubKeyHex.Length == 130)
  14. {
  15. pubKeyHex = pubKeyHex.Substring(2, 128);
  16. }
  17. //公钥X,前64位
  18. String x = pubKeyHex.Substring(0, 64);
  19. //公钥Y,后64位
  20. String y = pubKeyHex.Substring(64);
  21. //获取公钥对象
  22. AsymmetricKeyParameter publicKey1 = GmUtil.GetPublickeyFromXY(new BigInteger(x, 16), new BigInteger(y, 16));
  23. String content = "1234泰酷拉NET";
  24. Console.WriteLine("待处理字符串:" + content);
  25. //Sm2Encrypt 对应 C1C3C2
  26. // Sm2EncryptOld :C1C2C3
  27. byte[] digestByte = GmUtil.Sm2Encrypt(Encoding.UTF8.GetBytes(content), publicKey1);
  28. string strSM2 = Hex.ToHexString(digestByte);
  29. Console.WriteLine("SM2加密后:" + strSM2);
  30. // 4. .NET BC库SM2加密结果会带04,如果JAVA 那边报 Invalid point encoding 错误,删除加密结果前的04。如果对方要的是BASE64的加密结果,我们可以先转16进制字符串,裁掉04,再转BASE64。
  31. string newCipherText = Hex.ToHexString(digestByte);
  32. if (newCipherText.StartsWith("04"))
  33. {
  34. newCipherText = newCipherText.Substring(2);
  35. }
  36. Console.WriteLine("截取04后,加密结果:" + newCipherText);
  37. //.NET 自加自解
  38. BigInteger d = new BigInteger(privateKeyHex, 16);
  39. //先拿到私钥对象,用ECPrivateKeyParameters 或 AsymmetricKeyParameter 都可以
  40. //ECPrivateKeyParameters bcecPrivateKey = CommonUtils.GmUtil.GetPrivatekeyFromD(d);
  41. AsymmetricKeyParameter bcecPrivateKey = CommonUtils.GmUtil.GetPrivatekeyFromD(d);
  42. byte[] byToDecrypt = Hex.Decode(strSM2);
  43. byte[] byDecrypted = GmUtil.Sm2Decrypt(byToDecrypt, bcecPrivateKey);
  44. String strDecrypted = Encoding.UTF8.GetString(byDecrypted);
  45. Console.WriteLine("SM2解密后:" + strDecrypted);
  46. //JAVA 结果,.NET来解
  47. string javaSM2 = "04a7aaa9fd91aea6f99787ef431e19cb9feecc5bfb97fb445ce529c78c04676f1792e06b3a2814d1bda80bd3f63e530c149fc03911f1b81007dc86cef2c03f30c7fecc8b256272f881a8f2f4e71351c45d5bb27e8531f1e2ea6d55150c88f5026b8783ccef867a510a313178cfd26177";
  48. //.NET BC库解密,密文前要加 “04”,否则会报 Invalid point encoding XX
  49. //如果加密结果是BASE64的,把BASE64转16进制字符串,再判断是否04开头。
  50. //如果对方源码,固定截取的头2位,那么就不用判断是否04开头了,直接写死:javaSM2 = "04" + javaSM2;
  51. if (!javaSM2.StartsWith("04"))
  52. {
  53. javaSM2 = "04" + javaSM2;
  54. }
  55. Console.WriteLine("javaSM2加密结果:" + javaSM2);
  56. byToDecrypt = Hex.Decode(javaSM2);
  57. byDecrypted = GmUtil.Sm2Decrypt(byToDecrypt, bcecPrivateKey);
  58. strDecrypted = Encoding.UTF8.GetString(byDecrypted);
  59. Console.WriteLine("java SM2解密后:" + strDecrypted);
  60. }

 

java代码:

maven 引用 :

  1. <dependency>
  2. <groupId>cn.hutool</groupId>
  3. <artifactId>hutool-all</artifactId>
  4. <version>5.8.1</version>
  5. </dependency>
  6.  
  7. <dependency>
  8. <groupId>org.bouncycastle</groupId>
  9. <artifactId>bcprov-jdk15on</artifactId>
  10. <version>1.70</version>
  11. </dependency>

JAVA调用:

  1. package org.example;
  2. import cn.hutool.crypto.SmUtil;
  3. import cn.hutool.crypto.asymmetric.KeyType;
  4. import cn.hutool.crypto.asymmetric.SM2;
  5. import org.bouncycastle.crypto.engines.SM2Engine;
  6. import org.bouncycastle.util.encoders.Hex;
  7. static void testSM2Enc() {
  8. //sm2 加密模式:C1C3C2
  9. //私钥
  10. String privateKeyHex = "FAB8BBE670FAE338C9E9382B9FB6485225C11A3ECB84C938F10F20A93B6215F0";
  11. //完整公钥“9EF573019D9A03B16B0BE44FC8A5B4E8E098F56034C97B312282DD0B4810AFC3CC759673ED0FC9B9DC7E6FA38F0E2B121E02654BF37EA6B63FAF2A0D6013EADF”
  12. //公钥X
  13. String x = "9EF573019D9A03B16B0BE44FC8A5B4E8E098F56034C97B312282DD0B4810AFC3";
  14. //公钥Y
  15. String y = "CC759673ED0FC9B9DC7E6FA38F0E2B121E02654BF37EA6B63FAF2A0D6013EADF";
  16. String content = "1234泰酷拉JJ";
  17. System.out.println("待处理字符串:" + content);
  18. SM2 sm2 = new SM2(privateKeyHex, x, y);
  19. //默认是:C1C3C2
  20. sm2.setMode(SM2Engine.Mode.C1C3C2);
  21. //公钥加密
  22. byte[] byRst = sm2.encrypt(content.getBytes(), KeyType.PublicKey);
  23. String strRst = Hex.toHexString(byRst);
  24. System.out.println("加密后:" + strRst);
  25. byte[] byToDecrypt = Hex.decode(strRst);
  26. byte[] byDecrypted = sm2.decrypt(byToDecrypt, KeyType.PrivateKey);
  27. String strDecrypted = new String(byDecrypted);
  28. System.out.println("解密后:" + strDecrypted);
  29. }

 

end.


原文链接:https://www.cnblogs.com/runliuv/p/17607568.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号