Node.js解密Java AES密文报wrong final block length错误
报错核心信息
Error: error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length
错误产生原因
报错是Java加密端与Node.js解密端的逻辑、参数完全不匹配导致,核心问题有4个:
- 算法与密钥长度不匹配:Java端取SHA-256哈希结果的前16字节作为AES密钥,16字节对应AES-128算法;但Node端错误使用了
aes-256-ecb算法,该算法要求32字节长度密钥,参数完全不匹配。另外Java中Cipher.getInstance("AES")默认使用AES/ECB/PKCS5Padding工作模式,Node端ECB模式默认使用PKCS7填充,二者本身兼容,但必须匹配密钥长度。 - 密钥截取逻辑无效:Node端虽然循环取了哈希值的前16字节存入key数组,但后续生成keyBuffer时直接传入了完整32字节的SHA-256结果,根本没有使用截取后的16字节密钥,密钥值和加密端完全不一致。
- 密文解码方式错误:Java端使用URL安全Base64对密文做编码输出,但Node端错误将密文按十六进制(hex)格式转成Buffer,解码得到的二进制密文完全错误,长度不符合AES块对齐要求,直接触发块长度错误。
- 废弃API使用风险:Node端使用的
new Buffer()构造方法已经废弃,在高版本Node.js中会出现不可预期的类型转换问题。
修复方案
1. Java端优化(可选,避免默认参数歧义)
显式指定加密算法/模式/填充,不要依赖JDK默认实现,避免不同环境下的行为差异:
byte[] input = "data".getBytes(); MessageDigest md = MessageDigest.getInstance("SHA-256"); byte[] thedigest = md.digest("ENCRYPTION_KEY".getBytes("UTF-8")); // 取前16字节,对应AES-128 SecretKeySpec skc = new SecretKeySpec(Arrays.copyOf(thedigest, 16), "AES"); // 显式指定算法/模式/填充 Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); cipher.init(Cipher.ENCRYPT_MODE, skc); byte[] cipherText = cipher.doFinal(input); // URL安全Base64编码 String encryptData = Base64.getUrlEncoder().encodeToString(cipherText); System.out.println("encryptString:.......... "+encryptData);
2. Node.js解密代码修正
对齐Java端所有逻辑参数:
const crypto = require('crypto'); // 密钥与Java端保持一致 const keyStr = "ENCRYPTION_KEY"; // 替换为Java端实际输出的URL安全Base64密文 const encryptedData = "替换为实际的Java加密输出密文"; // 1. 生成SHA-256哈希,截取前16字节作为AES-128密钥 const hashPwd = crypto.createHash('sha256').update(keyStr, 'utf8').digest(); const keyBuffer = Buffer.from(hashPwd.subarray(0, 16)); // 2. 转换URL安全Base64为标准Base64格式,补全缺失的填充符 let base64Str = encryptedData.replace(/-/g, '+').replace(/_/g, '/'); const padLen = (4 - (base64Str.length % 4)) % 4; base64Str = base64Str.padEnd(base64Str.length + padLen, '='); const cipherTxtBuffer = Buffer.from(base64Str, 'base64'); // 3. 创建AES-128-ECB解密器,ECB模式不需要IV,传null即可 const decipher = crypto.createDecipheriv('aes-128-ecb', keyBuffer, null); // 4. 执行解密 const output = Buffer.concat([decipher.update(cipherTxtBuffer), decipher.final()]); console.log("解密结果:", output.toString('utf8'));
额外注意事项
- ECB模式安全性较低,固定密钥重复加密相同明文会得到相同密文,生产环境建议使用CBC/GCM等更安全的模式,搭配随机IV使用。
- 直接对密钥做SHA-256哈希派生加密密钥的方式安全性不足,生产环境建议使用PBKDF2、Argon2等专业密钥派生算法。
内容的提问来源于stack exchange,提问作者Shik
相关产品推荐
相关产品推荐

