You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java服务端与JS客户端AES加密不一致及IV异常问题求助

问题解决:JS与Java AES加密不一致+Java IV长度异常

问题根源

  1. Java端IV报错:你Java代码里把MD5生成的32位十六进制字符串转成字节数组,得到的是32字节数据,但AES-CBC要求IV必须是16字节(128位),所以直接抛出长度异常。
  2. 加密结果对不上: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 22:39:59