AES get different results by using the same key and iv to encrypt the same plaintext repeatedly

Question:

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) * ''
    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.

Asked By: Jolly23

||

Answers:

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) * '' # 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) * '' # 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) * '' # 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.

Answered By: Artjom B.