在 Forge.js 中解密 CryptoJS AES 数据(带密码)

Jac*_*all 1 javascript encryption cryptography cryptojs

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

CryptoJS.AES.encrypt(data, password).toString();
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

Art*_* B. 5

CryptoJS 支持 OpenSSL 的 EVP_BytesToKey 函数,该函数通过一轮 MD5 从新生成的盐和密码中派生出密钥和 IV。伪造文档页面上有一个示例:

在 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'});
}
Run Code Online (Sandbox Code Playgroud)

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