Reputation: 13372
The following code produces a different ciphertext
every time I execute it, which shouldn't happen since the key & data being passed is same for every execution.
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from base64 import b64encode, b64decode
key = '/I02fMuSSvnouuu+/vyyD7NuSEVDB/0gte/z50dM0b4='
data = 'hello world!'
cipher = AES.new(b64decode(key), AES.MODE_CBC)
padded_data = pad(data.encode(), cipher.block_size)
print(b64encode(padded_data))
# b'aGVsbG8gd29ybGQhBAQEBA=='
ciphertext = cipher.encrypt(padded_data)
print(b64encode(ciphertext))
# b'rEHH0MWIWCWUldjYBco9TA=='
ciphertext = cipher.encrypt(padded_data)
print(b64encode(ciphertext))
# b'FTpLrkZttDxMlpre3Kq8qQ=='
I am actually trying to replicate a sample PHP code to Python, the PHP code gives the same output and my Python code gives different outputs, none of which match the PHP one.
Python version 3.6.x
PyCryptoDome version 3.4.7
Upvotes: 3
Views: 10109
Reputation: 7776
Every time you generate with Pycryptodome an AES cipher object in CBC mode, a random IV is created and used. It can be accessed as the attribute called iv
(for instance cipher.iv
).
The unique (and unpredictable) IV achieves the goal of randomizing the output even if the same message is getting encrypted multiple times (with the same key), which is a piece of information an attacker can often take advantage of.
You don't show the PHP code, but if its output does NOT change every time, it means that the IV is fixed and the code has a security vulnerability.
Upvotes: 4
Reputation: 13372
I forgot to pass the iv
parameter while creating the cipher
object.
It should be something like -
cipher = AES.new(b64decode(key), AES.MODE_CBC, iv=b'0123456789abcdef')
And yeah, as correctly pointed out by Rawing, repeatedly using the same cipher
object to encrypt will give different results, but it will always give same output if you reconstruct the cipher
object.
cipher = AES.new(b64decode(key), AES.MODE_CBC, iv=b'0123456789abcdef')
padded_data = pad(data.encode(), cipher.block_size)
print(b64encode(padded_data))
# b'aGVsbG8gd29ybGQhBAQEBA=='
ciphertext = cipher.encrypt(padded_data)
print(b64encode(ciphertext))
# b'8G0KL2UiCv7Uo+pKMm9G+A=='
ciphertext = cipher.encrypt(padded_data)
print(b64encode(ciphertext))
# b'tBXcf/Nf6MtxM1ulzNnIlw=='
cipher = AES.new(b64decode(key), AES.MODE_CBC, iv=b'0123456789abcdef')
padded_data = pad(data.encode(), cipher.block_size)
ciphertext = cipher.encrypt(padded_data)
print(b64encode(ciphertext))
# b'8G0KL2UiCv7Uo+pKMm9G+A=='
Upvotes: 3