ECB Byte-at-a-Time Decryption Attack
- •
What it is
- •
A chosen-plaintext attack against an ECB oracle that encrypts
attacker_input || secret. Because ECB encrypts each 16-byte block independently and deterministically, identical plaintext blocks always produce identical ciphertext blocks — which lets an attacker recover the secret one byte at a time by controlling block alignment.
- •
- •
When to apply
- •
An oracle takes attacker-controlled plaintext, appends a fixed secret, and returns the AES-ECB ciphertext, with no randomization (no IV, no nonce) and no decryption needed.
- •
- •
Math
- •
Padding the input with filler bytes aligns the -th unknown byte of the secret as the last byte of a known block; brute-forcing that last byte against all 256 values and matching ciphertext blocks reveals it.
- •
- •
Worked example
- •
Secret
crypto{aaa_aa_aaaaa}appended after 15Abytes; the resulting first ciphertext block isbf...7ac. Brute-forcing the last input byte: guessing'c'reproduces that exact block (match: True), while'z'and'a'both produce completely different blocks — confirming the correct next secret byte isc, the true first character of the secret.
- •
- •
Python
- •
known = b"" for _ in range(len(secret)): pad = b"A" * (15 - len(known) % 16) target = encrypt(pad)[:len(pad) + len(known) + 1] for b in range(256): if encrypt(pad + known + bytes([b]))[:len(target)] == target: known += bytes([b]) break
- •
- •
- •
Cards
- •
What ECB property makes this attack possible?
- •
Identical plaintext blocks always encrypt to identical ciphertext blocks under a fixed key.
- •
- •
What's the role of the "A"-padding prefix in this attack?
- •
It aligns the unknown secret byte as the last byte of an otherwise-known 16-byte block, so it can be brute-forced one byte at a time.
- •
- •