Known-Plaintext Keystream Recovery (Many-Time Pad)
- •
What it is
- •
When a stream-cipher-style mode (CTR/OFB/CFB) reuses the same keystream for multiple blocks — usually from a broken nonce/counter — an attacker who knows or can guess the plaintext of one block can recover that keystream directly and reuse it to decrypt every other block sharing it.
- •
- •
When to apply
- •
The counter/nonce logic looks buggy (e.g. it never actually increments between blocks), collapsing the cipher into repeated single-block keystream reuse, and the plaintext format is guessable — e.g. a file's fixed magic-byte header.
- •
- •
Math
- •
; then for every block sharing that keystream.
- •
- •
Worked example
- •
Simulating the actual "frozen counter" bug (AES-ECB encrypting the same fixed counter value for every block instead of incrementing): a known 16-byte PNG header XORed against its ciphertext block recovered the keystream exactly, and reusing that keystream against a second ciphertext block (which used the same frozen counter) recovered its true plaintext (
SECOND_BLOCK_16!) exactly.
- •
- •
Python
- •
png_header = bytes.fromhex("89504e470d0a1a0a0000000d49484452") keystream = xor(png_header, ciphertext_blocks[0]) plaintext = b"".join(xor(block, keystream) for block in ciphertext_blocks)
- •
- •
- •
Cards
- •
What implementation bug typically causes this vulnerability?
- •
A counter/nonce that fails to actually change between blocks, so the same keystream block gets reused.
- •
- •
What do you need to recover the keystream in this attack?
- •
Any known or guessable plaintext fragment aligned with a ciphertext block that used the reused keystream.
- •
- •