#javascript #react-native #cryptography #erlang #elixir
#javascript #react-native #криптография #erlang #elixir
Вопрос:
Я пытался зашифровать в Javascript и расшифровать в Elixir, используя AES 256 с помощью GCM. Я позаимствовал несколько примеров здесь и там и придумал следующее.
Шифрование в 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
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)
Ответ №1:
Это очень просто: ваш "AES256GCM"
не должен присутствовать (или null, я не настолько знаком с Erlang). Он представляет дополнительные аутентифицированные данные и включается в вычисление тега аутентификации, что, очевидно, отличает его от тега аутентификации, сгенерированного кодом шифрования.
:aes_gcm
режим уже указан, а размер ключа, конечно, определяется размером secret_key
, поэтому строка в любом случае была бы совершенно ненужной.
Комментарии:
1. Это работает! когда я установил «AES256GCM» в «», и он успешно декодировался. Я думал, что это было там, чтобы соответствовать
aes-256-gcm
на стороне javascript. Большое спасибо!!