如何解决无法在 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 和加密的有效载荷是相同的。
由于 getAuthTag()
非常简单,而且我相信我正确地使用了它,所以我不知道此时我什至可以改变什么。因此,我还考虑了这是标准库中的错误的可能性很小。但是,我想我会先尝试 Stackoverflow,然后再发布 Github 问题,因为这很可能是我做错了。
在我设置的repo 中,我对代码进行了稍微扩展的描述,并证明了我如何知道什么是有效的。
提前致谢。
更多信息:节点:v14.15.4 Go:go 版本 go1.15.6 darwin/amd64
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。