赞
踩
开发中发现,我们采用Java或者NodeJS的国密SM2加密、解密、签名单边操作等正常,但是通过Nodejs加密或者生成的签名在Java下就不能解密或者不能验签。整个百度都看了,还是没有搞定通过国密算法实现前端加密、签名Java解密验签。没错,看完下面就全部都将明白。
npm install --save sm-crypto
- // 引入sm-crypto
- const sm2 = require("sm-crypto").sm2;
- // 生成密钥对
- let keypair = sm2.generateKeyPairHex();
- // 公钥
- publicKey = keypair.publicKey;
- // 私钥
- privateKey = keypair.privateKey;
注意:由于要能java解密必须配置参数hash是true,true不是默认值。
- // 参数介绍(明文,私钥,配置项)
- // 由于要能java解密必须配置参数hash是true,true不是默认值。
- sm2.doSignature("asdasd", privateKey, {
- hash: true
- })
注意:由于要能java解密必须配置参数hash是true,true不是默认值。
- // 参数介绍(明文,签名值,公钥,配置项)
- sm2.doVerifySignature("asdasd", "4c31b7d83e5ea9a77bb369be9eb28a418aa3f29b83c6df251abab9d38685a0f3e1f54fb667f6b0901915ea7c662ff7bc439b0f575359aa4a4dbc7e849ce40061", publicKey,
- {
- hash: true
- })
- const msgString = "20201325xjr"
-
- // 加密
- sm2.doEncrypt(msgString, publicKey)
- // 解密
- sm2.doDecrypt("c278ca67cb5def5b8bed5919d9ce4a8ea29f49d6145d0b6b8acffce81c64de2691d8cf1d888cec20eab11b90c4e3816751afb8e8e42d309decdd81e162085a4c2760ab85c6e938574c005140c4ff6eb57fec03336aef8e179ce41c2119a98809b5a04f40344fa1eadd03d3d6cb1c", privateKey)
- <dependency>
- <groupId>org.bouncycastle</groupId>
- <artifactId>bcprov-jdk15on</artifactId>
- <version>1.70</version>
- </dependency>
-
- <dependency>
- <groupId>cn.hutool</groupId>
- <artifactId>hutool-all</artifactId>
- <version>5.8.16</version>
- </dependency>
- SM2 sm2 = SmUtil.sm2();
- String privateKey = HexUtil.encodeHexStr(BCUtil.encodeECPrivateKey(sm2.getPrivateKey()));
- String publicKey = HexUtil.encodeHexStr(((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false));
- System.out.println(privateKey);
- System.out.println(publicKey);
注意:前端采用C1C3C2模式,DSA编码,并且是16进制字符串,所有这些模式需要配置完成。
- /**
- * 签名
- *
- * @param privateKey 私钥
- * @param msg 味精
- * @return {@link String}
- */
- public static String signature(String privateKey, String msg) {
- return SmUtil.sm2(privateKey, null).usePlainEncoding().setMode(SM2Engine.Mode.C1C3C2).signHex(HexUtil.encodeHexStr(msg));
- }
- /**
- * 验证签名
- *
- * @param publicKey 公钥
- * @param signHex 十六进制符号
- * @param msg 味精
- * @return {@link Boolean}
- */
- public static Boolean doVerifySignature(String publicKey, String signHex, String msg) {
- return SmUtil.sm2(null, publicKey).setMode(SM2Engine.Mode.C1C3C2).usePlainEncoding().verify(msg.getBytes(), HexUtil.decodeHex(signHex));
- }
注意:由于Java生成的代码多了04字符串,所以需要截取掉,不然前端没法解密
- /**
- * 加密
- *
- * @param publicKey 公钥
- * @param data 明文
- * @return 密文
- */
- public static String encrypt(String publicKey, String data) {
- return SmUtil.sm2(null, publicKey).encryptHex(data.getBytes(), KeyType.PublicKey)
- // 加密后,密文前面会有04,需要去掉
- .substring(2);
- }
注意:由于前端解密部分少了04字符串,所以解密是否需要添加
- /**
- * 解密
- *
- * @param privateKey 私钥
- * @param data 密文
- * @return 明文
- */
- public static String decrypt(String privateKey, String data) {
- // 前端加密是没有04的,所以解析的时候要加04
- data = "04" + data;
- return SmUtil.sm2(privateKey, null).decryptStr(data, KeyType.PrivateKey);
- }
跨语言间不能加解密和验证签名,主要问题还是Nodejs和JAVA在SM2算法实现上默认配置导致的问题。
- // npm install --save sm-crypto
- const sm2 = require("sm-crypto").sm2;
-
- // let keypair = sm2.generateKeyPairHex();
-
- // publicKey = keypair.publicKey; // 公钥
- // privateKey = keypair.privateKey; // 私钥
-
- publicKey = '04164e5372cf8a44d091780ccacde2ed3b7b1199285d004261a2dc8f9ce893d79001f348cd8feaeeacb883c703bc9dca8f215ba6bd3a20b6169908d3a902e030ad'; // 公钥
- privateKey = '7f054f0a7bd3b03199646d7195887ee48dda2ed9eb2b579f4acd13c9fd788872'; // 私钥
-
- // 签名
- const sign = sm2.doSignature("asdasd", privateKey, {
- hash: true
- })
- console.log(sign)
-
- // 验签
- console.log(sm2.doVerifySignature("asdasd", "4c31b7d83e5ea9a77bb369be9eb28a418aa3f29b83c6df251abab9d38685a0f3e1f54fb667f6b0901915ea7c662ff7bc439b0f575359aa4a4dbc7e849ce40061", publicKey,
- {
- hash: true
- }));
-
- const msgString = "20201325xjr"
-
- // 加密
- console.log(sm2.doEncrypt(msgString, publicKey))
-
- // 解密
- console.log(sm2.doDecrypt("c278ca67cb5def5b8bed5919d9ce4a8ea29f49d6145d0b6b8acffce81c64de2691d8cf1d888cec20eab11b90c4e3816751afb8e8e42d309decdd81e162085a4c2760ab85c6e938574c005140c4ff6eb57fec03336aef8e179ce41c2119a98809b5a04f40344fa1eadd03d3d6cb1c", privateKey))
- import cn.hutool.core.util.HexUtil;
- import cn.hutool.crypto.SmUtil;
- import cn.hutool.crypto.asymmetric.KeyType;
- import org.bouncycastle.crypto.engines.SM2Engine;
-
- /**
- * 加解密工具类
- *
- * @author yanliang
- */
- public class Sm2Util {
- /**
- * 加密
- *
- * @param publicKey 公钥
- * @param data 明文
- * @return 密文
- */
- public static String encrypt(String publicKey, String data) {
- return SmUtil.sm2(null, publicKey).encryptHex(data.getBytes(), KeyType.PublicKey)
- // 加密后,密文前面会有04,需要去掉
- .substring(2);
- }
-
- /**
- * 解密
- *
- * @param privateKey 私钥
- * @param data 密文
- * @return 明文
- */
- public static String decrypt(String privateKey, String data) {
- // 前端加密是没有04的,所以解析的时候要加04
- data = "04" + data;
- return SmUtil.sm2(privateKey, null).decryptStr(data, KeyType.PrivateKey);
- }
-
- /**
- * 验证签名
- *
- * @param publicKey 公钥
- * @param signHex 十六进制符号
- * @param msg 味精
- * @return {@link Boolean}
- */
- public static Boolean doVerifySignature(String publicKey, String signHex, String msg) {
- return SmUtil.sm2(null, publicKey).setMode(SM2Engine.Mode.C1C3C2).usePlainEncoding().verify(msg.getBytes(), HexUtil.decodeHex(signHex));
- }
-
-
- /**
- * 签名
- *
- * @param privateKey 私钥
- * @param msg 味精
- * @return {@link String}
- */
- public static String signature(String privateKey, String msg) {
- return SmUtil.sm2(privateKey, null).usePlainEncoding().setMode(SM2Engine.Mode.C1C3C2).signHex(HexUtil.encodeHexStr(msg));
- }
- }
- public void test() {
- 生成公私钥
- //SM2 sm2 = SmUtil.sm2();
- //String privateKey = HexUtil.encodeHexStr(BCUtil.encodeECPrivateKey(sm2.getPrivateKey()));
- //String publicKey = HexUtil.encodeHexStr(((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false));
- //System.out.println(privateKey);
- //System.out.println(publicKey);
-
- String publicKey = "04164e5372cf8a44d091780ccacde2ed3b7b1199285d004261a2dc8f9ce893d79001f348cd8feaeeacb883c703bc9dca8f215ba6bd3a20b6169908d3a902e030ad";
- String privateKey = "7f054f0a7bd3b03199646d7195887ee48dda2ed9eb2b579f4acd13c9fd788872";
-
- // 解密
- String decrypt = Sm2Util.decrypt(privateKey, "9d15178ae86c5679735dfbd2e556a64e5bcbc3c7ff9117e95ff9c58b81f71219394dd306509a3e1063d9caf0276f4019c77ff66c4be4bcc9b7ef076431adb14254c67a842773819af812f1d4c4a03d4d091f401adcef97b21fa852d4117e067c496b7a84c2de330a97b1ad");
- System.out.println(decrypt);
-
- // 加密
- String encryData = Sm2Util.encrypt(publicKey, "asdni你啊后");
- System.out.println(encryData);
-
-
- // 签名
- String data = "asdasd";
- String sign = Sm2Util.signature(privateKey, data);
- System.out.println(sign);
-
- // 验签
- sign = "c0899f68fbeaa9569126ec64a9519d0771d2dc26dbb2d1f01d7c4a0ff5a49aa4089302c2604b4ed84c6f8a17ee8fa5efc75ce80e8d959097b79b4861cbbcfc37";
- Boolean b = Sm2Util.doVerifySignature(publicKey, sign, data);
- System.out.println(b);
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。