如何解密用CryptoJS以不合规长度密钥/IV加密的数据?
解决CryptoJS AES-CBC不合规长度密钥的解密问题
核心原因分析
CryptoJS对WordArray类型的密钥/IV遵循以下处理逻辑:
- 解析Base64字符串时自动补全
=以符合Base64规范,解码为原始字节数组; - 将字节数组填充为4字节的倍数(因WordArray以32位Word为存储单元),填充字节为
0x00; - AES根据填充后的字节长度自动选择加密标准:16字节用AES-128,24字节用AES-192,32字节用AES-256。
你提供的示例中,Base64密钥ajMgHj6Vt6vn0dY2Bw解码后为15字节,自动填充1字节0x00后变为16字节的AES-128密钥,IV处理逻辑完全相同。
解密实现方案
1. 密钥/IV预处理函数
还原加密时的密钥/IV处理逻辑,生成合法的密钥和IV:
function getValidKeyIV(base64Str) { // 解析Base64为原始WordArray(自动补全=) let rawWA = CryptoJS.enc.Base64.parse(base64Str); const rawByteLen = rawWA.sigBytes; // 填充为4字节的倍数 const padTo4 = (4 - (rawByteLen % 4)) % 4; if (padTo4 > 0) { rawWA = rawWA.concat(CryptoJS.lib.WordArray.create([0], padTo4)); } // 调整为AES合法密钥长度(16/24/32字节) let validByteLen; if (rawWA.sigBytes <= 16) validByteLen = 16; else if (rawWA.sigBytes <= 24) validByteLen = 24; else validByteLen = 32; // 截断或填充到合法长度 if (rawWA.sigBytes > validByteLen) { rawWA.sigBytes = validByteLen; rawWA.words.length = Math.ceil(validByteLen / 4); } else if (rawWA.sigBytes < validByteLen) { const padNeeded = validByteLen - rawWA.sigBytes; rawWA = rawWA.concat(CryptoJS.lib.WordArray.create([0], padNeeded)); } return rawWA; }
2. 解密函数
使用预处理后的密钥/IV执行解密:
function aesDecryptData(ciphertext) { const base64KeyIV = "ajMgHj6Vt6vn0dY2Bw"; // 替换为你的原始Base64密钥/IV const key = getValidKeyIV(base64KeyIV); const iv = getValidKeyIV(base64KeyIV); const decryptedWA = CryptoJS.AES.decrypt(ciphertext, key, { iv: iv, mode: CryptoJS.mode.CBC, padding: CryptoJS.pad.Pkcs7 // 保持与加密时一致,CryptoJS默认值为Pkcs7 }); return decryptedWA.toString(CryptoJS.enc.Utf8); }
验证方法
用你的加密代码生成测试密文,再用上述解密代码验证:
// 测试加密 const testPlaintext = "Hello World"; const testCiphertext = aesEncryptData(testPlaintext); // 测试解密 const decryptedText = aesDecryptData(testCiphertext); console.log(decryptedText); // 应输出 "Hello World"
注意事项
- 若加密时修改过填充方式(非默认Pkcs7),需同步调整解密配置中的
padding参数; - 确保解密时使用的Base64密钥/IV与加密时完全一致;
- 对于17-21字符的Base64密钥,预处理函数会自动处理补全和长度调整,无需手动修改。
内容的提问来源于stack exchange,提问作者Respino
相关产品推荐
相关产品推荐

