Search code examples
pythonnode.jspycryptocryptojs

getting different results when encoding with python and when encoding with nodejs


i am trying to encode a particular string with python with pycrypto and encode the same string with nodejs with crypto. i am getting different results in both the cases for the same input string

python code:

from Crypto.Cipher import AES
from hashlib import md5
import base64


password = 'aquickbrownfoxjumpsoverthelazydog'
input = 'hello+world'

BLOCK_SIZE = 16

def pad (data):
    pad = BLOCK_SIZE - len(data) % BLOCK_SIZE
    return data + pad * chr(pad)

def unpad (padded):
    pad = ord(padded[-1])
    return padded[:-pad]

def text_encrypt(data, nonce, password):
    m = md5()
    m.update(password)
    key = m.hexdigest()
    m = md5()
    m.update(password + key)
    iv = m.hexdigest()

    data = pad(data)

    aes = AES.new(key, AES.MODE_CBC, iv[:16])

    encrypted = aes.encrypt(data)
    return base64.urlsafe_b64encode(encrypted)

output = text_encrypt(input, "", password)
print output

and the nodejs code is as follows:

var crypto = require('crypto');

var password = 'aquickbrownfoxjumpsoverthelazydog';
var input = 'hello+world';

var encrypt = function (input, password, callback) {
    var m = crypto.createHash('md5');
    m.update(password)
    var key = m.digest('hex');

    m = crypto.createHash('md5');
    m.update(password + key)
    var iv = m.digest('hex');

    var data = new Buffer(input, 'utf8').toString('binary');

    var cipher = crypto.createCipheriv('aes-256-cbc', key, iv.slice(0,16));

    var nodev = process.version.match(/^v(\d+)\.(\d+)/);
    var encrypted;

    if( nodev[1] === '0' && parseInt(nodev[2]) < 10) {
        encrypted = cipher.update(data, 'binary') + cipher.final('binary');
    } else {
        encrypted = cipher.update(data, 'utf8', 'binary') + cipher.final('binary');
    }

    var encoded = new Buffer(encrypted, 'binary').toString('base64');

    callback(encoded);
};

encrypt(input, password, function (encoded) {
    console.log(encoded);
});

the results for both the cases is different but after decryption they both tend to give the same correct result.

what might be the issue here?


Solution

  • You didn't specify what different results are you getting but those two should produce same-ish result. The only difference I see is in the base64 alphabet you're using.

    In Python you're calling base64.urlsafe_b64encode() which differs from the standard Base64 in what characters it uses for values for 62 and 63 (- and _ instead of + and /). To get the same result, either in Python return:

    return base64.b64encode(encrypted)
    

    Or post-process the base64 encoded string in Node.js:

    encoded = encoded.replace(/_/g, '/').replace(/-/g, '+');
    

    All this being said, as I've mentioned in my comment, never derive an IV from your password/key (or anything else deterministic and unchanging). Use a cryptographically secure PRNG for it.