Шифрование (aes-128-cbc) не совпадает между python(pycrypto) и nodejs(crypto)
У меня есть этот кусок кода Python, который мне нужно перевести в nodejs. Код Python использует pycrypto из шифрования. На стороне nodejs я использую собственный криптомодуль. Кажется, есть несоответствие между зашифрованными строками.
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex
import json
raw_key = [0x58, 0x86, 0x17, 0x6d, 0x88, 0x7c, 0x9a, 0xa0, 0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x28, 0xa4, 0x5a]
key = str(bytearray(raw_key))
raw_iv = [0x34, 0x2e, 0x17, 0x99, 0x6d, 0x19, 0x3d, 0x28, 0xdd, 0xb3, 0xa2, 0x69, 0x5a, 0x2e, 0x6f, 0x1b]
iv = str(bytearray(raw_iv))
text = json.dumps({ "a": 1, "b": 2 })
cryptor = AES.new(key, AES.MODE_CBC, iv)
length = 16
count = len(text)
add = length - (count % length)
text = text + ('\0' * add)
encrypted = cryptor.encrypt(text);
print b2a_hex(encrypted)
Вышеприведенные выводы кода Python
5c72b1a394654b6dab9ea8fdd90fe56b92141d74cb32ac65ede4d3154801bb57
тогда как приведенный ниже код nodejs
const crypto = require('crypto');
const KEY = Buffer.from([0x58, 0x86, 0x17, 0x6d, 0x88, 0x7c, 0x9a, 0xa0, 0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x28, 0xa4, 0x5a]);
const IV = Buffer.from([0x34, 0x2e, 0x17, 0x99, 0x6d, 0x19, 0x3d, 0x28, 0xdd, 0xb3, 0xa2, 0x69, 0x5a, 0x2e, 0x6f, 0x1b]);
const text = JSON.stringify({ a: 1, b: 2 });
const cipher = crypto.createCipheriv('aes-128-cbc', KEY, IV);
cipher.setAutoPadding(true);
const encrypted = Buffer.concat([cipher.update(text, 'utf-8'), cipher.final()]);
console.log(encrypted.toString('hex'));
выходы
d6a0dbc6df2a1038036e4db985f9ca10
Почему они не совпадают? Я делаю что-то неправильно?
1 ответ
Здесь есть две проблемы:
Автоматическое заполнение узла - заполнение PKCS. В вашем коде Python вместо заполнения используются нулевые байты, что является другим форматом. В документации узла даже явно упоминается отключение автоматического заполнения, чтобы использовать заполнение нулевым байтом.
JSON форматируется немного по-разному между узлом и питоном. в JavaScript
JSON.stringify()
удаляет все ненужные пробелы, тогда как python оставляет некоторые пробелы (например, между элементами в массиве / объекте). Самым простым решением этого, вероятно, будет изменение кода Python для указания явногоseparators
вариант:json.dumps({ "a": 1, "b": 2 }, separators=(',', ':'))
, так как JavaScriptJSON.stringify()
не столь гибок, когда дело доходит до изменения форматирования таким способом.
Приведенный ниже код узла показывает, что, сопоставив выходные данные JSON и используя надлежащие отступы, вы получите тот же шестнадцатеричный вывод, что и python:
const crypto = require('crypto');
const KEY = Buffer.from([0x58, 0x86, 0x17, 0x6d, 0x88, 0x7c, 0x9a, 0xa0, 0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x28, 0xa4, 0x5a]);
const IV = Buffer.from([0x34, 0x2e, 0x17, 0x99, 0x6d, 0x19, 0x3d, 0x28, 0xdd, 0xb3, 0xa2, 0x69, 0x5a, 0x2e, 0x6f, 0x1b]);
var text = '{"a": 1, "b": 2}';
const cipher = crypto.createCipheriv('aes-128-cbc', KEY, IV);
cipher.setAutoPadding(false);
var length = 16;
var count = Buffer.byteLength(text);
var add = length - (count % length);
if (add > 0)
text += '\0'.repeat(add);
const encrypted = Buffer.concat([cipher.update(text, 'utf-8'), cipher.final()]);
console.log(encrypted.toString('hex'));