参考博客:前端vue使用sm-crypto进行国密sm4加密

遇到的问题,后端是java,通过sm4加解密给前端,发现前端无法解密,并且被告知前端必须是32位字符长度的密钥

但是java这边密钥是16位,如果使用32位长度密钥就导致报错!

后面发现了这个博客,尝试使用这个方法,成功!

加解密插件 (前端)

"dependencies": {
"sm-crypto": "^0.3.13",
},

SM4

SM4-ECB

     getData() {
let msg = "{\"token\":\"token\",\"username\":\"username\",\"phoneNo\":\"phoneNo\"}" ;
let key = "uRiYC0rz2ehnwXM8";

let encryData = this.encryptSM4(msg,key,key);
console.log('加密:', encryData);

let decryData = this.decryptSM4(encryData,key,key);
console.log('解密:', decryData);

},
// 解密SM4
decryptSM4 (val,key,iv){
// 导入 sm-crypto 库(如果在浏览器中,请直接使用全局对象 `smCrypto`)
const sm4 = smcrypto.sm4;

const plaintext = this.base64ToByteArray(val);
// 创建 TextEncoder 实例
const textEncoder = new TextEncoder();
// 将 UTF-8 字符串转换为字节数组
// iv = textEncoder.encode(iv);
key = textEncoder.encode(key);
// 2. 使用 CBC 模式和 PKCS7 填充进行解密
const decryptedData = sm4.decrypt(plaintext, key);

return decryptedData;
},
// 加密SM4
encryptSM4 (val,key,iv){
// 导入 sm-crypto 库(如果在浏览器中,请直接使用全局对象 `smCrypto`)
const sm4 = smcrypto.sm4;
// 明文
let plaintext = val;

// 创建 TextEncoder 实例
const textEncoder = new TextEncoder();
// 将 UTF-8 字符串转换为字节数组
// iv = textEncoder.encode(iv);
key = textEncoder.encode(key);
// 使用 CBC 模式和 PKCS7 填充进行加密

let encryptedData = sm4.encrypt(plaintext, key);

encryptedData = this.hexToBase64(encryptedData);

return encryptedData;
},
base64ToByteArray(base64String) {
// 1. Base64 转 二进制字符串
const binaryString = Buffer.from(base64String, 'base64').toString('binary');

// 2. 二进制字符串 转 字节数组
const byteArray = [];
for (let i = 0; i < binaryString.length; i++) {
byteArray.push(binaryString.charCodeAt(i)); // 获取字符的 ASCII 值
}

return byteArray;
},
removePadding(decryptedText) {
const paddingLength = decryptedText.charCodeAt(decryptedText.length - 1);
return decryptedText.slice(0, decryptedText.length - paddingLength);
},
hexToBase64(hexStr) {
const bytes = new Uint8Array(hexStr.match(/[\da-f]{2}/gi).map(h => parseInt(h, 16))); // 每两个十六进制字符解析为一个字节
return btoa(String.fromCharCode(...bytes)); // 转换为 Base64
},

SM4-CBC + IV


getData() {
let msg = "{\n" +
" \"token\":\"token\",\n" +
" \"username\":\"username\",\n" +
" \"phoneNo\":\"phoneNo\"\n" +
" }";
let key = "uRiYC0rz2ehnwXM8";

let encryData = this.encryptSM4(msg,key,key);
console.log('加密:', encryData);

let decryData = this.decryptSM4(encryData,key,key);
console.log('解密:', decryData);

},
// 解密SM4
decryptSM4 (val,key,iv){
// 导入 sm-crypto 库(如果在浏览器中,请直接使用全局对象 `smCrypto`)
const sm4 = smcrypto.sm4;

const plaintext = this.base64ToByteArray(val);
// 创建 TextEncoder 实例
const textEncoder = new TextEncoder();
// 将 UTF-8 字符串转换为字节数组
iv = textEncoder.encode(iv);
key = textEncoder.encode(key);
// 2. 使用 CBC 模式和 PKCS7 填充进行解密
const decryptedData = sm4.decrypt(plaintext, key, {
mode: 'cbc', // CBC 模式
iv: iv, // 初始向量
padding: 'pkcs7' // 填充模式:PKCS7
});
return this.removePadding(decryptedData);
},
// 加密SM4
encryptSM4 (val,key,iv){
// 导入 sm-crypto 库(如果在浏览器中,请直接使用全局对象 `smCrypto`)
const sm4 = smcrypto.sm4;
// 明文
let plaintext = val;

// 创建 TextEncoder 实例
const textEncoder = new TextEncoder();
// 将 UTF-8 字符串转换为字节数组
iv = textEncoder.encode(iv);
key = textEncoder.encode(key);
// 使用 CBC 模式和 PKCS7 填充进行加密

let encryptedData = sm4.encrypt(plaintext, key, {
mode: 'cbc', // CBC 模式
iv: iv, // 初始向量
});

encryptedData = this.hexToBase64(encryptedData);

return encryptedData;
},
base64ToByteArray(base64String) {
// 1. Base64 转 二进制字符串
const binaryString = Buffer.from(base64String, 'base64').toString('binary');

// 2. 二进制字符串 转 字节数组
const byteArray = [];
for (let i = 0; i < binaryString.length; i++) {
byteArray.push(binaryString.charCodeAt(i)); // 获取字符的 ASCII 值
}

return byteArray;
},
removePadding(decryptedText) {
const paddingLength = decryptedText.charCodeAt(decryptedText.length - 1);
return decryptedText.slice(0, decryptedText.length - paddingLength);
},
hexToBase64(hexStr) {
const bytes = new Uint8Array(hexStr.match(/[\da-f]{2}/gi).map(h => parseInt(h, 16))); // 每两个十六进制字符解析为一个字节
return btoa(String.fromCharCode(...bytes)); // 转换为 Base64
},

其他

比如通过java后端加密后字符串,我一般在在线平台上测试下,在线平台上加解密过了,基本上前端这边按道理来说也OK!

在线国密SM4加解密