sm2加解密(js与java互通)_sm2在线解密
文章目录
工具
在线sm2测试工具(互通)
该在线工具采用的后端加解密,具体加解密过程未知,但本方案与之互通测试成功。
https://tool.hiofd.com/sm2-key-gen/
https://tool.hiofd.com/sm2-encrypt-online/
https://tool.hiofd.com/sm2-decrypt-online/
重点提醒
js解密时hex密文前缀不要加04,java解密时hex密文前缀要加04
SM2 密文中的 04 前缀含义
在 SM2 椭圆曲线加密算法中,密文通常采用 ASN.1 编码格式或简单拼接格式。其中,04 是一个关键的前缀标识符,用于表示非压缩形式的椭圆曲线点坐标。
更具体的说明直接问ai吧,就是不同加解密算法库对密文的处理方式不太一致,本文档记录的js库默认密文不包含04前缀,java库默认密文包含04前缀,因此需要调用者专门处理密文前缀04。
依赖
js端依赖:
nodejs nodejs ^14.21.3 || xxx
组件地址:
https://www.npmjs.com/package/sm-crypto-v2
安装命令:
npm install --save sm-crypto-v2
或者
组件地址:
https://www.npmjs.com/package/sm-crypto
安装命令:
npm install --save sm-crypto
纯js --其实还是sm-crypto
项目地址:
https://github.com/JuneAndGreen/sm-crypto
简要描述:
code里边有dist文件,将sm2.js下载并引入html,使用window.sm2调用加解密
java端依赖
<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.8.22</version></dependency><dependency> <groupId>org.bouncycastle</groupId> <artifactId>bcprov-jdk15on</artifactId> <version>1.70</version></dependency><dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.14</version></dependency>
代码
nodejs加解密
<template> <div></div></template><script>// import {sm2} from \'sm-crypto\'import {sm2} from \'sm-crypto-v2\'export default { name: \'App\', data(){ return { msgString: \"你是谁你好吗你作甚?\",//明文 cipherMode: 1,//1 - C1C3C2,0 - C1C2C3,默认为1 keypair: {},//秘钥对象 publicKey: \"\",// 未压缩的公钥 compressedPublicKey: \"\",//压缩后的公钥 privateKey: \"\",//私钥 encryptData: \"\",//密文 decryptData: \"\",//解密后文本 } }, mounted() { // 测试秘钥的生成 this.keyTest(); // 测试字符串加解密 this.stringTest(); // 测试解密java端加密后的数据(互通测试) this.decryptFromJava(); }, methods:{ keyTest() { this.keypair = sm2.generateKeyPairHex() this.publicKey = this.keypair.publicKey // 公钥 this.privateKey = this.keypair.privateKey // 私钥 console.log(\"publicKey=\"+this.publicKey) console.log(\"privateKey=\"+this.privateKey) // 默认生成公钥 130 位太长,可以压缩公钥到 66 位 this.compressedPublicKey = sm2.compressPublicKeyHex(this.publicKey) // compressedPublicKey 和 publicKey 等价 sm2.comparePublicKeyHex(this.publicKey, this.compressedPublicKey) // 判断公钥是否等价 // 自定义随机数,参数会直接透传给 BigInt 构造器 // 注意:开发者使用自定义随机数,需要自行确保传入的随机数符合密码学安全 this.keypair2 = sm2.generateKeyPairHex(\'123123123123123\') // 初始化随机数池,在某些场景下可能会用到 sm2.initRNGPool() // 验证公钥 sm2.verifyPublicKey(this.publicKey) // 验证公钥 sm2.verifyPublicKey(this.compressedPublicKey) }, stringTest(){ this.cipherMode = 1 // 支持使用 asn1 对加密结果进行编码,在 options 参数中传入 { asn1: true } 即可,默认不开启 this.encryptData = sm2.doEncrypt(this.msgString, this.publicKey, this.cipherMode, { asn1: false }) // 加密结果 console.log(\"encryptData=\"+this.encryptData) // 支持使用 asn1 对密文进行解码再解密,在 options 参数中传入 { asn1: true } 即可,默认不开启 this.decryptData = sm2.doDecrypt(this.encryptData, this.privateKey, this.cipherMode, { asn1: false }) // 解密结果 console.log(\"stringTestResult=\"+(this.msgString == this.decryptData)) }, decryptFromJava(){ this.cipherMode = 1 this.msgString = \"123\"; // 如果java端密文前缀为04 需要去掉 04 前缀 this.encryptData = \'e4c4ff0aff2a4a880abbdd9c9eb7b31d718fd8073b984da30aab5575c23828bc04433fd94a2ea2cd798f232845329ae05b2044c76e8fa089bfe277adec307b13a31d8702a29e15e59f1a9817ef797584dd780bff23df57e54e1aa6032d9fb2c560472b\'; this.privateKey = \"25bb46fa7c5a25c7439153b63fe3e7b5a67feaf5633c830de55e51615ffef530\"; this.decryptData = sm2.doDecrypt(this.encryptData, this.privateKey, this.cipherMode, { asn1: false }) // 解密结果 console.log(\"decryptFromJavaResult=\"+(this.msgString == this.decryptData)) } }}</script>
纯js端加解密
<html><body><h1>hello word!!!</h1><p>this is a html page</p><script src=\"./js/sm2.js\" type=\"module\"></script><script type=\"module\">let sm2 = window.sm2;let unCompressedPublicKeylet compressedPublicKeylet privateKey const cipherMode = 1 // 1 - C1C3C2,0 - C1C2C3const msgString = \'absasdagfadgadsfdfdsf\'// 生成密钥对let keypair = sm2.generateKeyPairHex()unCompressedPublicKey = keypair.publicKeyprivateKey = keypair.privateKeycompressedPublicKey = sm2.compressPublicKeyHex(unCompressedPublicKey) console.error(\"msgString = \"+msgString) console.error(\"unCompressedPublicKey = \"+unCompressedPublicKey) console.error(\"compressedPublicKey = \"+compressedPublicKey) console.error(\"privateKey = \"+privateKey)for (const publicKey of [unCompressedPublicKey, compressedPublicKey]) {let encryptData = sm2.doEncrypt(msgString, publicKey, cipherMode)console.error(\"encryptData = \"+encryptData)let decryptData = sm2.doDecrypt(encryptData, privateKey, cipherMode)console.error(decryptData === msgString)}</script></body></html>
java端加解密
SM2Utils.java 使用hutool与bouncycastle 生成sm2私钥与公钥
import cn.hutool.core.util.HexUtil;import cn.hutool.crypto.BCUtil;import cn.hutool.crypto.asymmetric.SM2;import lombok.extern.slf4j.Slf4j;import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;import org.bouncycastle.jce.provider.BouncyCastleProvider;import org.bouncycastle.math.ec.ECPoint;import java.math.BigInteger;import java.util.HashMap;import java.util.Map;@Slf4jpublic class SM2Utils {static final BouncyCastleProvider bc = new BouncyCastleProvider();public static Map<String,String> generateKey(){Map<String,String> map = new HashMap<>();SM2 sm2=new SM2();BCECPrivateKey privateKey = (BCECPrivateKey) (sm2.getPrivateKey());BigInteger d = privateKey.getD();BCECPublicKey publicKey = (BCECPublicKey) sm2.getPublicKey();ECPoint q = publicKey.getQ();//d.toByteArray() = BCUtil.encodeECPrivateKey(privateKey)String hutoolPrivateKeyHex = HexUtil.encodeHexStr(d.toByteArray());//q.getEncoded(false) = BCUtil.encodeECPublicKey(publicKey,false);String hutoolPublicKeyHex = HexUtil.encodeHexStr(q.getEncoded(false));map.put(\"privateKeyHex\",hutoolPrivateKeyHex);map.put(\"publicKeyHex\",hutoolPublicKeyHex);return map;}}
EncryptionApplicationTests sm2的加解密测试
import cn.hutool.core.util.HexUtil;import cn.hutool.crypto.SmUtil;import cn.hutool.crypto.asymmetric.KeyType;import cn.hutool.crypto.asymmetric.SM2;import com.insect.encryption.demos.web.SM2Utils;import org.junit.jupiter.api.Test;import org.springframework.boot.test.context.SpringBootTest;import java.util.Map;@SpringBootTestclass EncryptionApplicationTests {@Testvoid encryptAndDecrypt() {Map<String, String> keyMap = SM2Utils.generateKey();String privateKeyHex = keyMap.get(\"privateKeyHex\");String publicKeyHex = keyMap.get(\"publicKeyHex\");System.err.println(privateKeyHex);System.err.println(publicKeyHex);String msg = \"123\";SM2 sm2 = SmUtil.sm2(privateKeyHex, publicKeyHex);byte[] encrypt = sm2.encrypt(msg, KeyType.PublicKey);byte[] decrypt = sm2.decrypt(encrypt, KeyType.PrivateKey);String encryptString = HexUtil.encodeHexStr(encrypt);System.err.println(encryptString);String decryptString = new String(decrypt);System.err.println(decryptString);System.err.println(msg.equals(decryptString));}@Testvoid decryptFromJs() {String encryptHexString = \"04\"+\"29c19b68f3abcefd2219572e041d40bed954d561ae33d12fc7e3870246028da65c4167aa271a292d2f45b0b8df13aba29e83190862d80eada5c30bbd5d982c57b17a8eb1d956005947a7eecf1fe6d37e60d54ed6f6e4feef00e5192dc2f2ad00d43290a3c900c4a20dfe7223169ea48724a11a1eb13522f6bbb0c20ae5a5\";String privateKeyHex = \"9cdd0d4e7264d998eaa3de8b48ee29da8b4f9eafc04786f700eeb5e6045a26fd\";String publicKeyHex = \"04e841369b0d9858a384a18af7bffe0f6a1e794942134d214b626f4fad9efcb767801e220a01e9e1a36a3ae91ab1cc81f77cdfa52c98ce16764bce1f1280dcda42\";String msg = \"你是谁你好吗你作甚?\";SM2 sm2 = SmUtil.sm2(privateKeyHex, publicKeyHex);byte[] encrypt = sm2.encrypt(msg, KeyType.PublicKey);byte[] decrypt = sm2.decrypt(HexUtil.decodeHex(encryptHexString), KeyType.PrivateKey);String encryptString = HexUtil.encodeHexStr(encrypt);// 两次加密结果是不一致的System.err.println(encryptString.equals(encryptHexString));String decryptString = new String(decrypt);System.err.println(decryptString);System.err.println(msg.equals(decryptString));}