-1

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?

Ayush
  • 57
  • 2
  • 11
  • I'll have some time later to look at your issue if you don't get your answer, but at first glance a suggestion - using a non-random IV is a **very, very bad idea**. The key should be based on your _password_ the IV should always be a cryptographic random number. You can see a Python example that demonstrates how it should be performed in [this answer](https://stackoverflow.com/a/44212550/7553525). – zwer May 18 '18 at 14:26
  • 1. Use a random IV and in order to make it available for decryption just prefix the encrypted data with the iv, the IV does not need to be secret. 2. MD5 is not a secure method to derive an encryption key from a password, use PBKDF2 (aka Rfc2898DeriveBytes), Argon2 or similar password derivation functions, there should be an iteration count such that the derivation takes ~100ms or CPU time.. – zaph May 19 '18 at 09:21

1 Answers1

0

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.

Community
  • 1
  • 1
zwer
  • 24,943
  • 3
  • 48
  • 66