#国密sm2,sm4(前台vue,后台java)加解密
2023-03-20 14:42:45 时间
js端加密(使用sm-crypto)
- 引入依赖:
const sm4 = require('sm-crypto').sm4
const sm2 = require('sm-crypto').sm2
- sm2加密:
sm2加密类似RSA,有公钥和私钥,这里前端使用公钥加密,加密有两种模式,适配后端这里改为C1C2C3模式。undefined 需要注意的是,这里的加密结果不能直接返回后台,需要在前面加上04表示公钥未压缩
const cipherMode = 0 // 1 - C1C3C2,0 - C1C2C3,默认为1
sm2Encrypt(data) {
// sm2加密密钥
return '04' + sm2.doEncrypt(data, this.pubkeyHex, cipherMode);
}
- sm4加密:
sm4Encrypt(data, key) {
// sm4加密数据
return sm4.encrypt(data, key);
}
java端解密(使用Hutool工具包,需引入Bouncy Castle库的依赖)
- 引入依赖包
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.66</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcpkix-jdk15on</artifactId>
<version>1.66</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.5.8</version>
</dependency>
- sm2生成密钥
由于js端sm2代码实现使用公钥的q值和私钥的d值作为公私钥,所以直接使用hutool生成密钥是无法加解密的,必须做改写
public static void generateKey() throws NoSuchAlgorithmException {
// 1. bc库原始写法
X9ECParameters x9ECParameters = GMNamedCurves.getByName("sm2p256v1");
ECDomainParameters ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN());
ECKeyPairGenerator ecKeyPairGenerator = new ECKeyPairGenerator();
ecKeyPairGenerator.init(new ECKeyGenerationParameters(ecDomainParameters, SecureRandom.getInstance("SHA1PRNG")));
AsymmetricCipherKeyPair asymmetricCipherKeyPair = ecKeyPairGenerator.generateKeyPair();
//16进制格式的私钥,后端使用
BigInteger privatekey = ((ECPrivateKeyParameters) asymmetricCipherKeyPair.getPrivate()).getD();
String privateKeyHex = privatekey.toString(16);
//16进制格式的公钥,发给前端
ECPoint ecPoint = ((ECPublicKeyParameters) asymmetricCipherKeyPair.getPublic()).getQ();
byte[] encoded = ecPoint.getEncoded(false);
String publicKeyHex = Hex.toHexString(encoded);
System.out.println(privateKeyHex);
System.out.println(publicKeyHex);
// 2. hutool写法
SM2 sm2 = SmUtil.sm2();
String hutoolPrivateKeyHex = HexUtil.encodeHexStr(BCUtil.encodeECPrivateKey(sm2.getPrivateKey()));
String hutoolPublicKeyHex = HexUtil.encodeHexStr(((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false));
System.out.println(hutoolPrivateKeyHex);
System.out.println(hutoolPublicKeyHex);
}
- sm4生成密钥
注意密钥长度必须为128位
SM4 sm4 = new SM4();
SecretKey secretKey = sm4.getSecretKey();
byte[] encoded = secretKey.getEncoded();
String encodeHexStr = HexUtil.encodeHexStr(encoded);
- sm2解密
// JS加密产生的密文
String cipherData = "0477109887984ca6250635e6e30a58d11efe71abd998271808ec611366197698106b128ef699fe7fa09449bb7ca9527d674cc865a93a4e3593770ecd3ab06291aee81f5459b8500c284e5391956a83ddb2a90f298968a97828b0802749d5e5bbaa1c519489d4a37215ae0d5f7ef0b3a9a2e8dc1ce485544397a66923811c2f44a0";
byte[] cipherDataByte = Hex.decode(cipherData);
// 私钥
String privateKey = "9fb1f241314168f56d0bc0a236c3a8d6f60ebf778e4104ce94a6cc27cdd4d178";
// 1. 使用bc库解密
X9ECParameters x9ECParameters = GMNamedCurves.getByName("sm2p256v1");
ECDomainParameters ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN());
ECPrivateKeyParameters privateKeyParameters = new ECPrivateKeyParameters(new BigInteger(privateKey, 16), ecDomainParameters);
SM2Engine sm2Engine = new SM2Engine();
sm2Engine.init(false, privateKeyParameters);
byte[] bytes = sm2Engine.processBlock(cipherDataByte, 0, cipherDataByte.length);
String data = new String(bytes, CharsetUtil.CHARSET_UTF_8);
System.out.println(data);
// 2. 使用hutool解密
SM2 sm2 = new SM2(ECKeyUtil.toSm2PrivateParams(privateKey), null);
sm2.setMode(SM2Engine.Mode.C1C2C3);
sm2.setEncoding(new PlainDSAEncoding());
String decryptStr = sm2.decryptStr(cipherData, KeyType.PrivateKey);
System.out.println(decryptStr);
- sm4解密
这里的key与前端加密使用的key相同
SM4 sm4 = new SM4(HexUtil.decodeHex(key));
String decryptStr = sm4.decryptStr(data);
相关文章
- 深入探讨Java中的异常与错误处理
- 研究学习Kotlin的一些方法
- 数据显示Java热度持续下落,日子屈指可数?
- 2017年5月编程语言排行榜:Java与C语言优势正开始缩小
- Java多线程之内置锁与显示锁
- Java线程池的理论与实践
- 白话阿里巴巴Java开发手册(编程规约)
- 关于Java你不知道的十件事
- Java服务化系统线上应急和技术攻关,你必须掌握的Linux命令
- Java实现高斯模糊和图像的空间卷积
- Java阻塞队列实现原理分析
- NPM使用技巧
- Node.js对Java开发者而言是什么?
- Java反射机制应用实践
- 理解RxJava中的Single和Completable
- 2017年你不能错过的Java类库
- 大规模集群下的Hadoop NameNode
- 从源码解密Spark内存管理
- 2017年3月编程语言排行榜:Swift首次进入前十
- JVM热点技术:Java类的加载机制