Abul Hasnat
Abul Hasnat

Reputation: 1631

Porting AES decryption from CryptoJS to PyCrypto

Here is a JavaScript part which decodes a string with AES encryption

var p = 'some large string'
var s = 'Q05WTmhPSjlXM1BmeFd0UEtiOGg=' 
var y = CryptoJS.AES.decrypt({
    ciphertext: CryptoJS.enc.Base64.parse(p)
}, CryptoJS.enc.Base64.parse(s), {
    iv  CryptoJS.enc.Hex.parse("random")
});
var v = y.toString(CryptoJS.enc.Utf8)

I am trying to code a similar decoding function in python with importing AES.

Could anyone help me with this one. I can't figure out all equivalent code for js to python.

I looked up this page Python AES Decryption Routine (Code Help) and

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

Not sure if they have the code similar to the js I have here

"y.toString(CryptoJS.enc.Utf8)"

This in python what it means

I have tried something like this from another source

from base64 import b64decode
from Crypto.Cipher import AES

iv = 'random'
key = 'Q05WTmhPSjlXM1BmeFd0UEtiOGg='
encoded = b64decode('some large string')

dec = AES.new(key=key, mode=AES.MODE_CBC, IV=iv)
value = dec.decrypt(encoded)

Upvotes: 0

Views: 1421

Answers (1)

Artjom B.
Artjom B.

Reputation: 61902

There are multiple problems with your CryptoJS code and Python code.

Wrong key size

Your key s contains only 20 bytes (160 bit) which doesn't constitute any of the valid key sizes for AES which are 128 (10), 192 (12) and 256 bit (14 rounds). CryptoJS will silently run the key schedule for a 160 bit key with 11 rounds which PyCrypto doesn't support (see AES.c).

You can reduce the key to 128 bit like this in CryptoJS:

var key = CryptoJS.enc.Base64.parse('Q05WTmhPSjlXM1BmeFd0UEtiOGg=');
key.sigBytes = 16;
key.clamp();

or in Python:

key = b64decode('Q05WTmhPSjlXM1BmeFd0UEtiOGg=')[:16]

Wrong character encoding

You forgot to decode the key from a Base64 string in Python and you forgot to decode the IV from hex. The character '0' and the byte 0x00 are entirely different. There's an easier way to define an all zero IV:

iv = "\0"*16

No unpadding

CryptoJS uses PKCS#7 padding by default, but PyCrypto doesn't implement any padding and only handles data as a multiple of the block size. After you decrypt something, you need to remove the padding yourself in Python:

value = value[:value[-1]]

(the last byte determines how many bytes are padding bytes). More on that here.


Other considerations:

You really shouldn't be setting the IV to a static value. The IV should be randomly generated for every encryption using the same key. Otherwise, you will lose semantic security. Since the IV doesn't have to be secret, you can put it in front of the ciphertext and slice it off before decryption.

Upvotes: 2

Related Questions