The padding oracle is the canonical lesson that confidentiality without integrity is no confidentiality at all. A server using AES-CBC that distinguishes "bad padding" from "bad data" — by error message, status code, or response time — hands you a one-bit oracle, and that one bit is enough to decrypt any ciphertext you can replay.
- scheme
- AES-CBC + PKCS#7 padding
- oracle
- 1 bit — "was the padding valid after decryption?"
- goal
- recover plaintext (and forge ciphertext) with no key
the structure the attack exploits#
CBC decryption XORs each decrypted block with the previous ciphertext block:
The attacker can't compute , but they fully control when replaying. Call the unknown the intermediate. If you send a crafted block in front of a target block , the server computes — and tells you whether ends in valid PKCS#7 padding. You're choosing , so you can drive to a padding you want and solve for .
one byte at a time#
PKCS#7 pads with the pad length repeated (01, or 02 02, or 03 03 03, …).
Recover the intermediate's last byte by making the last plaintext byte 0x01:
Then climb to the next byte: set C'[15] so P'[15] == 0x02 (you know I_t[15]
now), and brute C'[14] until the oracle reports valid 02 02:
Sixteen bytes, at most 256 queries each — a few thousand requests to decrypt a block, with no key in sight. Walk every block and the whole message falls.
full plaintext from a yes/no
And it runs in reverse: because you can force any plaintext block by choosing ,
the same oracle lets you encrypt chosen plaintext — forging a valid-looking
ciphertext (e.g. flipping role:guest to role:admin) without the key.
the fix is integrity#
- Authenticated encryption. AES-GCM, ChaCha20-Poly1305, or encrypt-then-MAC: the MAC is checked first, so a tampered ciphertext is rejected before any padding is ever examined — there's no oracle to query.
- Don't leak the distinction. Identical responses (and constant-time padding checks) for "bad padding" and "bad MAC"/"bad data" — but this is a fragile patch next to just authenticating.
- MAC-then-encrypt is not enough, and unauthenticated CBC never is.
The padding oracle is why "encrypt with AES" is not a security claim. CBC keeps the plaintext secret only as long as nobody can tell a malformed decryption from a well-formed one — and almost every real system, somewhere, tells you.