用 CryptoJS 解密 Java AES/CBC/PKCS5Padding

Decrypt Java AES/CBC/PKCS5Padding with CryptoJS

我在使用 Java 加密的 CryptoJS 解密文本时遇到一些问题。解密应该用 AES/CBC/PKCS5Padding 完成。加密的字符串是 base64 编码的,我在尝试解密字符串之前对其进行了解码。

这是 Java 代码的样子:

private static byte[] doAES(int mode, byte[] dataToEncrypt, String secretKey, String salt) throws Exception {
        byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
        IvParameterSpec ivspec = new IvParameterSpec(iv);
        SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
        KeySpec spec = new PBEKeySpec(secretKey.toCharArray(), salt.getBytes(), 65536, 256);
        SecretKey tmp = factory.generateSecret(spec);
        SecretKeySpec secretKeySpec = new SecretKeySpec(tmp.getEncoded(), "AES");
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(mode, secretKeySpec, ivspec);
        
        return cipher.doFinal(dataToEncrypt);
}

这就是我尝试在 CryptoJS 中解密它的方式。 SharedSecretKey既是secretKey又是Java.

中的salt值
let decoded = Buffer.from(encodedString, 'base64')
console.log("Result: " + CryptoJS.AES.decrypt({
  ciphertext: CryptoJS.enc.Hex.parse(decoded.toString().substring(32))
}, CryptoJS.enc.Hex.parse(CryptoJS.SHA1(sharedSecretKey).toString().substring(0,32)),  
  {
    iv: CryptoJS.lib.WordArray.create(Buffer.alloc(16)),
  }).toString(CryptoJS.enc.Utf8))

其中 decoded 是我要解密的解码 Base64 字符串。但是,这不起作用,我收到错误 'Error: Malformed UTF-8 data'。我不确定是否遗漏了什么,非常感谢您的帮助。

在 CryptoJS 代码中,缺少使用 PBKDF2 派生的密钥。 CryptoJS 默认使用 SHA1。
密文可以通过Base64编码后隐式转换成一个CipherParams对象:

var encodedString = "0O15lUg8sE1G0+BjO5N2j8AjVKXV4J+18z5DinbM6tYjoILhL0WDTFWbcTiN+pG/";
var key = CryptoJS.PBKDF2(
  "my passphrase", 
  "my salt", 
  {
    keySize: 256 / 32, 
    iterations: 65536
  }
);
var decryptedData = CryptoJS.AES.decrypt(encodedString, key,  
  {
    iv: CryptoJS.enc.Utf8.parse("[=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=]"),
  }
);

console.log("Result: " + decryptedData.toString(CryptoJS.enc.Utf8));
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>

上面示例中的密文是先前使用发布的 Java 代码生成的。

请注意,静态 IV 是不安全的。 IV 通常是为每次加密随机生成的,并与密文一起传递(通常是串联的)。与盐类似,它是为每次密钥推导随机生成的,并与密文和 IV 一起传递,例如盐|iv|密文。 IV 和 salt 都不是秘密,不需要加密。

另外,编码getBytes(),解码new String()时,需要在Java代码中指定编码方式,否则可能会出现跨平台问题。