from Crypto.Cipher import AES
import os
key = 'mysecretpassword'
iv = os.urandom(16)
plaintext1 = 'Secret Message A'
encobj = AES.new(key, AES.MODE_CBC, iv)
ciphertext1 = encobj.encrypt(plaintext1)
encryptedText = ciphertext1.encode('base64')
print encryptedText
decobj = AES.new(key, AES.MODE_CBC, iv)
print decobj.decrypt(ciphertext1)
I copied the printed value of encryptedText
and the key
from my code and pasted to the websites below.
http://www.everpassword.com/aes-encryptor
http://www.nakov.com/blog/2011/12/26/online-aes-encryptor-decryptor-javascript/
I would expected it to be able to decrypt my cipher, but it doesn't. Thus I must be using pycrypto wrong. How do I fix this? The two sites can both encrypt and decrypt between each other, but mines can't. Both the websites do indeed use CBC mode.
If you look at the page source for the website in question, you will see that it uses gibberish-aes javascript library. To see whet you have to do to make it work, you have to study what it does.
Looking through its source code, it seems to use a random salt for encryption. That, prepended by the string Salted__
forms the beginning of the cyphertext before it is base64 encoded.
randArr = function(num) {
var result = [], i;
for (i = 0; i < num; i++) {
result = result.concat(Math.floor(Math.random() * 256));
}
return result;
},
and
enc = function(string, pass, binary) {
// string, password in plaintext
var salt = randArr(8),
pbe = openSSLKey(s2a(pass, binary), salt),
key = pbe.key,
iv = pbe.iv,
cipherBlocks,
saltBlock = [[83, 97, 108, 116, 101, 100, 95, 95].concat(salt)];
string = s2a(string, binary);
cipherBlocks = rawEncrypt(string, key, iv);
// Spells out 'Salted__'
cipherBlocks = saltBlock.concat(cipherBlocks);
return Base64.encode(cipherBlocks);
},
For decryption, it uses picks the random portion of the salt out of the beginning of the cyphertext after base64 decoding (the first slice
operator):
dec = function(string, pass, binary) {
// string, password in plaintext
var cryptArr = Base64.decode(string),
salt = cryptArr.slice(8, 16),
pbe = openSSLKey(s2a(pass, binary), salt),
key = pbe.key,
iv = pbe.iv;
cryptArr = cryptArr.slice(16, cryptArr.length);
// Take off the Salted__ffeeddcc
string = rawDecrypt(cryptArr, key, iv, binary);
return string;
},
The missing piece now is the openSSLkey
function:
openSSLKey = function(passwordArr, saltArr) {
// Number of rounds depends on the size of the AES in use
// 3 rounds for 256
// 2 rounds for the key, 1 for the IV
// 2 rounds for 128
// 1 round for the key, 1 round for the IV
// 3 rounds for 192 since it's not evenly divided by 128 bits
var rounds = Nr >= 12 ? 3: 2,
key = [],
iv = [],
md5_hash = [],
result = [],
data00 = passwordArr.concat(saltArr),
i;
md5_hash[0] = GibberishAES.Hash.MD5(data00);
result = md5_hash[0];
for (i = 1; i < rounds; i++) {
md5_hash[i] = GibberishAES.Hash.MD5(md5_hash[i - 1].concat(data00));
result = result.concat(md5_hash[i]);
}
key = result.slice(0, 4 * Nk);
iv = result.slice(4 * Nk, 4 * Nk + 16);
return {
key: key,
iv: iv
};
},
So basically you have to translate the openSSLKey
function to Python and feed it your password and salt. That creates a (key, iv) tuple. Use those to encrypt your data. Prepend the string Salted__
and the salt to the ciphertext before encoding it with base64. Then it should work, I think.