国密SM加密
- 国密SM:国密算法,即国家商用密码算法。是由国家密码管理局认定和公布的密码算法标准及其应用规范,其中部分密码算法已经成为国际标准。如SM系列密码,SM代表商密,即商业密码,是指用于商业的、不涉及国家秘密的密码技术。
后端封装SM2:
原文:SM2国密算法加解密_皮皮的小猪仔的技术博客_51CTO博客
1.1 导入POM依赖
<!-- hutool -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.5</version>
</dependency>
<!-- 加解密依赖包 -->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15to18</artifactId>
<version>1.71</version>
</dependency>
1.2 生成公钥、私钥密钥对
/**
* 生成公钥、私钥,这个保存好,尤其是私钥,切记不可泄漏
*/
public static void generateCommonKey() {
SM2 sm2 = SmUtil.sm2();
// 私钥:这个保存好,切记不要泄漏,真的泄露了就重新生成一下
byte[] privateKey = BCUtil.encodeECPrivateKey(sm2.getPrivateKey());
// 公钥:这个是前后端加密用的,不压缩选择带04的,不带04到时候前端会报错
byte[] publicKey = ((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false);
Console.log("公钥:\n{}", HexUtil.encodeHexStr(publicKey));
Console.log("私钥:\n{}", HexUtil.encodeHexStr(privateKey));
}
1.3 加解密
/**
* sm2明文加密
* PRIVATE_KEY:生成的私钥
* PUBLIC_KEY:生成的公钥
* @param data 加密前的明文
* @return 加密后的密文
*/
public static String encryptData(String data) {
SM2 sm2 = SmUtil.sm2(ECKeyUtil.toSm2PrivateParams(PRIVATE_KEY), ECKeyUtil.toSm2PublicParams(PUBLIC_KEY));
String encryptBcd = sm2.encryptBcd(data, KeyType.PublicKey);
// 这里的处理前端也可以处理,这个就看怎么约定了,其实都无伤大雅
if (StrUtil.isNotBlank(encryptBcd)) {
// 生成的加密密文会带04,因为前端sm-crypto默认的是1-C1C3C2模式,这里需去除04才能正常解密
if (encryptBcd.startsWith("04")) {
encryptBcd = encryptBcd.substring(2);
}
// 前端解密时只能解纯小写形式的16进制数据,这里需要将所有大写字母转化为小写
encryptBcd = encryptBcd.toLowerCase();
}
return encryptBcd;
}
/**
* sm2密文解密
* PRIVATE_KEY:生成的私钥
* PUBLIC_KEY:生成的公钥
* @param encryptData 加密密文
* @return 解密后的明文字符串
*/
public static String decryptData(String encryptData) throws Exception {
if (StrUtil.isBlank(encryptData)) {
throw new RuntimeException("解密串为空,解密失败");
}
SM2 sm2 = SmUtil.sm2(ECKeyUtil.toSm2PrivateParams(PRIVATE_KEY), ECKeyUtil.toSm2PublicParams(PUBLIC_KEY));
// BC库解密时密文开头必须带04,如果没带04则需补齐
if (!encryptData.startsWith("04")) {
encryptData = "04".concat(encryptData);
}
byte[] decryptFromBcd = sm2.decryptFromBcd(encryptData, KeyType.PrivateKey);
if (decryptFromBcd != null && decryptFromBcd.length > 0) {
return StrUtil.utf8Str(decryptFromBcd);
} else {
throw new Exception("密文解密失败");
}
}
前端封装SM2
原文:前端使用国密sm2和sm4进行加解密_js sm4_二七二十七的博客-CSDN博客
SM2加密依赖
npm install --save sm-crypto
或
npm install --save sm-crypto --legacy-peer-deps
- 将sm2的加密解密方法进行封装,文件命名为sm2.ts
// 引入 const sm2 = require('sm-crypto').sm2 const cipherMode = 0 // 1 - C1C3C2,0 - C1C2C3,默认为1 // 后端会生成密钥对 // publicKey:公钥 后端提供 // privateKey:私钥 后端提供 const publicKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" const privateKey = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" // 加密 // value:需要加密的内容 export function encrypt (value) { // 给后端传值时需要在加密的密文前面加04 ,这样后端才能解密正确不报错 return '04' + sm2.doEncrypt(value, publicKey, cipherMode) } // 解密 // value:需要解密的密文 export function decrypt (value) { // 后端传输过来的密文开头的两个字符通常也为04,因此解密时需要删除 return sm2.doDecrypt(value.slice(2, value.length), privateKey, cipherMode) }
使用
// 引入sm2.js,注意文件路径不要出错 import { encrypt, decrypt } from './sm2' // data:需要加密的数据 // encryptData:加密后的密文 // 若有需要则将js对象转换为字符串后进行加密:JSON.stringify(data) const encryptData = encrypt(JSON.stringify(data)) // data:需要解密的密文 // decryptData:解密后的数据 // 若解密结果为json字符串,则可以通过JSON.parse()方法将解密结果转化为json对象 const decryptData = decrypt(data)
SM4
前端封装
-
将sm4的加密解密方法进行封装,文件命名为sm4.js
const SM4 = require("gm-crypt").sm4; const pwdKey = "xxxx"; //密钥 前后端一致,后端提供 let sm4Config = { key: pwdKey, mode: "ecb", // 加密的方式有两种,ecb和cbc两种,看后端如何定义的,cbc需要iv参数,ecb不用 iv: '1234567891011121', // 初始向量,cbc模式的第二个参数,也需要跟后端配置的一致 cipherType: "base64" }; const sm4Util = new SM4(sm4Config); // new一个sm4函数,将上面的sm4Config作为参数传递进去。 /* * 加密工具函数 * @param {String} text 待加密文本 */ export function encrypt(text) { return sm4Util.encrypt(text, pwdKey); } /* * 解密工具函数 * @param {String} text 待解密密文 */ export function decrypt(text) { return sm4Util.decrypt(text, pwdKey); }
使用
// 引入asm4.js,注意文件路径不要出错 import { encrypt,decrypt } from "./sm4" // data:需要加密的数据 // encryptData:加密后的密文 // 若有需要则将js对象转换为字符串后进行加密:JSON.stringify(data) const encryptData = encrypt(JSON.stringify(data)) // data:需要解密的密文 // decryptData:解密后的数据 // 若解密结果为json字符串,则可以通过JSON.parse()方法将解密结果转化为json对象 const decryptData = decrypt(data)