Reputation: 21
I have got this piece of python code which I need to translate into nodejs. The python code uses pycrypto from encryption. On the nodejs side, I am using the native crypto module. There seems to be a mismatch between the encrypted strings.
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)
The above python code outputs
5c72b1a394654b6dab9ea8fdd90fe56b92141d74cb32ac65ede4d3154801bb57
whereas the below nodejs code
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'));
outputs
d6a0dbc6df2a1038036e4db985f9ca10
Why don't they match? Am I doing something wrong?
Upvotes: 1
Views: 1058
Reputation: 106746
There are two issues here:
Node's automatic padding is PKCS padding. Your python code is using null bytes for padding instead, which is a different format. The node documentation even explicitly mentions disabling auto padding in order to use null byte padding.
The JSON is formatted slightly differently between node and python. Javascript's JSON.stringify()
removes all unnecessary whitespace, whereas python leaves some whitespace (e.g. between elements in an array/object). The easiest solution to this will probably be to change the python code to specify an explicit separators
option: json.dumps({ "a": 1, "b": 2 }, separators=(',', ':'))
, since the javascript's JSON.stringify()
isn't as flexible when it comes to changing the formatting in this way.
The node code below shows that by matching the JSON output and using the proper padding, you will get the same hex output as 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'));
Upvotes: 2