HackBlue

Tools · Cryptography and passwords in practice · 12 / 20

Why ECB mode is unsafe: seeing patterns leak through encrypted data

Encrypt the same data with ECB, CBC, and GCM, see repeated blocks survive ECB encryption, and learn which modes to choose and which to avoid.

9 min read · practice only with authorization

Block cipher modes

AES encrypts 16-byte blocks. A mode decides how to handle longer messages. ECB encrypts each block independently with the same key, so identical plaintext blocks become identical ciphertext blocks. CBC chains each block with the previous ciphertext and needs a random IV. CTR and GCM turn AES into a stream; GCM adds authentication.

The pattern problem

The famous ECB penguin image shows the outline of a picture surviving encryption. You can reproduce the effect with text: a message with repeated 16-byte blocks shows repeated ciphertext blocks under ECB, and none under CBC or GCM.

Snippet
import os
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives.ciphers.aead import AESGCM

key = os.urandom(32)
block = b'ATTACK AT DAWN!!'           # exactly 16 bytes
plain = block * 4

def blocks(b):
    return [b[i:i + 16].hex()[:12] for i in range(0, len(b), 16)]

ecb = Cipher(algorithms.AES(key), modes.ECB()).encryptor()
print('ECB', blocks(ecb.update(plain) + ecb.finalize()))
cbc = Cipher(algorithms.AES(key), modes.CBC(os.urandom(16))).encryptor()
print('CBC', blocks(cbc.update(plain) + cbc.finalize()))
print('GCM', blocks(AESGCM(key).encrypt(os.urandom(12), plain, None)[:64]))

Lab: run it and explain

Run the script and note that all four ECB blocks are identical, while CBC and GCM blocks differ. Then try an image: convert a simple bitmap with large flat areas to raw pixels, encrypt the pixel bytes with ECB and with CTR, keep the header, and view both. Write two sentences explaining why the ECB image is still recognizable.

Snippet
# image experiment (requires ImageMagick and openssl)
convert logo.png -depth 8 rgb:logo.rgb
openssl enc -aes-128-ecb -K 00112233445566778899aabbccddeeff -nopad -in logo.rgb -out ecb.rgb
openssl enc -aes-128-ctr -K 00112233445566778899aabbccddeeff -iv 000102030405060708090a0b0c0d0e0f -in logo.rgb -out ctr.rgb
convert -size $(identify -format '%wx%h' logo.png) -depth 8 rgb:ecb.rgb ecb.png
convert -size $(identify -format '%wx%h' logo.png) -depth 8 rgb:ctr.rgb ctr.png

What to use

Use an AEAD mode: AES-GCM or ChaCha20-Poly1305, through a high-level library. Avoid ECB entirely. Avoid unauthenticated CBC or CTR unless combined with a MAC in encrypt-then-MAC order, which high-level libraries already do for you. The fixed keys in the lab are for demonstration only.

Diagram

ECB versus GCM on repeated data

Same key, same plaintext.

ECB

Repeated blocks. Identical ciphertext blocks

Integrity. None

Use. Never for data

GCM

Repeated blocks. All different

Integrity. Authenticated with a tag

Use. Default choice with unique nonces

Check yourself

1. What is the core weakness of ECB?

2. Which mode is a good default?

3. Why is CBC without a MAC discouraged?