【问题标题】:Decrypting CryptoJS AES data (with passphrase) in Forge.js在 Forge.js 中解密 CryptoJS AES 数据(带密码)
【发布时间】:2016-03-25 02:55:13
【问题描述】:

所以我有一段代码用密码加密一个字符串。它使用 CryptoJS AES 加密函数 (CryptoJS.AES.encrypt),看起来像这样...

CryptoJS.AES.encrypt(data, password).toString();

展望未来,我不想使用 CryptoJS,因为它已正式弃用/未维护,而我想使用 Forge.js。我试图通读 GitHub 上的 Forge.js 文档以找到解决方案,但找不到任何使用密码短语而不是手动创建密钥和 IV 的内容。

我查看了https://code.google.com/archive/p/crypto-js/ 的 CryptoJS 存档,似乎如果 encrypt 函数传递了一个字符串作为第二个参数(密钥),则它被用作派生密钥和 IV 的密码。但它没有详细说明它是如何做到这一点的。

似乎base64解码结果给出了一个以Salted__开头的字符串,然后是一个逗号,然后是二进制文本的加密blob,我什至不确定如何将“盐”传递给Forge。

我将如何仅使用 Forge.js 解密这些数据?

【问题讨论】:

    标签: javascript encryption cryptography cryptojs


    【解决方案1】:

    CryptoJS 支持 OpenSSL 的 EVP_BytesToKey 函数,该函数通过一轮 MD5 从新生成的盐和密码中派生出密钥和 IV。 forge documentation page上有一个例子:

    在node.js中使用forge来匹配openssl的“enc”命令行工具 (注意: OpenSSL“enc”使用带有自定义密钥的非标准文件格式 推导函数和固定的迭代计数 1,其中一些 考虑不如 OpenPGP/GnuPG 等替代方案安全):

    var forge = require('node-forge');
    var fs = require('fs');
    
    // openssl enc -des3 -in input.txt -out input.enc
    function encrypt(password) {
      var input = fs.readFileSync('input.txt', {encoding: 'binary'});
    
      // 3DES key and IV sizes
      var keySize = 24;
      var ivSize = 8;
    
      // get derived bytes
      // Notes:
      // 1. If using an alternative hash (eg: "-md sha1") pass
      //   "forge.md.sha1.create()" as the final parameter.
      // 2. If using "-nosalt", set salt to null.
      var salt = forge.random.getBytesSync(8);
      // var md = forge.md.sha1.create(); // "-md sha1"
      var derivedBytes = forge.pbe.opensslDeriveBytes(
        password, salt, keySize + ivSize/*, md*/);
      var buffer = forge.util.createBuffer(derivedBytes);
      var key = buffer.getBytes(keySize);
      var iv = buffer.getBytes(ivSize);
    
      var cipher = forge.cipher.createCipher('3DES-CBC', key);
      cipher.start({iv: iv});
      cipher.update(forge.util.createBuffer(input, 'binary'));
      cipher.finish();
    
      var output = forge.util.createBuffer();
    
      // if using a salt, prepend this to the output:
      if(salt !== null) {
        output.putBytes('Salted__'); // (add to match openssl tool output)
        output.putBytes(salt);
      }
      output.putBuffer(cipher.output);
    
      fs.writeFileSync('input.enc', output.getBytes(), {encoding: 'binary'});
    }
    
    // openssl enc -d -des3 -in input.enc -out input.dec.txt
    function decrypt(password) {
      var input = fs.readFileSync('input.enc', {encoding: 'binary'});
    
      // parse salt from input
      input = forge.util.createBuffer(input, 'binary');
      // skip "Salted__" (if known to be present)
      input.getBytes('Salted__'.length);
      // read 8-byte salt
      var salt = input.getBytes(8);
    
      // Note: if using "-nosalt", skip above parsing and use
      // var salt = null;
    
      // 3DES key and IV sizes
      var keySize = 24;
      var ivSize = 8;
    
      var derivedBytes = forge.pbe.opensslDeriveBytes(
        password, salt, keySize + ivSize);
      var buffer = forge.util.createBuffer(derivedBytes);
      var key = buffer.getBytes(keySize);
      var iv = buffer.getBytes(ivSize);
    
      var decipher = forge.cipher.createDecipher('3DES-CBC', key);
      decipher.start({iv: iv});
      decipher.update(input);
      var result = decipher.finish(); // check 'result' for true/false
    
      fs.writeFileSync(
        'input.dec.txt', decipher.output.getBytes(), {encoding: 'binary'});
    }
    

    此示例是针对三重 DES 显示的,但它的工作方式与 AES 相同。您只需将 ivSize 更改为 16。

    【讨论】:

    • 我很感激,这就是我的问题的答案。我忽略了能够使用 AES 重用引用的 3DES 示例。
    • 我意识到在尝试了您的建议后我没有回复。也许我遗漏了一些东西,但是简单地将3DES 更改为AES 并将8 更改为16 对于ivSize 不会产生相同的结果。我试图找出问题可能是什么,因为 forge 说它是成功的,但输出完全不同 - 所以我想知道这是否是与编码相关的问题?不太确定。
    • Forge 输出以下字符串...1pÍ0¿UÚ@G4WtCÕ5¸«ñZ¿}Á6©_ͬiñýü¾¸iÔú®ð5ÕÆÉP¹ú)&nQOW»AMب3{~5=O!¼=W²Ò? [...] cryptojs 输出以下...-----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQEAqSFulewpMjRBLhiiorbvWleD5I [...] 我很想将此标记为正确的评论,但右上方的 sn-p现在,我不希望其他人遇到这个问题并遇到同样的问题。
    • 我发现了为什么我遇到了上面提到的问题 - input 是 base64 编码的,所以我在它变成缓冲区之前通过 atob(input) 运行它。谢谢 Artjom!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-08-13
    • 1970-01-01
    • 2014-08-17
    • 1970-01-01
    • 2014-12-16
    • 2016-08-22
    • 1970-01-01
    相关资源
    最近更新 更多