Here is my code:
from Crypto.Cipher import AES
import binascii
def encrypt(secret_key, sign, raw):
key = md5(secret_key).hexdigest()[::-2]
iv = md5(sign).hexdigest()[::-2]
raw += (16 - len(raw) % 16) * '\0'
generator = AES.new(key, AES.MODE_CBC, IV=iv)
#***********************************************
#Problems occur at here !
#If I execute "generator.encrypt(raw)"
#The results are not same every time
print generator.encrypt(raw) # result_1
print generator.encrypt(raw) # result_2
print generator.encrypt(raw) # result_3
#***********************************************
return binascii.b2a_hex(generator.encrypt(raw))
I will get the different results when every time I execute "generator.encrypt(raw)" It is very confuse to me because I used the same KEY and IV.
I want to establish a API-SYSTEM, I need others post their cryptographic data no matter which language they used, just want to get the same result in AES.
How can I get the stable result in using AES?
I mean I want to get the same result when I using the same KEY and IV to encrypt the same plaintext.
The AES
implementation in pycrypto is stateful for CBC mode. This statefulness can be simulated by the IV value. Let's assume that raw
is shorter than 16 bytes for simplicity.
In that case the code
raw += (16 - len(raw) % 16) * '\0' # zero padding
generator = AES.new(key, AES.MODE_CBC, IV=iv)
print generator.encrypt(raw) # result_1
print generator.encrypt(raw) # result_2
print generator.encrypt(raw) # result_3
is equivalent to
raw += (16 - len(raw) % 16) * '\0' # zero padding
generator = AES.new(key, AES.MODE_CBC, IV=iv)
ct1 = generator.encrypt(raw)
print ct1 # result_1
generator = AES.new(key, AES.MODE_CBC, IV=ct1)
ct2 = generator.encrypt(raw)
print ct2 # result_2
generator = AES.new(key, AES.MODE_CBC, IV=ct2)
ct3 = generator.encrypt(raw)
print ct3 # result_3
The reason is that the IV is advanced internally according to the definition of the CBC mode. It means that the IV is set to the last full ciphertext block.
If raw
is assumed to be any length, then the following would be equivalent where only the last block of the ciphertext is used as the IV for the next encryption:
raw += (16 - len(raw) % 16) * '\0' # zero padding
generator = AES.new(key, AES.MODE_CBC, IV=iv)
ct1 = generator.encrypt(raw)
print ct1 # result_1
generator = AES.new(key, AES.MODE_CBC, IV=ct1[-16:])
ct2 = generator.encrypt(raw)
print ct2 # result_2
generator = AES.new(key, AES.MODE_CBC, IV=ct2[-16:])
ct3 = generator.encrypt(raw)
print ct3 # result_3
If you don't want that, then you need to initialize the generator
with the original IV.