微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

无法在 Node.js 中获取 256 位 AES GCM 加密的正确标签

如何解决无法在 Node.js 中获取 256 位 AES GCM 加密的正确标签

我需要编写以下解密函数的反向(加密):

const crypto = require('crypto');

let AESDecrypt = (data,key) => {
  const decoded = Buffer.from(data,'binary');

  const nonce = decoded.slice(0,16);
  const ciphertext = decoded.slice(16,decoded.length - 16);
  const tag = decoded.slice(decoded.length - 16);

  let decipher = crypto.createDecipheriv('aes-256-gcm',key,nonce);
  decipher.setAuthTag(tag)
  decipher.setAutopadding(false);
  try {
    let plaintext = decipher.update(ciphertext,'binary','binary');
    plaintext += decipher.final('binary');
    return Buffer.from(plaintext,'binary');
  } catch (ex) {
    console.log('AES Decrypt Failed. Exception: ',ex);
    throw ex;
  }
}

以上函数允许我按照规范正确解密加密缓冲区:

| Nonce/IV (First 16 bytes) | Ciphertext | Authentication Tag (Last 16 bytes) |

AESDecrypt 之所以这么写(auth 标记为最后 16 个字节)是因为这是 AES 的认标准库实现在 Java 和 Go 中加密数据的方式。我需要能够在 Go、Java 和 Node.js 之间双向解密/加密。 Node.js 中基于 crypto 库的加密不会将 auth 标签放在任何地方,开发人员可以在解密期间如何存储它以传递给 setAuthTag()。在上面的代码中,我将标签直接烘焙到最终的加密缓冲区中。

所以我编写的 AES 加密函数需要满足上述情况(无需修改 AESDecrypt,因为它可以正常工作)并且我有以下代码对我不起作用:

let AESEncrypt = (data,key) => {

  const nonce = 'BfVsfgErXsbfiA00'; // Do not copy paste this line in production code (https://crypto.stackexchange.com/questions/26790/how-bad-it-is-using-the-same-iv-twice-with-aes-gcm)
  const encoded = Buffer.from(data,'binary');

  const cipher = crypto.createCipheriv('aes-256-gcm',nonce);
  try {
    let encrypted = nonce;
    encrypted += cipher.update(encoded,'binary')
    encrypted += cipher.final('binary');
    const tag = cipher.getAuthTag();
    encrypted += tag;
    return Buffer.from(encrypted,'binary');
  } catch (ex) {
    console.log('AES Encrypt Failed. Exception: ',ex);
    throw ex;
  }
}


我知道对 nonce 进行硬编码是不安全的。我通过这种方式可以更轻松地使用二进制文件差异程序(如 vbindiff

)将正确加密的文件与损坏的实现进行比较

我越用不同的方式看待这个问题,这个问题就越让我困惑。

我实际上非常习惯于实现基于 256 位 AES GCM 的加密/解密,并且在 Go 和 Java 中有正常工作的实现。此外,由于某些情况,几个月前我在 Node.js 中实现了 AES 解密。

我知道这是真的,因为我可以在 Node.js 中解密我在 Java 和 Go 中加密的文件。我建立了一个快速存储库,其中包含专为此目的编写的 Go 服务器的源代码实现和损坏的 Node.js 代码

为了让懂 Node.js 但不懂 Go 的人更容易访问,我提供了以下 Go 服务器 Web 界面,用于使用托管在 https://go-aes.voiceit.io/ 的上述算法进行加密和解密。您可以通过在 https://go-aes.voiceit.io/ 加密您选择的文件并使用 decrypt.js 解密该文件来确认我的 Node.js 解密函数工作正常(请查看 README 以了解有关如果您需要确认它正常工作,如何运行它。)


此外,我知道这个问题特别与 AESEncrypt 的以下几行有关:

    const tag = cipher.getAuthTag();
    encrypted += tag;

针对在 Go 和 Node.js 中加密的同一个文件运行 vbindiff文件开始仅在最后 16 个字节(写入 auth 标记的地方)显示差异。换句话说,在 Go 和 Node.js 中,nonce 和加密的有效载荷是相同的。

vbindiff

由于 getAuthTag() 非常简单,而且我相信我正确地使用了它,所以我不知道此时我什至可以改变什么。因此,我还考虑了这是标准库中的错误的可能性很小。但是,我想我会先尝试 Stackoverflow,然后再发布 Github 问题,因为这很可能是我做错了。

在我设置的repo 中,我对代码进行了稍微扩展的描述,并证明了我如何知道什么是有效的。

提前致谢。

更多信息:节点:v14.15.4 Go:go 版本 go1.15.6 darwin/amd64

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。