是否存在与 CryptoJS 中 Jasypt-Library 的 AES256TextEncryptor Class 等效的行为?

Is there a behavioral equivalent to the AES256TextEncryptor Class of the Jasypt-Library in CryptoJS?

作为密码学的新手,我正在尝试使用 CrpytoJS 库重现与 jasypt 库的 AES256TextEncryptor Class 相同的默认行为。这是我的 Java 方法,它基本上接受两个参数 - 我要加密的消息以及我的秘密释义:

private String encryptWithAes256(String messageToBeEncrypted, String encryptorSecret) {
    AES256TextEncryptor encryptor = new AES256TextEncryptor();
    encryptor.setPassword(encryptorSecret);
    return encryptor.encrypt(messageToBeEncrypted);
}

当使用此代码加密 messageToBeEncrypted 时,生成的加密消息没有问题。我发现内部使用 StandardPBEStringEncryptor 作为加密器的 AES256TextEncryptor 似乎默认使用 PBEWithHMACSHA512AndAES_256 算法。

如何使用 CrpytoJS 重现相同的加密行为?当我尝试按照记录的方式使用 CryptoJS 加密消息时 here,结果与我预期的完全不同。

基于 Topaco 的 ,我想出了以下 Java 脚本代码来模仿 Java 代码:

function encryptWithAes256(messageToEncrypt, encryptorKey){
      // Generate random 16 bytes salt
      var salt = CryptoJS.lib.WordArray.random(128/8);
    
      // Derive key
      var key = CryptoJS.PBKDF2(encryptorKey, salt, { keySize: 256/32, iterations: 1000 });
      console.log("derived key: " + key);
    
      // Generate random 16 bytes init vector (iv)
      var iv = CryptoJS.lib.WordArray.random(128/8);
    
      var cipherText = CryptoJS.AES.encrypt(messageToEncrypt, key, {iv: iv});
      console.log("aes encrypted text: "+ salt.toString() + iv.toString() + cipherText.toString());
      }

生成的结果似乎仍然不是预期的那样,因为它的长度是 88 个字符,而 Java 代码生成了 64 个字符长的加密消息。

发布的代码接近要求的结果。以下还有待更正:

  • PBKDF2默认使用SHA1,这意味着必须明确指定SHA512。
  • 必须在二进制级别进行串联,而不是使用十六进制和 Base64 编码数据。

如果这是固定的,可能的实现是:

function encryptWithAes256(messageToEncrypt, encryptorKey){
    // Generate random 16 bytes salt
    var salt = CryptoJS.lib.WordArray.random(128/8);
    
    // Derive key
    var key = CryptoJS.PBKDF2(
        encryptorKey, 
        salt, 
        { keySize: 256/32, iterations: 1000, hasher: CryptoJS.algo.SHA512 }     // Apply SHA512
    );                                                                         
    console.log("derived key:\n" + key);
    
    // Generate random 16 bytes init vector (iv)
    var iv = CryptoJS.lib.WordArray.random(128/8);
    
    // Encrypt
    var cipherText = CryptoJS.AES.encrypt(messageToEncrypt, key, {iv: iv});
    
    // Concatenate
    var encryptedData = salt.clone().concat(iv).concat(cipherText.ciphertext);  // Concatenate on binary level
    var encryptedDataB64 = encryptedData.toString(CryptoJS.enc.Base64);         // Base64 encode the result
    console.log("aes encrypted text:\n", encryptedDataB64.replace(/(.{56})/g,'\n')); 
}

encryptWithAes256('The quick brown fox jumps over the lazy dog', 'my passphrase');
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js"></script>

由于随机盐和 IV 总是生成不同的数据,因此无法通过比较数据来测试实现。相反,必须检查用 CryptoJS 代码生成的数据是否可以用 Jasypt 对应解密:

private static String decryptWithAes256(String ciphertextToBeDecrypted, String encryptorSecret) {
    AES256TextEncryptor encryptor = new AES256TextEncryptor();
    encryptor.setPassword(encryptorSecret);
    return encryptor.decrypt(ciphertextToBeDecrypted); 
}

上面的 CryptoJS 实现确实是这种情况。