问题
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.
回答1:
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.
来源:https://stackoverflow.com/questions/12221484/how-come-i-cant-decrypted-my-aes-encrypted-message-on-someone-elses-aes-decrypt