Fabrice Jaouën
Fabrice Jaouën

Reputation: 199

pycryptodome & AES CBC : failing to decrypt a string

I'm trying to implement a simple encryption-decryption script with pycryptodome and AES-CBC, that is:

from Crypto.Cipher import AES
from Crypto import Random
#import itertools

plain_text = "This is the text to encrypt"
key = "0361231230000000"

def encrypt(plain_text, key):
    key = bytes(key, "UTF-8")
    cipher = AES.new(key, AES.MODE_CBC)
    print("Encryption Cipher: ", cipher)
    # When there is no padding, the block size must equal the cipher length
    # Padding is necessary for texts with length different from 16 bytes
    cbytes = cipher.encrypt(bytes(plain_text[:16], "UTF-8"))
    return cbytes


def decrypt(enc_text):
    k = bytes(key, "UTF-8")
    cipher = AES.new(k, AES.MODE_CBC)
    print("Decryption Cipher: ")
    return cipher.decrypt(enc_text).decode("UTF-8")


if __name__ == "__main__":
    enc_text = encrypt(plain_text, key)
    print(enc_text)

    dec_text = decrypt(enc_text)
    print(dec_text)

The error message is the following one: UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte

If in the decryption process I replace "UTF-8" by "Latin-1", the output does not match:

Decryption Cipher: 
Ï(¨e¨^î

What did I miss ?

Upvotes: 3

Views: 9801

Answers (1)

bereal
bereal

Reputation: 34290

Unlike ECB, CBC does require an initialization vector. As the documentation says:

If [iv argument] not provided, a random byte string is generated (you must then read its value with the iv attribute).

To apply that to your code:

from Crypto.Cipher import AES
from Crypto import Random

plain_text = "This is the text to encrypt"
key = b"0361231230000000"

def encrypt(plain_text, key):
    cipher = AES.new(key, AES.MODE_CBC)
    b = plain_text.encode("UTF-8")
    return cipher.iv, cipher.encrypt(b)

def decrypt(iv, enc_text):
    cipher = AES.new(key, AES.MODE_CBC, iv=iv)
    return cipher.decrypt(enc_text).decode("UTF-8")
    
if __name__ == "__main__":
    iv, enc_text = encrypt(plain_text[:16], key)
    dec_text = decrypt(iv, enc_text)
    print(dec_text)

Upvotes: 5

Related Questions