javascript - 使用 CTR 模式对 crypto-js 进行加密并在 Node crypto 上进行解密问题

标签 javascript node.js cryptography cryptojs node-crypto

我正在尝试使用 crypto-js javascript 库加密数据,并尝试使用 Node 加密库在 Nodejs 端解密相同的加密文本。我正在使用 AES 256 加密算法和 CTR 模式,没有填充。我能够正确加密,但 Nodejs 加密模块上的描述不会生成相同的纯文本。

如果我尝试使用相同的 crypto-js 和 Node 加密库进行加密或解密,它工作正常,但 crypto-js 上的加密和 crypto 上的描述无法按预期工作。我试图确认我是否在同一个库中加密和解密,而不是它是否有效,并且它工作得很好。有人可以检查一下我在这里犯了什么错误吗?

请查找以下代码示例。

加密:

var key =  CryptoJS.enc.Hex.parse('F29BA22B55F9B229CC9C250E11FD4384');
var iv  =  CryptoJS.enc.Hex.parse('C160C947CD9FC273');


function encrypt(plainText) {

  return CryptoJS.AES.encrypt(                                               
                                plainText,                                           
                                key,
                                { 
                                    iv: iv,
                                    padding: CryptoJS.pad.NoPadding,
                                    mode:  CryptoJS.mode.CTR
                                }
                              );                             
}

使用 NodeJS crypto 模块解密:

var algorithm = 'aes-256-ctr';
var key = 'F29BA22B55F9B229CC9C250E11FD4384';
var iv = 'C160C947CD9FC273';

var outputEncoding = 'hex';
var inputEncoding = 'hex';

const decipher = crypto.createDecipheriv(algorithm, key, iv);
let decrypted = decipher.update('8df5e11f521cf492437a95', inputEncoding, 'utf8');
decrypted += decipher.final('utf8');

console.log(decrypted);

正如我上面提到的,如果我使用相同的库进行加密和解密,我的 JavaScriptrypo-js 和 NodeJSrypo 模块 session 可以正常工作,但否则就无法工作。请检查以下工作代码。

JavaScript:http://jsfiddle.net/usr_r/2qwt8jsh/2/

NodeJS:https://repl.it/repls/AchingRegalPhp

最佳答案

我认为您的 CryptoJS 代码没有使用 AES-256,因为 key 和 IV 太短,因此它隐式使用 AES-128。如果您从 CryptoJS.AES 对象获取 blockSize ,它对我来说是 4 。这就是说我不太了解 CryptoJS,这可能并不意味着“4 个词”。

为了绕过这种实现的不确定性,最好有一个可以复制的“黄金标准”。 NIST 提供了大量测试向量,其中一些适用于您的CTR mode AES-256 。首先,我从该文档中提取一组(十六进制编码)测试向量:

const key = (
  '603deb1015ca71be2b73aef0857d7781' +
  '1f352c073b6108d72d9810a30914dff4'
)
const ctr = 'f0f1f2f3f4f5f6f7f8f9fafbfcfdff00'

const output = '5a6e699d536119065433863c8f657b94'
const cipher = 'f443e3ca4d62b59aca84e990cacaf5c5'
const plain = 'ae2d8a571e03ac9c9eb76fac45af8e51'

接下来我尝试从 Node's crypto module 恢复这些内容:

const crypto = require('crypto')

function node_crypto(text) {
  const dec = crypto.createDecipheriv(
    'aes-256-ctr',
    Buffer.from(key, 'hex'),
    Buffer.from(ctr, 'hex')
  );
  const out = dec.update(Buffer.from(text, 'hex'))
  return out.toString('hex')
}

现在我可以编写一个简单的测试工具来测试上述内容并将其与该功能一起使用:

const zero = '00'.repeat(16);
function test_crypto(fn) {
  return {
    'zero => output': fn(zero) == output,
    'cipher => plain': fn(cipher) == plain,
    'plain => cipher': fn(plain) == cipher,
  }
}

console.log(test_crypto(node_crypto))

这为我的所有测试提供了true

最后,CryptoJS 的等效代码是:

const CryptoJS = require("crypto-js");

function cryptojs(text) {
  const out = CryptoJS.AES.encrypt(
    CryptoJS.enc.Latin1.parse(Buffer.from(text, 'hex').toString('binary')),
    CryptoJS.enc.Hex.parse(key),
    {
      iv: CryptoJS.enc.Hex.parse(ctr),
      mode:  CryptoJS.mode.CTR,
      padding: CryptoJS.pad.NoPadding,
    }
  );

  return out.ciphertext.toString();
}

console.log(test_crypto(cryptojs))

这也适合我。

需要注意的是,CryptoJS 只是默默地接受 arbitrarily sized keys ,文档说:

CryptoJS supports AES-128, AES-192, and AES-256. It will pick the variant by the size of the key you pass in. If you use a passphrase, then it will generate a 256-bit key.

关于javascript - 使用 CTR 模式对 crypto-js 进行加密并在 Node crypto 上进行解密问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57929210/

相关文章:

javascript - 如何配置 SystemJS 来识别已加载的库(如 jquery)?

javascript - 无法使用 jQuery 删除带有 id 的 div

node.js - Node 路由器无法使用异步等待从 Sequelize 获取数据

c - OpenSSL AES 256 CBC 通过 C 中的 EVP api

cryptography - 字符频率评分操作

Java SecretKeyFactory生成的 key 与输入密码相同

javascript - 如何在javascript中可靠地获取没有后缀的文件名?

javascript - CSS 分离头表技巧 : keep verticall scrollbar on screen and last cell go full width

python - 将一个大的 json 文件拆分成多个小文件

mysql - 如何将参数传递给nodejs中的mysql查询回调