当前位置:   article > 正文

实现Java与前端之间国密算法加解密与签名_doverifysignature

doverifysignature

问题

开发中发现,我们采用Java或者NodeJS的国密SM2加密、解密、签名单边操作等正常,但是通过Nodejs加密或者生成的签名在Java下就不能解密或者不能验签。整个百度都看了,还是没有搞定通过国密算法实现前端加密、签名Java解密验签。没错,看完下面就全部都将明白。

前端部分

  1. 安装国密操作依赖
npm install --save sm-crypto 
  1. 生成sm2公私钥
  1. // 引入sm-crypto
  2. const sm2 = require("sm-crypto").sm2;
  3. // 生成密钥对
  4. let keypair = sm2.generateKeyPairHex();
  5. // 公钥
  6. publicKey = keypair.publicKey;
  7. // 私钥
  8. privateKey = keypair.privateKey;
  1. 签名

注意:由于要能java解密必须配置参数hash是true,true不是默认值。

  1. // 参数介绍(明文,私钥,配置项)
  2. // 由于要能java解密必须配置参数hash是truetrue不是默认值。
  3. sm2.doSignature("asdasd", privateKey, {
  4. hash: true
  5. })
  1. 验签

注意:由于要能java解密必须配置参数hash是true,true不是默认值。

  1. // 参数介绍(明文,签名值,公钥,配置项)
  2. sm2.doVerifySignature("asdasd", "4c31b7d83e5ea9a77bb369be9eb28a418aa3f29b83c6df251abab9d38685a0f3e1f54fb667f6b0901915ea7c662ff7bc439b0f575359aa4a4dbc7e849ce40061", publicKey,
  3. {
  4. hash: true
  5. })
  1. 加密
  1. const msgString = "20201325xjr"
  2. // 加密
  3. sm2.doEncrypt(msgString, publicKey)
  1. 解密
  1. // 解密
  2. sm2.doDecrypt("c278ca67cb5def5b8bed5919d9ce4a8ea29f49d6145d0b6b8acffce81c64de2691d8cf1d888cec20eab11b90c4e3816751afb8e8e42d309decdd81e162085a4c2760ab85c6e938574c005140c4ff6eb57fec03336aef8e179ce41c2119a98809b5a04f40344fa1eadd03d3d6cb1c", privateKey)

后端部分

  1. 引入maven依赖
  1. <dependency>
  2. <groupId>org.bouncycastle</groupId>
  3. <artifactId>bcprov-jdk15on</artifactId>
  4. <version>1.70</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>cn.hutool</groupId>
  8. <artifactId>hutool-all</artifactId>
  9. <version>5.8.16</version>
  10. </dependency>
  1. 生成sm2公私钥
  1. SM2 sm2 = SmUtil.sm2();
  2. String privateKey = HexUtil.encodeHexStr(BCUtil.encodeECPrivateKey(sm2.getPrivateKey()));
  3. String publicKey = HexUtil.encodeHexStr(((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false));
  4. System.out.println(privateKey);
  5. System.out.println(publicKey);
  1. 签名

注意:前端采用C1C3C2模式,DSA编码,并且是16进制字符串,所有这些模式需要配置完成。

  1. /**
  2. * 签名
  3. *
  4. * @param privateKey 私钥
  5. * @param msg 味精
  6. * @return {@link String}
  7. */
  8. public static String signature(String privateKey, String msg) {
  9. return SmUtil.sm2(privateKey, null).usePlainEncoding().setMode(SM2Engine.Mode.C1C3C2).signHex(HexUtil.encodeHexStr(msg));
  10. }
  1. 验签
  1. /**
  2. * 验证签名
  3. *
  4. * @param publicKey 公钥
  5. * @param signHex 十六进制符号
  6. * @param msg 味精
  7. * @return {@link Boolean}
  8. */
  9. public static Boolean doVerifySignature(String publicKey, String signHex, String msg) {
  10. return SmUtil.sm2(null, publicKey).setMode(SM2Engine.Mode.C1C3C2).usePlainEncoding().verify(msg.getBytes(), HexUtil.decodeHex(signHex));
  11. }
  1. 加密

注意:由于Java生成的代码多了04字符串,所以需要截取掉,不然前端没法解密

  1. /**
  2. * 加密
  3. *
  4. * @param publicKey 公钥
  5. * @param data 明文
  6. * @return 密文
  7. */
  8. public static String encrypt(String publicKey, String data) {
  9. return SmUtil.sm2(null, publicKey).encryptHex(data.getBytes(), KeyType.PublicKey)
  10. // 加密后,密文前面会有04,需要去掉
  11. .substring(2);
  12. }
  1. 解密

注意:由于前端解密部分少了04字符串,所以解密是否需要添加

  1. /**
  2. * 解密
  3. *
  4. * @param privateKey 私钥
  5. * @param data 密文
  6. * @return 明文
  7. */
  8. public static String decrypt(String privateKey, String data) {
  9. // 前端加密是没有04的,所以解析的时候要加04
  10. data = "04" + data;
  11. return SmUtil.sm2(privateKey, null).decryptStr(data, KeyType.PrivateKey);
  12. }

总结

跨语言间不能加解密和验证签名,主要问题还是Nodejs和JAVA在SM2算法实现上默认配置导致的问题。

  1. 前端
  1. // npm install --save sm-crypto
  2. const sm2 = require("sm-crypto").sm2;
  3. // let keypair = sm2.generateKeyPairHex();
  4. // publicKey = keypair.publicKey; // 公钥
  5. // privateKey = keypair.privateKey; // 私钥
  6. publicKey = '04164e5372cf8a44d091780ccacde2ed3b7b1199285d004261a2dc8f9ce893d79001f348cd8feaeeacb883c703bc9dca8f215ba6bd3a20b6169908d3a902e030ad'; // 公钥
  7. privateKey = '7f054f0a7bd3b03199646d7195887ee48dda2ed9eb2b579f4acd13c9fd788872'; // 私钥
  8. // 签名
  9. const sign = sm2.doSignature("asdasd", privateKey, {
  10. hash: true
  11. })
  12. console.log(sign)
  13. // 验签
  14. console.log(sm2.doVerifySignature("asdasd", "4c31b7d83e5ea9a77bb369be9eb28a418aa3f29b83c6df251abab9d38685a0f3e1f54fb667f6b0901915ea7c662ff7bc439b0f575359aa4a4dbc7e849ce40061", publicKey,
  15. {
  16. hash: true
  17. }));
  18. const msgString = "20201325xjr"
  19. // 加密
  20. console.log(sm2.doEncrypt(msgString, publicKey))
  21. // 解密
  22. console.log(sm2.doDecrypt("c278ca67cb5def5b8bed5919d9ce4a8ea29f49d6145d0b6b8acffce81c64de2691d8cf1d888cec20eab11b90c4e3816751afb8e8e42d309decdd81e162085a4c2760ab85c6e938574c005140c4ff6eb57fec03336aef8e179ce41c2119a98809b5a04f40344fa1eadd03d3d6cb1c", privateKey))
  1. 后端
  • 工具类
  1. import cn.hutool.core.util.HexUtil;
  2. import cn.hutool.crypto.SmUtil;
  3. import cn.hutool.crypto.asymmetric.KeyType;
  4. import org.bouncycastle.crypto.engines.SM2Engine;
  5. /**
  6. * 加解密工具类
  7. *
  8. * @author yanliang
  9. */
  10. public class Sm2Util {
  11. /**
  12. * 加密
  13. *
  14. * @param publicKey 公钥
  15. * @param data 明文
  16. * @return 密文
  17. */
  18. public static String encrypt(String publicKey, String data) {
  19. return SmUtil.sm2(null, publicKey).encryptHex(data.getBytes(), KeyType.PublicKey)
  20. // 加密后,密文前面会有04,需要去掉
  21. .substring(2);
  22. }
  23. /**
  24. * 解密
  25. *
  26. * @param privateKey 私钥
  27. * @param data 密文
  28. * @return 明文
  29. */
  30. public static String decrypt(String privateKey, String data) {
  31. // 前端加密是没有04的,所以解析的时候要加04
  32. data = "04" + data;
  33. return SmUtil.sm2(privateKey, null).decryptStr(data, KeyType.PrivateKey);
  34. }
  35. /**
  36. * 验证签名
  37. *
  38. * @param publicKey 公钥
  39. * @param signHex 十六进制符号
  40. * @param msg 味精
  41. * @return {@link Boolean}
  42. */
  43. public static Boolean doVerifySignature(String publicKey, String signHex, String msg) {
  44. return SmUtil.sm2(null, publicKey).setMode(SM2Engine.Mode.C1C3C2).usePlainEncoding().verify(msg.getBytes(), HexUtil.decodeHex(signHex));
  45. }
  46. /**
  47. * 签名
  48. *
  49. * @param privateKey 私钥
  50. * @param msg 味精
  51. * @return {@link String}
  52. */
  53. public static String signature(String privateKey, String msg) {
  54. return SmUtil.sm2(privateKey, null).usePlainEncoding().setMode(SM2Engine.Mode.C1C3C2).signHex(HexUtil.encodeHexStr(msg));
  55. }
  56. }
  • 测试类
  1. public void test() {
  2. 生成公私钥
  3. //SM2 sm2 = SmUtil.sm2();
  4. //String privateKey = HexUtil.encodeHexStr(BCUtil.encodeECPrivateKey(sm2.getPrivateKey()));
  5. //String publicKey = HexUtil.encodeHexStr(((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false));
  6. //System.out.println(privateKey);
  7. //System.out.println(publicKey);
  8. String publicKey = "04164e5372cf8a44d091780ccacde2ed3b7b1199285d004261a2dc8f9ce893d79001f348cd8feaeeacb883c703bc9dca8f215ba6bd3a20b6169908d3a902e030ad";
  9. String privateKey = "7f054f0a7bd3b03199646d7195887ee48dda2ed9eb2b579f4acd13c9fd788872";
  10. // 解密
  11. String decrypt = Sm2Util.decrypt(privateKey, "9d15178ae86c5679735dfbd2e556a64e5bcbc3c7ff9117e95ff9c58b81f71219394dd306509a3e1063d9caf0276f4019c77ff66c4be4bcc9b7ef076431adb14254c67a842773819af812f1d4c4a03d4d091f401adcef97b21fa852d4117e067c496b7a84c2de330a97b1ad");
  12. System.out.println(decrypt);
  13. // 加密
  14. String encryData = Sm2Util.encrypt(publicKey, "asdni你啊后");
  15. System.out.println(encryData);
  16. // 签名
  17. String data = "asdasd";
  18. String sign = Sm2Util.signature(privateKey, data);
  19. System.out.println(sign);
  20. // 验签
  21. sign = "c0899f68fbeaa9569126ec64a9519d0771d2dc26dbb2d1f01d7c4a0ff5a49aa4089302c2604b4ed84c6f8a17ee8fa5efc75ce80e8d959097b79b4861cbbcfc37";
  22. Boolean b = Sm2Util.doVerifySignature(publicKey, sign, data);
  23. System.out.println(b);
  24. }
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/煮酒与君饮/article/detail/787070
推荐阅读
相关标签
  

闽ICP备14008679号