Search code examples
pythonopensslcryptographyaescbc-mode

bad decrypt when trying to decrypt a AES-CBC encrypted file using openssl


I'm trying to encrypt a file with python, like so:

import os
from binascii import hexlify
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes

key = hexlify(os.urandom(16))
print(key.decode())
iv = hexlify(os.urandom(16))
print(iv[:16].decode())
cipher = Cipher(algorithms.AES(key), modes.CBC(iv[:16]))
encryptor = cipher.encryptor()
msg = b"a secret message"
ct = encryptor.update(msg) + encryptor.finalize()
open("ciphertext.bin", "wb").write(ct)

and then I try to decrypt it using openSSL(I have to use openSSL as it was requested by my professor) to check for success, like so:

openssl enc -aes-128-cbc -d -K <key_the_program_prints> -iv <iv_the_program_prints> -in ciphertext.bin -out res.txt

but I get:

hex string is too short, padding with zero bytes to length
bad decrypt
139711335437696:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:crypto/evp/evp_enc.c:583:

What am I doing wrong? I believe I have the correct size in all the components, so I don't understand the error

Does it have anything to do with python handling the key and iv in bytes and I using them in string format for openSSL?

Thanks


Solution

  • In the Python code, key (16 bytes for AES-128) and IV (16 bytes for AES) must be passed binary. In the OpenSSL statement they must be specified hexadecimal encoded, i.e. in the Python code use:

    key = os.urandom(16)
    print(hexlify(key)) # for OpenSSL
    iv = os.urandom(16)
    print(hexlify(iv)) # for OpenSSL
    

    This also means that iv can be used directly instead of iv[:16] during the Cipher instantiation.

    The Cryptography library does not pad automatically. However, OpenSSL applies PKCS7 padding by default. This must therefore be disabled with the -nopad option in the OpenSSL statement, here.

    Please note that without padding only plaintexts whose length is an integer multiple of the AES block size (16 bytes) can be encrypted. Otherwise a padding must be applied. The Cryptography library supports several padding variants, including PKCS7, here. With padding, of course, the -nopad option in the OpenSSL statement must be removed.