nodejs 中的 AES-256-ECB 加密与 php MCrypt 模块不匹配

AES-256-ECB encryption in nodejs does not match php MCrypt module

我正在接收来自外部方的加密消息。他们使用 php 和 mcrypt 通过以下配置进行加密

下图显示配置

在我这边,我正在使用 nodejs 来解密。我有一个 node-mcrypt binding 的工作版本。但我想避免使用原生模块,所以我正在寻找一个纯粹的 javascript 解决方案。

我试过节点的 crypto 但它的 aes-256-ecb 产生了不同的(不可读的)输出

在 nodejs 中使用 MCrypt 绑定的工作代码:

const decryptAES256 = (encrypted: string, password: string): string => {
  try {
    const desEcb = new MCrypt('rijndael-256', 'ecb');
    desEcb.open(md5(password));
    const ciphertext = desEcb.decrypt(new Buffer(encrypted, 'hex'));
    const plain = ciphertext.toString();

    const isUTF8 = plain.split('').every(c => c.charCodeAt(0) <= 256);

    if (!isUTF8) {
      throw new Error('Invalid Input');
    }

    const unpadding = plain
      .split('')
      .filter(c => c.charCodeAt(0))
      .join('');

    return unpadding;
  } catch (ex) {
    console.error('Invalid token');
  }
};

当您声明 "rijndael-256" 时,可能指定了一个非 AES 的 256 位块大小。 AES 有一种块大小:128 位。

这似乎是由 32 二进制字节的加密输出产生的,对于 "thank you" 的输入,输出应该是一个块,所以看起来块大小是 32 字节(256-位)。

  1. 不要使用 mcrypt,它只会导致互操作性问题。
  2. 确保您使用的 AES 可以是 128 位块大小的 rijndael。
  3. 不要混淆密钥大小和块大小。
  4. 如果输入数据不总是块大小的倍数,则必须将填充添加到输入数据],指定填充,PKCS#7(née PKCS#5)填充可能是默认值。 mcrypt 不支持标准填充。如果必须与 mcrypt 互操作,则需要指定无填充并自行执行填充。

在意识到 rijndael 256 不等同于 aes 256(128 版本是)之后,我选择在纯 javascript 中找到一个 rijndael 特定的库,这是一个工作代码:

const Rijndael = require('rijndael-js');

describe('cipher', () => {
  it('should work', () => {
    const text = 'thank you';
    //  + String.fromCharCode(0).repeat(5)
    const key = '94a08da1fecbb6e8b46990538c7b50b2';
    const cipher = new Rijndael(key, 'ecb');
    const ciphertext = cipher.encrypt(text, 256);

    expect(ciphertext.toString('hex')).toBe(
      'a364cb3bb55c2788b25f04ef6867d770771a7d0fdd44462b40233ea76a8bd00d'
    );

    const plaintext = cipher.decrypt(ciphertext, 256);
    const unpadded = plaintext.toString().replace(/\u0000*$/g, '');
    expect(unpadded).toBe(text);
  });
});