Java服务端与JS客户端AES加密不一致及IV异常问题求助
问题解决:JS与Java AES加密不一致+Java IV长度异常
问题根源
- Java端IV报错:你Java代码里把MD5生成的32位十六进制字符串转成字节数组,得到的是32字节数据,但AES-CBC要求IV必须是16字节(128位),所以直接抛出长度异常。
- 加密结果对不上:JS里CryptoJS.MD5返回的是16字节的原始哈希值(不是字符串),而Java你转成了32位十六进制字符串再转字节,两边IV完全不一样;另外JS输出的是加密结果的十六进制字符串,Java输出的是Base64,格式也不统一。
修复步骤
1. 修正JS代码的语法错误(函数参数未定义)
原JS中encrypt函数没声明参数但调用时传了值,先修正逻辑:
var key = "0123456789ABCDEF"; // 修正encrypt函数的参数定义 function encrypt(value) { // CryptoJS.MD5直接返回16字节的哈希值,用作IV const ivMd5Hash = CryptoJS.MD5(CryptoJS.enc.Utf8.parse(key)); console.log("Hash: " + ivMd5Hash.toString(CryptoJS.enc.Hex)); const cipher = this.cipher(CryptoJS.enc.Utf8.parse(value), CryptoJS.enc.Utf8.parse(key), ivMd5Hash); // 返回十六进制格式的加密结果 return cipher.ciphertext.toString(CryptoJS.enc.Hex); } function cipher(value, key, iv) { const cipher = CryptoJS.AES.encrypt(value, key, { iv: iv, mode: CryptoJS.mode.CBC, keySize: 128, padding: CryptoJS.pad.Pkcs7 }); return cipher; } console.log("Encrypted value: " + encrypt("testuser"));
2. 修改Java代码,对齐JS的加密逻辑
核心修改:用MD5的原始16字节哈希当IV,加密结果也转为十六进制字符串:
import javax.crypto.Cipher; import javax.crypto.spec.IvParameterSpec; import javax.crypto.spec.SecretKeySpec; import java.security.MessageDigest; public class MainClass { private static final String key = "0123456789ABCDEF"; // 存储MD5的原始16字节哈希值 private static byte[] initVectorBytes; public static void main(String[] args) throws Exception { // 获取MD5的原始字节数组(16字节) initVectorBytes = md5Bytes(key); // 打印十六进制格式哈希,和JS控制台输出对齐 System.out.println("HASH: " + bytesToHex(initVectorBytes)); System.out.println("Encrypted value: " + encrypt("testuser")); } public static String encrypt(String value) { try { // 使用16字节的原始MD5哈希作为IV IvParameterSpec iv = new IvParameterSpec(initVectorBytes); SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES"); // AES场景下PKCS5Padding和PKCS7Padding逻辑等价,无需修改 Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING"); cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv); byte[] encrypted = cipher.doFinal(value.getBytes("UTF-8")); // 将加密结果转为十六进制字符串,和JS输出格式一致 return bytesToHex(encrypted); } catch (Exception ex) { ex.printStackTrace(); } return null; } // 获取MD5的原始字节数组,直接返回16字节数据 public static byte[] md5Bytes(String str) { MessageDigest messageDigest = null; try { messageDigest = MessageDigest.getInstance("MD5"); messageDigest.reset(); messageDigest.update(str.getBytes("UTF-8")); } catch (Exception e) { e.printStackTrace(); System.exit(-1); } return messageDigest.digest(); } // 字节数组转十六进制的工具方法 public static String bytesToHex(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { sb.append(String.format("%02x", b)); } return sb.toString(); } }
修复后效果
- Java端不再抛出IV长度异常,使用的是标准16字节IV
- JS与Java的加密结果完全一致,均为
fc88ab1f7821b9f8c5b46ab1d41250a2
额外提醒
生产环境不要使用固定IV!AES-CBC模式下,每次加密都应该生成随机IV,将IV与加密结果一起传输给服务端,服务端用该IV解密,这样能大幅提升加密安全性。
内容的提问来源于stack exchange,提问作者vicinl
相关产品推荐
相关产品推荐

