Search code examples
pythonnode.jscryptographypycrypto

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


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).


Solution

  • 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