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

如何在Spring Boot中解密CryptoJS生成的加密数据?

Spring Boot适配CryptoJS AES解密方案修正

你的解密逻辑和客户端CryptoJS的实现存在两处核心不匹配,导致解密失败及IV长度错误,以下是问题分析和修正后的完整实现:

问题根源

  1. 密钥推导逻辑错误:客户端使用CryptoJS的PBKDF2算法生成密钥,而你用自定义MD5循环推导,两者完全不兼容。
  2. Hex转字节方法可能失效:如果hexStringToByteArray实现错误,会导致32位的IV十六进制字符串无法正确转为16字节的IV数组,触发长度报错。

修正后的解密代码

以下是完全匹配客户端逻辑的Spring Boot解密实现,使用javax.crypto实现标准PBKDF2密钥推导,并修复Hex转字节逻辑:

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import java.security.spec.KeySpec;
import java.util.Base64;

public class CryptoJsDecryptor {

    // 严格匹配客户端CryptoJS的PBKDF2参数
    private static final int PBKDF2_ITERATIONS = 1000;
    private static final int AES_KEY_SIZE = 256;
    private static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1";
    private static final String AES_TRANSFORMATION = "AES/CBC/PKCS5Padding";

    public static String decrypt(String passphrase, String jsonString) throws Exception {
        JsonObject jsonObject = new Gson().fromJson(jsonString, JsonObject.class);
        String ctBase64 = jsonObject.get("ct").getAsString();
        String ivHex = jsonObject.get("iv").getAsString();
        String saltHex = jsonObject.get("s").getAsString();

        // 将Hex字符串转为字节数组
        byte[] salt = hexStringToByteArray(saltHex);
        byte[] iv = hexStringToByteArray(ivHex);
        byte[] cipherText = Base64.getDecoder().decode(ctBase64);

        // 使用PBKDF2生成密钥,完全对齐客户端逻辑
        SecretKeyFactory factory = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM);
        KeySpec spec = new PBEKeySpec(passphrase.toCharArray(), salt, PBKDF2_ITERATIONS, AES_KEY_SIZE);
        SecretKey secretKey = factory.generateSecret(spec);

        // 初始化AES解密器
        Cipher cipher = Cipher.getInstance(AES_TRANSFORMATION);
        IvParameterSpec ivSpec = new IvParameterSpec(iv);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);

        // 解密并返回明文
        byte[] decryptedBytes = cipher.doFinal(cipherText);
        return new String(decryptedBytes, "UTF-8");
    }

    // 正确的十六进制字符串转字节数组实现
    private static byte[] hexStringToByteArray(String s) {
        int len = s.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
                    + Character.digit(s.charAt(i+1), 16));
        }
        return data;
    }

    // 测试示例
    public static void main(String[] args) throws Exception {
        String publicKey = "S!ZcdNb4XXcw_jXbHQqiFsHp6";
        String encData = "{\"ct\":\"d97K/kt03Inh9wYp90iyNwefnaTwMAeQXTjOwJR+gU0=\",\"iv\":\"4101e6c0938e312952ea24f19306cfb2\",\"s\":\"615cc2b4480e260a\"}";
        String plainText = decrypt(publicKey, encData);
        System.out.println("解密结果: " + plainText);
    }
}

关键细节说明

  • PBKDF2参数对齐:客户端CryptoJS的PBKDF2默认使用SHA-1哈希、1000次迭代、256位密钥,服务端必须严格匹配这些参数才能生成一致的密钥。
  • Hex转字节正确性:修正后的hexStringToByteArray方法能将32位的IV十六进制字符串准确转为16字节的IV数组,彻底解决"Wrong IV length"错误。
  • 填充模式兼容:Java的PKCS5Padding对AES的16字节块加密完全兼容CryptoJS的PKCS7填充,无需额外修改。

内容的提问来源于stack exchange,提问作者Febry Fairuz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 15:47:02