AES - Encryption with Crypto (node-js) / decryption with Pycrypto (python)

nnaelle picture nnaelle · Aug 14, 2013 · Viewed 20.6k times · Source

I'm writing this question + answer because I struggled a lot (maybe because of a lack of experience), got lost in many different ways of encrypting/decrypting things with node or python.

I thought maybe my case could help people in the future.

What I needed to do:

  • Get data from a form, encrypt them using Crypto (node-js)
  • Pass the encrypted data in Python and decrypt it using PyCrypto.

I chose to use the AES encryption.

Here is how I started (I'm not gonna go through everything I tried):

  • I followed the example at the end of this page

    Which gave in my case:

    (this might be a very bad mix between javascript and coffeescript)

    crypto = require "crypto"
    [...]
    key = "mykeywhatever"
    cipher = crypto.createCipher('aes192', key)
    cipher.update('string i want to encode', 'binary', 'hex')
    encoded_string = cipher.final('hex')
    [...]
    

    This worked pretty fine to encode my string.

  • Then I wrote my python script to decrypt this string, using the readme on PyCrypto's github's page:

    from Crypto.Cipher import AES
    [...]
    my_string = data_coming_from_rabbitmq
    obj = AES.new('mykeywhatever', AES.MODE_CBC)
    obj.decrypt(ciphertext)
    [...]
    

    This obviously didn't work: in the readme there is an IV but since I didn't gave one in the node script, why would I give one in the python one?

After more googling, I learnt that node's Crypto uses OpenSSL, while PyCrypto apparently doesn't. So I looked into that and found those pages:

So things got complicated, no one is doing the same thing to decrypt data, I got lost, and asked for help.

The answer is what my coworker and I came up with (well, mostly my corworker).

Answer

nnaelle picture nnaelle · Aug 14, 2013

So we started from the "How can i decrypt... OpenSSL" 's answer.

  • We needed to modify the encryption script which gave:

    crypto = require "crypto"
    [...]
    var iv = new Buffer('asdfasdfasdfasdf')
    var key = new Buffer('asdfasdfasdfasdfasdfasdfasdfasdf')
    var cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
    cipher.update(new Buffer("mystring"));
    var enc = cipher.final('base64');
    [...]
    

    iv needs to be 16bytes long, key is 32bytes. And we changed createCipher to createCipheriv.

  • Back to the python decryption script:

    Process was simply reading PyCrypto's documentation, and compare with the code we started from.

    Then we decided to just stick to the API, and start from scratch. And it gave:

    from base64 import b64decode
    from Crypto.Cipher import AES
    [...]
    iv = 'asdfasdfasdfasdf'
    key = 'asdfasdfasdfasdfasdfasdfasdfasdf'
    encoded = b64decode('my_encrypted_string')
    
    dec = AES.new(key=key, mode=AES.MODE_CBC, IV=iv)
    value = dec.decrypt(encoded)
    

And it was as simple as that... Hope it'll help some of you!

Update:

As Perseids wrote in the comments of his answer, the IV has to be random and different for every message