[Crypto] Leaking IV in CBC mode

Sometimes, IV in CBC mode can be leaked, if a plaintext contains many zeroes or padding bytes.

Let's see.

Zero-padded buffer

This is a real case from my practice. I knew the AES key, but I had no idea that CBC is used and I tried to decrypt using ECB mode.

#!/usr/bin/env python3

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

key = b"some highly secret key 123456789"
IV=b"init vector here"

def encr(msg):
    cipher = Cipher(algorithms.AES(key), modes.CBC(IV))
    encryptor = cipher.encryptor()
    return encryptor.update(msg) + encryptor.finalize()

def decr_with_IV(msg):
    cipher = Cipher(algorithms.AES(key), modes.CBC(IV))
    decryptor = cipher.decryptor()
    return decryptor.update(msg) + decryptor.finalize()

def decr_without_IV(msg):
    cipher = Cipher(algorithms.AES(key), modes.ECB())
    decryptor = cipher.decryptor()
    return decryptor.update(msg) + decryptor.finalize()

msg=b"Saturday"
padded_msg=msg+b"\0"*(16-len(msg))
encrypted=encr(padded_msg)
print (decr_with_IV(encrypted))
print (decr_without_IV(encrypted))


b'Saturday\x00\x00\x00\x00\x00\x00\x00\x00'
b':\x0f\x1d\x01R\x12\x04\x1ator here'

I saw only the ending of IV, but I quickly deduced its full value.

PKCS#7 padding

(See my another blog post about PKCS#7 padding.)

5-byte input file:

test

Encrypt with CBC mode:

# % echo "hello, world." | xxd -g 1
# 00000000: 68 65 6c 6c 6f 2c 20 77 6f 72 6c 64 2e 0a        hello, world..

openssl enc -aes-128-cbc -nosalt -e \
        -in input -out output \
        -K '112233445566778899aabbccddeeff00' -iv '68656c6c6f2c20776f726c642e2e2e2e'

Would be decrypted back:

openssl enc -aes-128-cbc -nosalt -d \
        -in output -out output2 \
        -K '112233445566778899aabbccddeeff00' -iv '68656c6c6f2c20776f726c642e2e2e2e'

But not in ECB mode, because of padding present:

openssl enc -aes-128-ecb -nosalt -d \
        -in output -out output2 \
        -K '112233445566778899aabbccddeeff00'
bad decrypt
40471EA6F7720000:error:1C800064:Provider routines:ossl_cipher_unpadblock:bad decrypt:../providers/implementations/ciphers/ciphercommon_block.c:124:

A Python code to decrypt it, also, to cancel padding bytes:

#!/usr/bin/env python3

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

key=b"\x11\x22\x33\x44\x55\x66\x77\x88\x99\xaa\xbb\xcc\xdd\xee\xff\x00"
IV=b"\x68\x65\x6c\x6c\x6f\x2c\x20\x77\x6f\x72\x6c\x64\x2e\x2e\x2e\x2e"

def decr_with_IV(msg):
    cipher = Cipher(algorithms.AES(key), modes.CBC(IV))
    decryptor = cipher.decryptor()
    plaintext = decryptor.update(msg) + decryptor.finalize()
    return plaintext

def decr_without_IV(msg):
    cipher = Cipher(algorithms.AES(key), modes.ECB())
    decryptor = cipher.decryptor()
    plaintext = decryptor.update(msg) + decryptor.finalize()
    return plaintext

f=open("output", "rb")
x=decr_with_IV(f.read())
print (x)

f=open("output", "rb")
x=decr_without_IV(f.read())
print (list(map(lambda i: chr(i^0xb), x)))

In first case you see correct decryption and padding bytes. In second -- IV is leaked.

b'test\n\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b'
['\x17', '\x0b', '\x14', '\x13', 'n', ',', ' ', 'w', 'o', 'r', 'l', 'd', '.', '.', '.', '.']

Without knowing padding length, it can be enumerated/bruteforced easily.

(the post first published at 20250916.)


List of my other blog posts.

Subscribe to my news feed,

Some time ago (before 24-Mar-2025) there was Disqus JS script for comments. I dropped it --- it was so motley, distracting, animated, with too much ads. I never liked it. Also, comments didn"t appeared correctly (Disqus was buggy). Also, my blog is too chamberlike --- not many people write comments here. So I decided to switch to the model I once had at least in 2020 --- send me your comments by email (don"t forget to include URL to this blog post) and I"ll copy&paste it here manually.

Let"s party like it"s ~1993-1996, in this ultimate, radical and uncompromisingly primitive pre-web1.0-style blog and website.