跨平台AES 256 GCM Javascript和Elixir
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了跨平台AES 256 GCM Javascript和Elixir相关的知识,希望对你有一定的参考价值。
我一直在尝试使用带有GCM的AES 256在javascript中加密并在Elixir中解密。我从这里和那里借了一些例子,想出了以下内容。
Javascript中的加密
const _crypto = require('crypto');
function encrypt(message, secret) {
// random initialization vector
const iv = _crypto.randomBytes(16);
// extract the auth tag
const cipher = _crypto.createCipheriv('aes-256-gcm', secret, iv);
// encrypt the given text
const encrypted = Buffer.concat([cipher.update(message, 'utf8'), cipher.final()]);
// extract the auth tag
const tag = cipher.getAuthTag();
const encrypted_message = Buffer.concat([iv, tag, encrypted]).toString('base64');
return encrypted_message;
}
const secret = _crypto.randomBytes(32);
encrypt("secret message", secret);
Elixir中的解密
def decrypt(encrypted_message, secret) do
secret_key = :base64.decode(secret)
ciphertext = :base64.decode(encrypted_message)
<<iv::binary-16, tag::binary-16, ciphertext::binary>> = ciphertext
:crypto.block_decrypt(:aes_gcm, secret_key, iv, {"AES256GCM", ciphertext, tag})
end
# secret would be the secret from javascript encoded in base64
decrypt(encrypted_message, secret)
而我在Elixir方面的结果一直是:error
我感觉它与编码和解码有关,但我似乎无法找出哪里出了什么问题。
如果有人能指出我正确的方向将不胜感激。
谢谢!
更新的工作版本
对于打算使用相同语言的人:
Javascript加密
const _crypto = require('crypto');
function encrypt(message, secret) {
// random initialization vector
const iv = _crypto.randomBytes(16);
// extract the auth tag
const cipher = _crypto.createCipheriv('aes-256-gcm', secret, iv);
// add the following line if you want to include "AES256GCM" on the elixir side
// cipher.setAAD(Buffer.from("AES256GCM", 'utf8'));
// encrypt the given text
const encrypted = Buffer.concat([cipher.update(message, 'utf8'), cipher.final()]);
// extract the auth tag
const tag = cipher.getAuthTag();
const encrypted_message = Buffer.concat([iv, tag, encrypted]).toString('base64');
return encrypted_message;
}
const secret = _crypto.randomBytes(32);
encrypt("secret message", secret);
Elixir Decryption
def decrypt(encrypted_message, secret) do
secret_key = :base64.decode(secret)
ciphertext = :base64.decode(encrypted_message)
<<iv::binary-16, tag::binary-16, ciphertext::binary>> = ciphertext
// make sure _AAD is an empty string "" if you didn't set it during encryption
:crypto.block_decrypt(:aes_gcm, secret_key, iv, {_AAD, ciphertext, tag})
// otherwise, you would need to set _AAD to whatever you set during encryption, using "AES256GCM" as example
// Note: AAD (Associated Authenticated Data) can be whatever string you want to my knowledge, just to make sure you have the same in both encryption and decryption process
// :crypto.block_decrypt(:aes_gcm, secret_key, iv, {"AES256GCM", ciphertext, tag})
end
# secret would be the secret from javascript encoded in base64
decrypt(encrypted_message, secret)
答案
这很简单:你的"AES256GCM"
不应该存在(或者null,我不熟悉Erlang)。它表示附加的经过身份验证的数据,并包含在身份验证标记的计算中,显然使其与加密代码生成的身份验证标记不同。
:aes_gcm
已经指定了模式,键大小当然是由secret_key
的大小决定的,所以无论如何这个字符串都是非常不必要的。
以上是关于跨平台AES 256 GCM Javascript和Elixir的主要内容,如果未能解决你的问题,请参考以下文章
为啥带有 GCM 的 AES-256 会在密文大小上增加 16 个字节?
Nodejs AES-256-GCM 通过 webcrypto api 解密加密的客户端消息