当前位置:   article > 正文

sm2证书生成(openssl生成公私钥对)—使用_openssl sm2

openssl sm2

用上一篇的命令生成公私钥对。

1、sm2PubKey.pem

  1. -----BEGIN PUBLIC KEY-----
  2. MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEmxmSy4HOD2d2sakaJTw0QFhRGZs2
  3. 5umcKzmg12FAsYNjVRmtLxcbydzTMELGKpHHle//IZ0Eqx7P15IKiyoK/g==
  4. -----END PUBLIC KEY-----

2、sm2PriKeyPkcs8.pem

  1. -----BEGIN PRIVATE KEY-----
  2. MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgilIj1dWX+977jcQO
  3. oHDQq6XtbWaazcZdJiHjXpAhKD6hRANCAASbGZLLgc4PZ3axqRolPDRAWFEZmzbm
  4. 6ZwrOaDXYUCxg2NVGa0vFxvJ3NMwQsYqkceV7/8hnQSrHs/XkgqLKgr+
  5. -----END PRIVATE KEY-----

3、openssl ec -in sm2PriKeyPkcs8.pem -text

  1. read EC key
  2. Private-Key: (256 bit)
  3. priv:
  4. 8a:52:23:d5:d5:97:fb:de:fb:8d:c4:0e:a0:70:d0:
  5. ab:a5:ed:6d:66:9a:cd:c6:5d:26:21:e3:5e:90:21:
  6. 28:3e
  7. pub:
  8. 04:9b:19:92:cb:81:ce:0f:67:76:b1:a9:1a:25:3c:
  9. 34:40:58:51:19:9b:36:e6:e9:9c:2b:39:a0:d7:61:
  10. 40:b1:83:63:55:19:ad:2f:17:1b:c9:dc:d3:30:42:
  11. c6:2a:91:c7:95:ef:ff:21:9d:04:ab:1e:cf:d7:92:
  12. 0a:8b:2a:0a:fe
  13. ASN1 OID: SM2
  14. writing EC key
  15. -----BEGIN EC PRIVATE KEY-----
  16. MHcCAQEEIIpSI9XVl/ve+43EDqBw0Kul7W1mms3GXSYh416QISg+oAoGCCqBHM9V
  17. AYItoUQDQgAEmxmSy4HOD2d2sakaJTw0QFhRGZs25umcKzmg12FAsYNjVRmtLxcb
  18. ydzTMELGKpHHle//IZ0Eqx7P15IKiyoK/g==
  19. -----END EC PRIVATE KEY-----

5、工具类
BCECUtil.java

  1. package GMSM;
  2. import org.bouncycastle.asn1.ASN1Encodable;
  3. import org.bouncycastle.asn1.ASN1EncodableVector;
  4. import org.bouncycastle.asn1.ASN1Encoding;
  5. import org.bouncycastle.asn1.ASN1Integer;
  6. import org.bouncycastle.asn1.ASN1ObjectIdentifier;
  7. import org.bouncycastle.asn1.ASN1OctetString;
  8. import org.bouncycastle.asn1.ASN1Primitive;
  9. import org.bouncycastle.asn1.DERNull;
  10. import org.bouncycastle.asn1.DEROctetString;
  11. import org.bouncycastle.asn1.DERSequence;
  12. import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
  13. import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
  14. import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
  15. import org.bouncycastle.asn1.x9.X962Parameters;
  16. import org.bouncycastle.asn1.x9.X9ECParameters;
  17. import org.bouncycastle.asn1.x9.X9ECPoint;
  18. import org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
  19. import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
  20. import org.bouncycastle.crypto.generators.ECKeyPairGenerator;
  21. import org.bouncycastle.crypto.params.ECDomainParameters;
  22. import org.bouncycastle.crypto.params.ECKeyGenerationParameters;
  23. import org.bouncycastle.crypto.params.ECKeyParameters;
  24. import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
  25. import org.bouncycastle.crypto.params.ECPublicKeyParameters;
  26. import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
  27. import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
  28. import org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util;
  29. import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
  30. import org.bouncycastle.jce.provider.BouncyCastleProvider;
  31. import org.bouncycastle.jce.spec.ECNamedCurveSpec;
  32. import org.bouncycastle.jce.spec.ECParameterSpec;
  33. import org.bouncycastle.math.ec.ECCurve;
  34. import org.bouncycastle.math.ec.ECPoint;
  35. import org.bouncycastle.math.ec.FixedPointCombMultiplier;
  36. import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
  37. import org.bouncycastle.util.io.pem.PemObject;
  38. import org.bouncycastle.util.io.pem.PemReader;
  39. import org.bouncycastle.util.io.pem.PemWriter;
  40. import java.io.ByteArrayInputStream;
  41. import java.io.ByteArrayOutputStream;
  42. import java.io.IOException;
  43. import java.io.InputStreamReader;
  44. import java.io.OutputStreamWriter;
  45. import java.math.BigInteger;
  46. import java.security.InvalidAlgorithmParameterException;
  47. import java.security.KeyFactory;
  48. import java.security.KeyPair;
  49. import java.security.KeyPairGenerator;
  50. import java.security.NoSuchAlgorithmException;
  51. import java.security.NoSuchProviderException;
  52. import java.security.SecureRandom;
  53. import java.security.spec.ECGenParameterSpec;
  54. import java.security.spec.InvalidKeySpecException;
  55. import java.security.spec.PKCS8EncodedKeySpec;
  56. import java.security.spec.X509EncodedKeySpec;
  57. /**
  58. * 这个工具类的方法,也适用于其他基于BC库的ECC算法
  59. */
  60. public class BCECUtil {
  61. private static final String ALGO_NAME_EC = "EC";
  62. private static final String PEM_STRING_PUBLIC = "PUBLIC KEY";
  63. private static final String PEM_STRING_ECPRIVATEKEY = "EC PRIVATE KEY";
  64. /**
  65. * 生成ECC密钥对
  66. *
  67. * @return ECC密钥对
  68. */
  69. public static AsymmetricCipherKeyPair generateKeyPairParameter(
  70. ECDomainParameters domainParameters, SecureRandom random) {
  71. ECKeyGenerationParameters keyGenerationParams = new ECKeyGenerationParameters(domainParameters,
  72. random);
  73. ECKeyPairGenerator keyGen = new ECKeyPairGenerator();
  74. keyGen.init(keyGenerationParams);
  75. return keyGen.generateKeyPair();
  76. }
  77. public static KeyPair generateKeyPair(ECDomainParameters domainParameters, SecureRandom random)
  78. throws NoSuchProviderException, NoSuchAlgorithmException,
  79. InvalidAlgorithmParameterException {
  80. KeyPairGenerator kpg = KeyPairGenerator.getInstance(ALGO_NAME_EC, BouncyCastleProvider.PROVIDER_NAME);
  81. ECParameterSpec parameterSpec = new ECParameterSpec(domainParameters.getCurve(), domainParameters.getG(),
  82. domainParameters.getN(), domainParameters.getH());
  83. kpg.initialize(parameterSpec, random);
  84. return kpg.generateKeyPair();
  85. }
  86. public static int getCurveLength(ECKeyParameters ecKey) {
  87. return getCurveLength(ecKey.getParameters());
  88. }
  89. public static int getCurveLength(ECDomainParameters domainParams) {
  90. return (domainParams.getCurve().getFieldSize() + 7) / 8;
  91. }
  92. public static byte[] fixToCurveLengthBytes(int curveLength, byte[] src) {
  93. if (src.length == curveLength) {
  94. return src;
  95. }
  96. byte[] result = new byte[curveLength];
  97. if (src.length > curveLength) {
  98. System.arraycopy(src, src.length - result.length, result, 0, result.length);
  99. } else {
  100. System.arraycopy(src, 0, result, result.length - src.length, src.length);
  101. }
  102. return result;
  103. }
  104. /**
  105. * @param dHex 十六进制字符串形式的私钥d值,如果是SM2算法,Hex字符串长度应该是64(即32字节)
  106. * @param domainParameters EC Domain参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS}
  107. * @return
  108. */
  109. public static ECPrivateKeyParameters createECPrivateKeyParameters(
  110. String dHex, ECDomainParameters domainParameters) {
  111. return createECPrivateKeyParameters(ByteUtils.fromHexString(dHex), domainParameters);
  112. }
  113. /**
  114. * @param dBytes 字节数组形式的私钥d值,如果是SM2算法,应该是32字节
  115. * @param domainParameters EC Domain参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS}
  116. * @return
  117. */
  118. public static ECPrivateKeyParameters createECPrivateKeyParameters(
  119. byte[] dBytes, ECDomainParameters domainParameters) {
  120. return createECPrivateKeyParameters(new BigInteger(1, dBytes), domainParameters);
  121. }
  122. /**
  123. * @param d 大数形式的私钥d值
  124. * @param domainParameters EC Domain参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS}
  125. * @return
  126. */
  127. public static ECPrivateKeyParameters createECPrivateKeyParameters(
  128. BigInteger d, ECDomainParameters domainParameters) {
  129. return new ECPrivateKeyParameters(d, domainParameters);
  130. }
  131. /**
  132. * 根据EC私钥构造EC公钥
  133. *
  134. * @param priKey ECC私钥参数对象
  135. * @return
  136. */
  137. public static ECPublicKeyParameters buildECPublicKeyByPrivateKey(ECPrivateKeyParameters priKey) {
  138. ECDomainParameters domainParameters = priKey.getParameters();
  139. ECPoint q = new FixedPointCombMultiplier().multiply(domainParameters.getG(), priKey.getD());
  140. return new ECPublicKeyParameters(q, domainParameters);
  141. }
  142. /**
  143. * @param x 大数形式的公钥x分量
  144. * @param y 大数形式的公钥y分量
  145. * @param curve EC曲线参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#CURVE}
  146. * @param domainParameters EC Domain参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS}
  147. * @return
  148. */
  149. public static ECPublicKeyParameters createECPublicKeyParameters(
  150. BigInteger x, BigInteger y, ECCurve curve, ECDomainParameters domainParameters) {
  151. return createECPublicKeyParameters(x.toByteArray(), y.toByteArray(), curve, domainParameters);
  152. }
  153. /**
  154. * @param xHex 十六进制形式的公钥x分量,如果是SM2算法,Hex字符串长度应该是64(即32字节)
  155. * @param yHex 十六进制形式的公钥y分量,如果是SM2算法,Hex字符串长度应该是64(即32字节)
  156. * @param curve EC曲线参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#CURVE}
  157. * @param domainParameters EC Domain参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS}
  158. * @return
  159. */
  160. public static ECPublicKeyParameters createECPublicKeyParameters(
  161. String xHex, String yHex, ECCurve curve, ECDomainParameters domainParameters) {
  162. return createECPublicKeyParameters(ByteUtils.fromHexString(xHex), ByteUtils.fromHexString(yHex),
  163. curve, domainParameters);
  164. }
  165. /**
  166. * @param xBytes 十六进制形式的公钥x分量,如果是SM2算法,应该是32字节
  167. * @param yBytes 十六进制形式的公钥y分量,如果是SM2算法,应该是32字节
  168. * @param curve EC曲线参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#CURVE}
  169. * @param domainParameters EC Domain参数,一般是固定的,如果是SM2算法的可参考{@link SM2Util#DOMAIN_PARAMS}
  170. * @return
  171. */
  172. public static ECPublicKeyParameters createECPublicKeyParameters(
  173. byte[] xBytes, byte[] yBytes, ECCurve curve, ECDomainParameters domainParameters) {
  174. final byte uncompressedFlag = 0x04;
  175. int curveLength = getCurveLength(domainParameters);
  176. xBytes = fixToCurveLengthBytes(curveLength, xBytes);
  177. yBytes = fixToCurveLengthBytes(curveLength, yBytes);
  178. byte[] encodedPubKey = new byte[1 + xBytes.length + yBytes.length];
  179. encodedPubKey[0] = uncompressedFlag;
  180. System.arraycopy(xBytes, 0, encodedPubKey, 1, xBytes.length);
  181. System.arraycopy(yBytes, 0, encodedPubKey, 1 + xBytes.length, yBytes.length);
  182. return new ECPublicKeyParameters(curve.decodePoint(encodedPubKey), domainParameters);
  183. }
  184. public static ECPrivateKeyParameters convertPrivateKeyToParameters(BCECPrivateKey ecPriKey) {
  185. ECParameterSpec parameterSpec = ecPriKey.getParameters();
  186. ECDomainParameters domainParameters = new ECDomainParameters(parameterSpec.getCurve(), parameterSpec.getG(),
  187. parameterSpec.getN(), parameterSpec.getH());
  188. return new ECPrivateKeyParameters(ecPriKey.getD(), domainParameters);
  189. }
  190. public static ECPublicKeyParameters convertPublicKeyToParameters(BCECPublicKey ecPubKey) {
  191. ECParameterSpec parameterSpec = ecPubKey.getParameters();
  192. ECDomainParameters domainParameters = new ECDomainParameters(parameterSpec.getCurve(), parameterSpec.getG(),
  193. parameterSpec.getN(), parameterSpec.getH());
  194. return new ECPublicKeyParameters(ecPubKey.getQ(), domainParameters);
  195. }
  196. public static BCECPublicKey createPublicKeyFromSubjectPublicKeyInfo(SubjectPublicKeyInfo subPubInfo)
  197. throws NoSuchProviderException,
  198. NoSuchAlgorithmException, InvalidKeySpecException, IOException {
  199. return BCECUtil.convertX509ToECPublicKey(subPubInfo.toASN1Primitive().getEncoded(ASN1Encoding.DER));
  200. }
  201. /**
  202. * 将ECC私钥转换为PKCS8标准的字节流
  203. *
  204. * @param priKey
  205. * @param pubKey 可以为空,但是如果为空的话得到的结果OpenSSL可能解析不了
  206. * @return
  207. */
  208. public static byte[] convertECPrivateKeyToPKCS8(
  209. ECPrivateKeyParameters priKey, ECPublicKeyParameters pubKey) {
  210. ECDomainParameters domainParams = priKey.getParameters();
  211. ECParameterSpec spec = new ECParameterSpec(domainParams.getCurve(), domainParams.getG(),
  212. domainParams.getN(), domainParams.getH());
  213. BCECPublicKey publicKey = null;
  214. if (pubKey != null) {
  215. publicKey = new BCECPublicKey(ALGO_NAME_EC, pubKey, spec,
  216. BouncyCastleProvider.CONFIGURATION);
  217. }
  218. BCECPrivateKey privateKey = new BCECPrivateKey(ALGO_NAME_EC, priKey, publicKey,
  219. spec, BouncyCastleProvider.CONFIGURATION);
  220. return privateKey.getEncoded();
  221. }
  222. /**
  223. * 将PKCS8标准的私钥字节流转换为私钥对象
  224. *
  225. * @param pkcs8Key
  226. * @return
  227. * @throws NoSuchAlgorithmException
  228. * @throws NoSuchProviderException
  229. * @throws InvalidKeySpecException
  230. */
  231. public static BCECPrivateKey convertPKCS8ToECPrivateKey(byte[] pkcs8Key)
  232. throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException {
  233. PKCS8EncodedKeySpec peks = new PKCS8EncodedKeySpec(pkcs8Key);
  234. KeyFactory kf = KeyFactory.getInstance(ALGO_NAME_EC, BouncyCastleProvider.PROVIDER_NAME);
  235. return (BCECPrivateKey) kf.generatePrivate(peks);
  236. }
  237. /**
  238. * 将PKCS8标准的私钥字节流转换为PEM
  239. *
  240. * @param encodedKey
  241. * @return
  242. * @throws IOException
  243. */
  244. public static String convertECPrivateKeyPKCS8ToPEM(byte[] encodedKey) throws IOException {
  245. return convertEncodedDataToPEM(PEM_STRING_ECPRIVATEKEY, encodedKey);
  246. }
  247. /**
  248. * 将PEM格式的私钥转换为PKCS8标准字节流
  249. *
  250. * @param pemString
  251. * @return
  252. * @throws IOException
  253. */
  254. public static byte[] convertECPrivateKeyPEMToPKCS8(String pemString) throws IOException {
  255. return convertPEMToEncodedData(pemString);
  256. }
  257. /**
  258. * 将ECC私钥转换为SEC1标准的字节流
  259. * openssl d2i_ECPrivateKey函数要求的DER编码的私钥也是SEC1标准的,
  260. * 这个工具函数的主要目的就是为了能生成一个openssl可以直接“识别”的ECC私钥.
  261. * 相对RSA私钥的PKCS1标准,ECC私钥的标准为SEC1
  262. *
  263. * @param priKey
  264. * @param pubKey
  265. * @return
  266. * @throws IOException
  267. */
  268. public static byte[] convertECPrivateKeyToSEC1(
  269. ECPrivateKeyParameters priKey, ECPublicKeyParameters pubKey) throws IOException {
  270. byte[] pkcs8Bytes = convertECPrivateKeyToPKCS8(priKey, pubKey);
  271. PrivateKeyInfo pki = PrivateKeyInfo.getInstance(pkcs8Bytes);
  272. ASN1Encodable encodable = pki.parsePrivateKey();
  273. ASN1Primitive primitive = encodable.toASN1Primitive();
  274. byte[] sec1Bytes = primitive.getEncoded();
  275. return sec1Bytes;
  276. }
  277. /**
  278. * 将SEC1标准的私钥字节流恢复为PKCS8标准的字节流
  279. *
  280. * @param sec1Key
  281. * @return
  282. * @throws IOException
  283. */
  284. public static byte[] convertECPrivateKeySEC1ToPKCS8(byte[] sec1Key) throws IOException {
  285. /**
  286. * 参考org.bouncycastle.asn1.pkcs.PrivateKeyInfo和
  287. * org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey,逆向拼装
  288. */
  289. X962Parameters params = getDomainParametersFromName(SM2Util.JDK_EC_SPEC, false);
  290. ASN1OctetString privKey = new DEROctetString(sec1Key);
  291. ASN1EncodableVector v = new ASN1EncodableVector();
  292. v.add(new ASN1Integer(0)); //版本号
  293. v.add(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params)); //算法标识
  294. v.add(privKey);
  295. DERSequence ds = new DERSequence(v);
  296. return ds.getEncoded(ASN1Encoding.DER);
  297. }
  298. /**
  299. * 将SEC1标准的私钥字节流转为BCECPrivateKey对象
  300. *
  301. * @param sec1Key
  302. * @return
  303. * @throws NoSuchAlgorithmException
  304. * @throws NoSuchProviderException
  305. * @throws InvalidKeySpecException
  306. * @throws IOException
  307. */
  308. public static BCECPrivateKey convertSEC1ToBCECPrivateKey(byte[] sec1Key)
  309. throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, IOException {
  310. PKCS8EncodedKeySpec peks = new PKCS8EncodedKeySpec(convertECPrivateKeySEC1ToPKCS8(sec1Key));
  311. KeyFactory kf = KeyFactory.getInstance(ALGO_NAME_EC, BouncyCastleProvider.PROVIDER_NAME);
  312. return (BCECPrivateKey) kf.generatePrivate(peks);
  313. }
  314. /**
  315. * 将SEC1标准的私钥字节流转为ECPrivateKeyParameters对象
  316. * openssl i2d_ECPrivateKey函数生成的DER编码的ecc私钥是:SEC1标准的、带有EC_GROUP、带有公钥的,
  317. * 这个工具函数的主要目的就是为了使Java程序能够“识别”openssl生成的ECC私钥
  318. *
  319. * @param sec1Key
  320. * @return
  321. * @throws NoSuchAlgorithmException
  322. * @throws NoSuchProviderException
  323. * @throws InvalidKeySpecException
  324. */
  325. public static ECPrivateKeyParameters convertSEC1ToECPrivateKey(byte[] sec1Key)
  326. throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, IOException {
  327. BCECPrivateKey privateKey = convertSEC1ToBCECPrivateKey(sec1Key);
  328. return convertPrivateKeyToParameters(privateKey);
  329. }
  330. /**
  331. * 将ECC公钥对象转换为X509标准的字节流
  332. *
  333. * @param pubKey
  334. * @return
  335. */
  336. public static byte[] convertECPublicKeyToX509(ECPublicKeyParameters pubKey) {
  337. ECDomainParameters domainParams = pubKey.getParameters();
  338. ECParameterSpec spec = new ECParameterSpec(domainParams.getCurve(), domainParams.getG(),
  339. domainParams.getN(), domainParams.getH());
  340. BCECPublicKey publicKey = new BCECPublicKey(ALGO_NAME_EC, pubKey, spec,
  341. BouncyCastleProvider.CONFIGURATION);
  342. return publicKey.getEncoded();
  343. }
  344. /**
  345. * 将X509标准的公钥字节流转为公钥对象
  346. *
  347. * @param x509Bytes
  348. * @return
  349. * @throws NoSuchProviderException
  350. * @throws NoSuchAlgorithmException
  351. * @throws InvalidKeySpecException
  352. */
  353. public static BCECPublicKey convertX509ToECPublicKey(byte[] x509Bytes) throws NoSuchProviderException,
  354. NoSuchAlgorithmException, InvalidKeySpecException {
  355. X509EncodedKeySpec eks = new X509EncodedKeySpec(x509Bytes);
  356. KeyFactory kf = KeyFactory.getInstance("EC", BouncyCastleProvider.PROVIDER_NAME);
  357. return (BCECPublicKey) kf.generatePublic(eks);
  358. }
  359. /**
  360. * 将X509标准的公钥字节流转为PEM
  361. *
  362. * @param encodedKey
  363. * @return
  364. * @throws IOException
  365. */
  366. public static String convertECPublicKeyX509ToPEM(byte[] encodedKey) throws IOException {
  367. return convertEncodedDataToPEM(PEM_STRING_PUBLIC, encodedKey);
  368. }
  369. /**
  370. * 将PEM格式的公钥转为X509标准的字节流
  371. *
  372. * @param pemString
  373. * @return
  374. * @throws IOException
  375. */
  376. public static byte[] convertECPublicKeyPEMToX509(String pemString) throws IOException {
  377. return convertPEMToEncodedData(pemString);
  378. }
  379. /**
  380. * copy from BC
  381. *
  382. * @param genSpec
  383. * @return
  384. */
  385. public static X9ECParameters getDomainParametersFromGenSpec(ECGenParameterSpec genSpec) {
  386. return getDomainParametersFromName(genSpec.getName());
  387. }
  388. /**
  389. * copy from BC
  390. *
  391. * @param curveName
  392. * @return
  393. */
  394. public static X9ECParameters getDomainParametersFromName(String curveName) {
  395. X9ECParameters domainParameters;
  396. try {
  397. if (curveName.charAt(0) >= '0' && curveName.charAt(0) <= '2') {
  398. ASN1ObjectIdentifier oidID = new ASN1ObjectIdentifier(curveName);
  399. domainParameters = ECUtil.getNamedCurveByOid(oidID);
  400. } else {
  401. if (curveName.indexOf(' ') > 0) {
  402. curveName = curveName.substring(curveName.indexOf(' ') + 1);
  403. domainParameters = ECUtil.getNamedCurveByName(curveName);
  404. } else {
  405. domainParameters = ECUtil.getNamedCurveByName(curveName);
  406. }
  407. }
  408. } catch (IllegalArgumentException ex) {
  409. domainParameters = ECUtil.getNamedCurveByName(curveName);
  410. }
  411. return domainParameters;
  412. }
  413. /**
  414. * copy from BC
  415. *
  416. * @param ecSpec
  417. * @param withCompression
  418. * @return
  419. */
  420. public static X962Parameters getDomainParametersFromName(
  421. java.security.spec.ECParameterSpec ecSpec, boolean withCompression) {
  422. X962Parameters params;
  423. if (ecSpec instanceof ECNamedCurveSpec) {
  424. ASN1ObjectIdentifier curveOid = ECUtil.getNamedCurveOid(((ECNamedCurveSpec) ecSpec).getName());
  425. if (curveOid == null) {
  426. curveOid = new ASN1ObjectIdentifier(((ECNamedCurveSpec) ecSpec).getName());
  427. }
  428. params = new X962Parameters(curveOid);
  429. } else if (ecSpec == null) {
  430. params = new X962Parameters(DERNull.INSTANCE);
  431. } else {
  432. ECCurve curve = EC5Util.convertCurve(ecSpec.getCurve());
  433. X9ECParameters ecP = new X9ECParameters(
  434. curve,
  435. new X9ECPoint(EC5Util.convertPoint(curve, ecSpec.getGenerator()), withCompression),
  436. ecSpec.getOrder(),
  437. BigInteger.valueOf(ecSpec.getCofactor()),
  438. ecSpec.getCurve().getSeed());
  439. // 如果是1.62或更低版本的bcprov-jdk15on应该使用以下这段代码,因为高版本的EC5Util.convertPoint没有向下兼容
  440. /*
  441. X9ECParameters ecP = new X9ECParameters(
  442. curve,
  443. EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression),
  444. ecSpec.getOrder(),
  445. BigInteger.valueOf(ecSpec.getCofactor()),
  446. ecSpec.getCurve().getSeed());
  447. */
  448. params = new X962Parameters(ecP);
  449. }
  450. return params;
  451. }
  452. private static String convertEncodedDataToPEM(String type, byte[] encodedData) throws IOException {
  453. ByteArrayOutputStream bOut = new ByteArrayOutputStream();
  454. PemWriter pWrt = new PemWriter(new OutputStreamWriter(bOut));
  455. try {
  456. PemObject pemObj = new PemObject(type, encodedData);
  457. pWrt.writeObject(pemObj);
  458. } finally {
  459. pWrt.close();
  460. }
  461. return new String(bOut.toByteArray());
  462. }
  463. private static byte[] convertPEMToEncodedData(String pemString) throws IOException {
  464. ByteArrayInputStream bIn = new ByteArrayInputStream(pemString.getBytes());
  465. PemReader pRdr = new PemReader(new InputStreamReader(bIn));
  466. try {
  467. PemObject pemObject = pRdr.readPemObject();
  468. return pemObject.getContent();
  469. } finally {
  470. pRdr.close();
  471. }
  472. }
  473. }

SM2Util.java

  1. package GMSM;
  2. import org.bouncycastle.asn1.gm.GMNamedCurves;
  3. import org.bouncycastle.asn1.x9.X9ECParameters;
  4. import org.bouncycastle.crypto.CryptoException;
  5. import org.bouncycastle.crypto.InvalidCipherTextException;
  6. import org.bouncycastle.crypto.engines.SM2Engine;
  7. import org.bouncycastle.crypto.params.*;
  8. import org.bouncycastle.crypto.signers.SM2Signer;
  9. import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
  10. import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
  11. import org.bouncycastle.jce.provider.BouncyCastleProvider;
  12. import org.bouncycastle.math.ec.ECCurve;
  13. import org.bouncycastle.math.ec.ECPoint;
  14. import org.bouncycastle.math.ec.custom.gm.SM2P256V1Curve;
  15. import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
  16. import org.bouncycastle.util.Strings;
  17. import org.bouncycastle.util.encoders.Base64;
  18. import org.bouncycastle.util.encoders.Hex;
  19. import java.math.BigInteger;
  20. import java.nio.charset.Charset;
  21. import java.security.KeyPair;
  22. import java.security.KeyPairGenerator;
  23. import java.security.NoSuchAlgorithmException;
  24. import java.security.SecureRandom;
  25. import java.security.Security;
  26. import java.security.spec.ECFieldFp;
  27. import java.security.spec.ECGenParameterSpec;
  28. import java.security.spec.EllipticCurve;
  29. /**
  30. * SM2 工具类
  31. */
  32. public class SM2Util {
  33. static {
  34. Security.addProvider(new BouncyCastleProvider());
  35. }
  36. //
  37. /*
  38. * 以下为SM2推荐曲线参数
  39. */
  40. public static final SM2P256V1Curve CURVE = new SM2P256V1Curve();
  41. public final static BigInteger SM2_ECC_P = CURVE.getQ();
  42. public final static BigInteger SM2_ECC_A = CURVE.getA().toBigInteger();
  43. public final static BigInteger SM2_ECC_B = CURVE.getB().toBigInteger();
  44. public final static BigInteger SM2_ECC_N = CURVE.getOrder();
  45. public final static BigInteger SM2_ECC_H = CURVE.getCofactor();
  46. public final static BigInteger SM2_ECC_GX = new BigInteger(
  47. "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7", 16);
  48. public final static BigInteger SM2_ECC_GY = new BigInteger(
  49. "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0", 16);
  50. public static final ECPoint G_POINT = CURVE.createPoint(SM2_ECC_GX, SM2_ECC_GY);
  51. public static final ECDomainParameters DOMAIN_PARAMS = new ECDomainParameters(CURVE, G_POINT,
  52. SM2_ECC_N, SM2_ECC_H);
  53. public static final int CURVE_LEN = BCECUtil.getCurveLength(DOMAIN_PARAMS);
  54. //
  55. public static final EllipticCurve JDK_CURVE = new EllipticCurve(new ECFieldFp(SM2_ECC_P), SM2_ECC_A, SM2_ECC_B);
  56. public static final java.security.spec.ECPoint JDK_G_POINT = new java.security.spec.ECPoint(
  57. G_POINT.getAffineXCoord().toBigInteger(), G_POINT.getAffineYCoord().toBigInteger());
  58. public static final java.security.spec.ECParameterSpec JDK_EC_SPEC = new java.security.spec.ECParameterSpec(
  59. JDK_CURVE, JDK_G_POINT, SM2_ECC_N, SM2_ECC_H.intValue());
  60. //
  61. // SM2推荐曲线名称
  62. public static final String SM2_CURVE_NAME = "sm2p256v1";
  63. public static final Charset UTF_8 = Charset.forName("utf-8");
  64. /**
  65. * 生成密钥
  66. *
  67. * @return
  68. * @throws Exception
  69. */
  70. public static KeyPair genKeyPair() throws Exception {
  71. final ECGenParameterSpec sm2Spec = new ECGenParameterSpec(SM2_CURVE_NAME);
  72. // 获取一个椭圆曲线类型的密钥对生成器
  73. final KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", new BouncyCastleProvider());
  74. SecureRandom random = new SecureRandom();
  75. // 使用SM2的算法区域初始化密钥生成器
  76. kpg.initialize(sm2Spec, random);
  77. // 获取密钥对
  78. KeyPair keyPair = kpg.generateKeyPair();
  79. return keyPair;
  80. }
  81. /**
  82. * SM2根据公钥加密 param: message 待加密内容 , publicKey 加密公钥(BASE64编码) return:
  83. * 加密信息的Base64编码
  84. *
  85. * @throws InvalidCipherTextException
  86. */
  87. public static String encryptBySM2(String message, String publicKey) throws InvalidCipherTextException {
  88. ECDomainParameters domin = getDomain();
  89. // 公钥对象
  90. ECPublicKeyParameters pubKeyParameters = getPubKey(publicKey, domin);
  91. byte[] cipherBytes = new byte[0];
  92. cipherBytes = encrypt(SM2Engine.Mode.C1C3C2, pubKeyParameters, message.getBytes(UTF_8));
  93. return Base64.toBase64String(cipherBytes);
  94. }
  95. /**
  96. * SM2根据私钥解密 param: cipherText 待解密密文 privateKey-私钥(BASE64编码)
  97. */
  98. public static String decryptBySM2(String cipherText, String privateKey) throws InvalidCipherTextException {
  99. BigInteger d = new BigInteger(1, Base64.decode(privateKey));
  100. ECDomainParameters domin = getDomain();
  101. // 私钥对象
  102. ECPrivateKeyParameters ecPrivateKeyParameters = new ECPrivateKeyParameters(d, domin);
  103. byte[] decrypt = decrypt(SM2Engine.Mode.C1C3C2, ecPrivateKeyParameters, Base64.decode(cipherText));
  104. return new String(decrypt, UTF_8);
  105. }
  106. /**
  107. * 根据公钥字符串创建公钥对象
  108. *
  109. */
  110. public static ECPublicKeyParameters getPubKey(String publicKey, ECDomainParameters domain) {
  111. ECCurve curve = domain.getCurve();
  112. ECPoint point = curve.decodePoint(Base64.decode(publicKey));
  113. ECPublicKeyParameters PublicKey = new ECPublicKeyParameters(point, domain);
  114. return PublicKey;
  115. }
  116. /**
  117. * @param mode 指定密文结构,旧标准的为C1C2C3,新的[《SM2密码算法使用规范》 GM/T
  118. * 0009-2012]标准为C1C3C2
  119. * @param pubKeyParameters 公钥
  120. * @param srcData 原文
  121. * @return 根据mode不同,输出的密文C1C2C3排列顺序不同。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。
  122. * @throws InvalidCipherTextException
  123. */
  124. public static byte[] encrypt(SM2Engine.Mode mode, ECPublicKeyParameters pubKeyParameters, byte[] srcData)
  125. throws InvalidCipherTextException {
  126. SM2Engine engine = new SM2Engine(mode);
  127. ParametersWithRandom pwr = new ParametersWithRandom(pubKeyParameters, new SecureRandom());
  128. engine.init(true, pwr);
  129. return engine.processBlock(srcData, 0, srcData.length);
  130. }
  131. /**
  132. * @param mode 指定密文结构,旧标准的为C1C2C3,新的[《SM2密码算法使用规范》 GM/T
  133. * 0009-2012]标准为C1C3C2
  134. * @param priKeyParameters 私钥
  135. * @param sm2Cipher 根据mode不同,需要输入的密文C1C2C3排列顺序不同。C1为65字节第1字节为压缩标识,这里固定为0x04,后面64字节为xy分量各32字节。C3为32字节。C2长度与原文一致。
  136. * @return 原文。SM2解密返回了数据则一定是原文,因为SM2自带校验,如果密文被篡改或者密钥对不上,都是会直接报异常的。
  137. * @throws InvalidCipherTextException
  138. */
  139. public static byte[] decrypt(SM2Engine.Mode mode, ECPrivateKeyParameters priKeyParameters, byte[] sm2Cipher)
  140. throws InvalidCipherTextException {
  141. SM2Engine engine = new SM2Engine(mode);
  142. engine.init(false, priKeyParameters);
  143. return engine.processBlock(sm2Cipher, 0, sm2Cipher.length);
  144. }
  145. public static ECDomainParameters getDomain() {
  146. // 获取一条SM2曲线参数
  147. X9ECParameters x9ECParameters = GMNamedCurves.getByName(SM2_CURVE_NAME);
  148. // 构造domain参数
  149. ECDomainParameters domain = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(),
  150. x9ECParameters.getN(), x9ECParameters.getH());
  151. return domain;
  152. }
  153. /**
  154. * 私钥签名
  155. *
  156. * @param privateKey 私钥
  157. * @param content 待签名内容
  158. * @return
  159. */
  160. public static String sign(String privateKey, String content) throws CryptoException, CryptoException {
  161. // 待签名内容转为字节数组
  162. byte[] message = content.getBytes();
  163. BigInteger domainParameters = new BigInteger(1, Base64.decode(privateKey));
  164. ECDomainParameters domin = getDomain();
  165. // 私钥对象
  166. ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(domainParameters, domin);
  167. // 创建签名实例
  168. SM2Signer sm2Signer = new SM2Signer();
  169. // 初始化签名实例,带上ID,国密的要求,ID默认值:1234567812345678
  170. try {
  171. sm2Signer.init(true,
  172. new ParametersWithID(
  173. new ParametersWithRandom(privateKeyParameters, SecureRandom.getInstance("SHA1PRNG")),
  174. Strings.toByteArray("1234567812345678")));
  175. } catch (NoSuchAlgorithmException e) {
  176. e.printStackTrace();
  177. }
  178. sm2Signer.update(message, 0, message.length);
  179. // 生成签名,签名分为两部分r和s,分别对应索引0和1的数组
  180. byte[] signBytes = sm2Signer.generateSignature();
  181. String sign = Base64.toBase64String(signBytes);
  182. return sign;
  183. }
  184. /**
  185. * 验证签名
  186. *
  187. * @param publicKey 公钥
  188. * @param content 待签名内容
  189. * @param sign 签名值
  190. * @return
  191. */
  192. public static boolean verify(String publicKey, String content, String sign) {
  193. // 待签名内容
  194. byte[] message = content.getBytes();
  195. byte[] signData = Base64.decode(sign);
  196. // 获取一条SM2曲线参数
  197. X9ECParameters sm2ECParameters = GMNamedCurves.getByName(SM2_CURVE_NAME);
  198. // 构造domain参数
  199. ECDomainParameters domainParameters = new ECDomainParameters(sm2ECParameters.getCurve(), sm2ECParameters.getG(),
  200. sm2ECParameters.getN());
  201. // 提取公钥点
  202. ECPoint pukPoint = sm2ECParameters.getCurve().decodePoint(java.util.Base64.getDecoder().decode(publicKey));
  203. // 公钥前面的02或者03表示是压缩公钥,04表示未压缩公钥, 04的时候,可以去掉前面的04
  204. ECPublicKeyParameters publicKeyParameters = new ECPublicKeyParameters(pukPoint, domainParameters);
  205. // 创建签名实例
  206. SM2Signer sm2Signer = new SM2Signer();
  207. ParametersWithID parametersWithID = new ParametersWithID(publicKeyParameters,
  208. Strings.toByteArray("1234567812345678"));
  209. sm2Signer.init(false, parametersWithID);
  210. sm2Signer.update(message, 0, message.length);
  211. // 验证签名结果
  212. boolean verify = sm2Signer.verifySignature(signData);
  213. return verify;
  214. }
  215. /**
  216. * 获取私钥(16进制字符串,头部不带00长度共64)
  217. * @param privateKey 私钥
  218. * @return
  219. */
  220. public static String getPriKeyHexString(PrivateKey privateKey){
  221. BCECPrivateKey s=(BCECPrivateKey)privateKey;
  222. String priKeyHexString = Hex.toHexString(s.getD().toByteArray());
  223. if(null!= priKeyHexString && priKeyHexString.length()==66 && "00".equals(priKeyHexString.substring(0,2))){
  224. return priKeyHexString.substring(2);
  225. }
  226. return priKeyHexString;
  227. }
  228. /**
  229. * 获取公钥(16进制字符串,头部带04长度共130)
  230. * @param publicKey
  231. * @return
  232. */
  233. public static String getPubKeyHexString(PublicKey publicKey){
  234. BCECPublicKey p=(BCECPublicKey)publicKey;
  235. return Hex.toHexString(p.getQ().getEncoded(false));
  236. }
  237. }

6、写一个main方法

  1. public static void main(String[] args) throws Exception {
  2. //openssl生成sm2公私钥对
  3. //公钥
  4. String pu1 = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEmxmSy4HOD2d2sakaJTw0QFhRGZs25umcKzmg12FAsYNjVRmtLxcbydzTMELGKpHHle//IZ0Eqx7P15IKiyoK/g==";
  5. //私钥
  6. String pr1 = "MIGHAgEAMBMGByqGSM49AgEGCCqBHM9VAYItBG0wawIBAQQgilIj1dWX+977jcQOoHDQq6XtbWaazcZdJiHjXpAhKD6hRANCAASbGZLLgc4PZ3axqRolPDRAWFEZmzbm6ZwrOaDXYUCxg2NVGa0vFxvJ3NMwQsYqkceV7/8hnQSrHs/XkgqLKgr+";
  7. //公钥文件是x509格式,转换成ECPublicKey,提取真正的公钥
  8. byte[] x509pu1 = Base64.decode(pu1);
  9. BCECPublicKey bcecPublicKey = BCECUtil.convertX509ToECPublicKey(x509pu1);
  10. String s1 = ByteUtils.toHexString(bcecPublicKey.getQ().getEncoded(false));
  11. System.out.println("公钥:" + s1);
  12. //私钥文件是pkcs8格式,转换成ECPrivateKey,提取真正的私钥
  13. byte[] x509pr1 = Base64.decode(pr1);
  14. BCECPrivateKey bcecPrivateKey = BCECUtil.convertPKCS8ToECPrivateKey(x509pr1);
  15. String s2 = ByteUtils.toHexString(bcecPrivateKey.getD().toByteArray());
  16. //java会在私钥前加00,要去除
  17. s2 = s2.substring(2);
  18. System.out.println("私钥:" + s2);
  19. System.out.println("==========测试加密解密==========");
  20. //String publicKey = "049b1992cb81ce0f6776b1a91a253c34405851199b36e6e99c2b39a0d76140b183635519ad2f171bc9dcd33042c62a91c795efff219d04ab1ecfd7920a8b2a0afe";
  21. String publicKey = s1;
  22. String str = "11111111111111111111111111111111111111111111111111111111111";
  23. String en = encryptBySM2(str, Base64.toBase64String(Hex.decode(publicKey)) );
  24. System.out.println("加密后:" + en);
  25. //String privateKey = "8a5223d5d597fbdefb8dc40ea070d0aba5ed6d669acdc65d2621e35e9021283e";
  26. String privateKey = s2;
  27. String de = decryptBySM2(en, Base64.toBase64String(Hex.decode(privateKey)) );
  28. System.out.println("解密后:" + de);
  29. System.out.println("==========测试签名验签==========");
  30. String sign = sign(Base64.toBase64String(Hex.decode(privateKey)), str);
  31. System.out.println("sign:" + sign);
  32. boolean flag = verify(Base64.toBase64String(Hex.decode(publicKey)), str, sign);
  33. System.out.println("验签结果:" + flag);
  34. }

执行结果:

  1. 公钥:049b1992cb81ce0f6776b1a91a253c34405851199b36e6e99c2b39a0d76140b183635519ad2f171bc9dcd33042c62a91c795efff219d04ab1ecfd7920a8b2a0afe
  2. 私钥:8a5223d5d597fbdefb8dc40ea070d0aba5ed6d669acdc65d2621e35e9021283e
  3. ==========测试加密解密==========
  4. 加密后:BKIe16SRgAgHGgOalBDv1xtIONHVQtrfCXpnVnH2iOwhKoXXYLCDrp8FlcNtJwnpJxtF9soslWvO+HhfpmW4knRBGk+NLs9ftf+mSeNaVkFG2ySt0tIjUKHl51GUZlkW1yQ/DRm7w9BNheJgow+PX5jorKhzM1IIv2AshlNFQg9Yut066j+5dLtE+no5/32O9+4dP80z6jGc+FcI
  5. 解密后:11111111111111111111111111111111111111111111111111111111111
  6. ==========测试签名验签==========
  7. sign:MEUCICKGZZ5X1JAFa40/vtqD4de+HKh9rAiWaAtiUKVAODPgAiEAkXcnA3OxcXk0latkmmr3KS5ptwBI6PiPVJcyJJrnSp8=
  8. 验签结果:true

密钥和命令解析出来的一样。
依赖包:bcprov-jdk15on-1.70.jar

SM2加密算法的结果长度,取决于明文长度,没记错的话是C1+C2+C3, C1和C3是定长,分别为64字节和32字节,C2的长度等于明文长度
准确的计算过程,可以看看GM/T 0003.4

用密钥明文16进制转16进制字符串再base64编码:

  1. public static void main(String[] args) throws Exception {
  2. //公钥明文字符串转base64编码,公钥明文字符串128字节长度不带04
  3. String pu2 = "OWIxOTkyY2I4MWNlMGY2Nzc2YjFhOTFhMjUzYzM0NDA1ODUxMTk5YjM2ZTZlOTljMmIzOWEwZDc2MTQwYjE4MzYzNTUxOWFkMmYxNzFiYzlkY2QzMzA0MmM2MmE5MWM3OTVlZmZmMjE5ZDA0YWIxZWNmZDc5MjBhOGIyYTBhZmU=";
  4. //私钥明文字符串转base64编码,私钥明文字符串64字节长度
  5. String pr2 = "OGE1MjIzZDVkNTk3ZmJkZWZiOGRjNDBlYTA3MGQwYWJhNWVkNmQ2NjlhY2RjNjVkMjYyMWUzNWU5MDIxMjgzZQ==";
  6. //base64解码
  7. String s3 = "04" + new String(Base64.decode(pu2)); //公钥前加04
  8. String s4 = new String(Base64.decode(pr2));
  9. System.out.println("公钥:" + s3);
  10. System.out.println("私钥:" + s4);
  11. byte pub2[] = Hex.decode("04" + new String(Base64.decode(pu2)));
  12. byte pri2[] = Hex.decode(new String(Base64.decode(pr2)));
  13. String str = "11111111111111111111111111111111111111111111111111111111111";
  14. System.out.println("==========测试加密解密==========");
  15. String en = encryptBySM2(str, Base64.toBase64String(pub2));
  16. System.out.println("加密后:" + en);
  17. String de = decryptBySM2(en, Base64.toBase64String(pri2));
  18. System.out.println("解密后:" + de);
  19. System.out.println("==========测试签名验签==========");
  20. String sign = sign(Base64.toBase64String(pri2), str);
  21. System.out.println("sign:" + sign);
  22. boolean flag = verify(Base64.toBase64String(pub2), str, sign);
  23. System.out.println("验签结果:" + flag);
  24. }

执行结果:

  1. 公钥:049b1992cb81ce0f6776b1a91a253c34405851199b36e6e99c2b39a0d76140b183635519ad2f171bc9dcd33042c62a91c795efff219d04ab1ecfd7920a8b2a0afe
  2. 私钥:8a5223d5d597fbdefb8dc40ea070d0aba5ed6d669acdc65d2621e35e9021283e
  3. ==========测试加密解密==========
  4. 加密后:BIPG2WfWmBz+xU/btAI796VF7RX53WYZfsujS2ICC5umdS7x6hIE+zDEJpStVY/rAYmJeqEsmNx2oHN/8rbWiDgkZJS2xZL50br+a2RThzmh2fcdFSy3MtNcvcFGB/FD/h+pm5ImdPO94HD9Efv3apNum3/V5sNxUOM08YMgXrIYx30osZzBE41NSfO7El2NM5Ryy7xj0qgPmq3j
  5. 解密后:11111111111111111111111111111111111111111111111111111111111
  6. ==========测试签名验签==========
  7. sign:MEUCIQDTzmVPjkPqPvpV2hMJvqPIMNjakS5/iMY5aeIGIYjGAAIgOREKqHSC0bfb1RIbhGz80wKpU87qqFYYCxyjiI64CRg=
  8. 验签结果:true

用工具类生成密钥对:

  1. public static void main(String[] args) throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
  2. String M="encryption standard";
  3. System.out.println("\n明文:"+ M);
  4. SM2Util sm2 = new SM2Util();
  5. KeyPair keyPair = sm2.geneSM2KeyPair();
  6. PublicKey publicKey = keyPair.getPublic();
  7. String pubKeyHexString = sm2.getPubKeyHexString(publicKey);
  8. System.out.println("公钥:"+ pubKeyHexString);
  9. PrivateKey privateKey = keyPair.getPrivate();
  10. String priKeyHexString = sm2.getPriKeyHexString(privateKey);
  11. System.out.println("私钥:"+ priKeyHexString);
  12. String cipherData = sm2.encrypt(pubKeyHexString, M);
  13. System.out.println("密文:" + cipherData);
  14. String text=sm2.decrypt(priKeyHexString, cipherData);
  15. System.out.println("解密:"+text);
  16. }

参考资料:
支付对接常用的加密方式介绍以及java代码实现_京东云官方的技术博客_51CTO博客

对于如何从SM2的pfx证书文件中解析公钥和私钥,并从二次加密的密文中解密 - 旧信 - 博客园 (cnblogs.com)

GitHub - ZZMarquis/gmhelper: 基于BC库:国密SM2/SM3/SM4算法简单封装;实现SM2 X509v3证书的签发;实现SM2 pfx证书的签发

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/363197
推荐阅读
相关标签
  

闽ICP备14008679号