CryptoJS and Pycrypto working together
Question: I'm encrypting a string in a web application using CryptoJS (v 2.3), and I
need to decrypt it on the server in Python, so I'm using PyCrypto. I feel like
I'm missing something because I can't can it working.

Here's the JS:

    
    
    Crypto.AES.encrypt('1234567890123456', '1234567890123456',
                       {mode: new Crypto.mode.CBC(Crypto.pad.ZeroPadding)})
    // output: "wRbCMWcWbDTmgXKCjQ3Pd//aRasZ4mQr57DgTfIvRYE="
    

The python:

    
    
    from Crypto.Cipher import AES
    import base64
    decryptor = AES.new('1234567890123456', AES.MODE_CBC)
    decryptor.decrypt(base64.b64decode("wRbCMWcWbDTmgXKCjQ3Pd//aRasZ4mQr57DgTfIvRYE="))
    # output: '\xd0\xc2\x1ew\xbb\xf1\xf2\x9a\xb9\xb6\xdc\x15l\xe7\xf3\xfa\xed\xe4\xf5j\x826\xde(m\xdf\xdc_\x9e\xd3\xb1'
    


Answer: Here is a version with CryptoJS 3.1.2. Always beware of the following things
(use the same in both languages):

  * Mode of operation (CBC in this case)
  * Padding (Zero Padding in this case; better use PKCS#7 padding)
  * Key (the same derivation function or clear key)
  * Encoding (same encoding for key, plaintext, ciphertext, ...)
  * IV (generated during encryption, passed for decryption)

If a string is passed as the `key` argument to the CryptoJS `encrypt()`
function, the string is used to derive the actual key to be used for
encryption. If you wish to use a key (valid sizes are 16, 24 and 32 byte),
then you need to pass it as a WordArray.

The result of the CryptoJS encryption is an OpenSSL formatted ciphertext
string. To get the actual ciphertext from it, you need to access the
`ciphertext` property on it.

The IV must be random for each encryption so that it is semantically secure.
That way attackers cannot say whether the same plaintext that was encrypted
multiple times is actually the same plaintext when only looking at the
ciphertext.

JavaScript:

    
    
    var key = CryptoJS.enc.Utf8.parse('1234567890123456');
    
    function encrypt(msgString, key) {
        // msgString is expected to be Utf8 encoded
        var iv = CryptoJS.lib.WordArray.random(16);
        var encrypted = Crypto.AES.encrypt(msgString, key, {
            iv: iv
        });
        return iv.concat(encrypted.ciphertext).toString(CryptoJS.enc.Base64);
    }
    
    function decrypt(ciphertextStr, key) {
        var ciphertext = CryptoJS.enc.Base64.parse(ciphertextStr);
    
        // split IV and ciphertext
        var iv = ciphertext.clone();
        iv.sigBytes = 16;
        iv.clamp();
        ciphertext.words.splice(0, 4); // delete 4 words = 16 bytes
        ciphertext.sigBytes -= 16;
    
        // decryption
        var decrypted = CryptoJS.AES.decrypt({ciphertext: ciphertext}, key, {
            iv: iv
        });
        return decrypted.toString(CryptoJS.enc.Utf8);
    }
    

Python code:

    
    
    BLOCK_SIZE = 16
    key = b"1234567890123456"
    
    def pad(data):
        length = BLOCK_SIZE - (len(data) % BLOCK_SIZE)
        return data + chr(length)*length
    
    def unpad(data):
        return data[:-ord(data[-1])]
    
    def encrypt(message, passphrase):
        IV = Random.new().read(BLOCK_SIZE)
        aes = AES.new(passphrase, AES.MODE_CBC, IV)
        return base64.b64encode(IV + aes.encrypt(pad(message)))
    
    def decrypt(encrypted, passphrase):
        encrypted = base64.b64decode(encrypted)
        IV = encrypted[:BLOCK_SIZE]
        aes = AES.new(passphrase, AES.MODE_CBC, IV)
        return unpad(aes.decrypt(encrypted[BLOCK_SIZE:]))
    

* * *

**Other considerations:**

It seems that you want to use a passphrase as a key. Passphrases are usually
human readable, but keys are not. You can derive a key from a passphrase with
functions such as PBKDF2, bcrypt or scrypt.

The code above is not fully secure, because it lacks authentication.
Unauthenticated ciphertexts may lead to viable attacks and unnoticed data
manipulation. Usually the an encrypt-then-MAC scheme is employed with a good
MAC function such as HMAC-SHA256.

