Java实现的AES加密逻辑迁移至JavaScript结果不匹配如何解决
问题根因分析
你两端加密结果不匹配的核心原因不是IV处理,而是密钥生成逻辑不一致:
- Java侧通过
PBEKeySpec走了PBKDF2密钥派生流程,基于原始密钥、盐、迭代次数65536派生得到256位的AES密钥 - JS侧直接把原始的SECURITY_KEY作为AES密钥使用,完全跳过了PBKDF2派生步骤,这是最核心的差异点。
IV侧的小问题:你用bin2String转0字节数组再用Utf8.parse的方式容易出现编码异常,直接生成对应字节的WordArray更稳妥。
修正后JS代码
默认Java侧ALGORITHM为PBKDF2WithHmacSHA1(如果是SHA256需要对应修改hasher参数):
const crypto = require('crypto-js'); // 对应Java侧的常量定义 const SECURITY_KEY = new Array(21).fill(0); // 21个0字节 const SALT = new Array(6).fill(0); // 6个0字节 const ITERATION_COUNT = 65536; const KEY_SIZE = 256 / 32; // 256位对应CryptoJS的WordArray长度单位 const IV = new Array(16).fill(0); // 16个0字节的IV // 工具函数:字节数组转CryptoJS WordArray function byteArrayToWordArray(byteArray) { const wordArray = []; for (let i = 0; i < byteArray.length; i++) { wordArray[i >>> 2] |= byteArray[i] << (24 - (i % 4) * 8); } return crypto.lib.WordArray.create(wordArray, byteArray.length); } // 1. 走PBKDF2派生AES密钥,和Java逻辑对齐 const password = byteArrayToWordArray(SECURITY_KEY).toString(crypto.enc.Utf8); const saltWordArray = byteArrayToWordArray(SALT); const aesKey = crypto.PBKDF2(password, saltWordArray, { keySize: KEY_SIZE, iterations: ITERATION_COUNT, hasher: crypto.algo.SHA1 // 如果Java侧是PBKDF2WithHmacSHA256则改为crypto.algo.SHA256 }); // 2. 生成IV const ivWordArray = byteArrayToWordArray(IV); // 加密函数 function encrypt(text) { return crypto.AES.encrypt(text, aesKey, { iv: ivWordArray, mode: crypto.mode.CBC, padding: crypto.pad.Pkcs7 }).toString(); } // 解密函数 function decrypt(cipherText) { const decrypted = crypto.AES.decrypt(cipherText, aesKey, { iv: ivWordArray, mode: crypto.mode.CBC, padding: crypto.pad.Pkcs7 }); return decrypted.toString(crypto.enc.Utf8); } // 测试 console.log(encrypt("password11"));
验证注意事项
- 确认Java侧
ALGORITHM的哈希算法,和JS侧PBKDF2的hasher参数保持一致 - 确认Java侧
input.getBytes()的编码,默认如果是UTF-8则和CryptoJS默认行为完全匹配,如果是GBK等其他编码需要对应修改JS侧的明文编码规则 - Java的
PKCS5Padding和CryptoJS的Pkcs7在AES场景下完全兼容,不需要修改填充规则
内容的提问来源于stack exchange,提问作者Leo Chan
相关产品推荐
相关产品推荐

