参考博客:前端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加解密