Section 8: Attacks & Vulnerabilities
Here is the uncomfortable truth of applied cryptography: attackers almost never break the math. AES has withstood a quarter century of open cryptanalysis; RSA with proper key sizes remains unfactorable. Yet cryptographic systems are broken constantly — because attackers target the implementation (timing leaks, error messages, memory bugs), the protocol (replayable messages, unauthenticated key exchange), or the operator (reused nonces, homemade padding checks). As Bruce Schneier put it: attacks never get worse — they only ever get better. A weakness that looks merely theoretical today is a point-and-click exploit in five years.
This section explains how the classic breaks work — conceptually, so you can defend against them. There is no exploit code here; every subsection ends with the defense that neutralizes the attack.
Threat models: what the attacker sees
Cryptanalysis is classified by attacker access, from weakest to strongest:
| Model | Attacker has | Example |
|---|---|---|
| Ciphertext-only | Intercepted ciphertext only | Frequency analysis on classical ciphers |
| Known-plaintext | Some plaintext/ciphertext pairs | Breaking Enigma via predictable weather reports |
| Chosen-plaintext | Can encrypt messages of choice | Any public-key system grants this for free |
| Chosen-ciphertext | Can submit ciphertexts, observe decryption behavior | Padding oracle attacks |
Modern ciphers are built to survive even a chosen-ciphertext attacker. Broken systems usually hand the attacker a stronger position than the designers assumed.
Padding oracle attacks
Recall from Section 4: CBC mode pads plaintext to the block size with PKCS#7 (pad with n bytes each of value n). On decryption, the receiver checks the padding is well-formed.
The trap: if a server behaves differently when padding is invalid versus valid-but-otherwise-wrong — a different error string, HTTP status, or even response time — that single leaked bit ("was the padding valid?") turns it into a decryption oracle.
The mechanism, at a high level: in CBC, P[i] = Decrypt(C[i]) XOR C[i-1]. The attacker controls the previous ciphertext block C[i-1], so altering one of its bytes changes the same byte of decrypted P[i] predictably. By cycling the last byte of C[i-1] through its 256 values and watching for the "valid padding" response (which means the byte became 0x01), XOR algebra reveals the true plaintext byte. Move to the next byte, targeting padding 0x02 0x02, and so on — around 128 queries per byte, decrypting the message without ever knowing the key.
C[i-1] (attacker tweaks bytes here)
| XOR
v
Decrypt(C[i]) --> P[i] server checks padding of P[i]
"valid" / "invalid" <-- the leaked bit
Real incidents: Lucky 13 (2013, timing variant), POODLE (2014, forced SSL 3.0 downgrade, hastened SSL 3 retirement), and the ASP.NET padding oracle (2010, MS10-070, allowed decryption of view-state and forms auth tickets).
Timing attacks
Cryptographic secrets can leak through how long an operation takes. The classic case is a byte-by-byte comparison that returns early on the first mismatch: a guess sharing more leading bytes with the secret takes measurably longer to reject, so an attacker can recover a MAC or token one byte at a time by timing responses. Paul Kocher formalized this in 1996 against RSA and Diffie-Hellman; later work showed it is viable even over a network.
crypto.timingSafeEqual in Node, hmac.compare_digest in Python). A common trick: HMAC both values under a random key and compare the HMACs, so absolute values never leak through timing.
Replay attacks
A replay attack captures a valid message and resends it later. The cryptography is untouched — the message was genuinely signed or encrypted — but replaying it triggers an unintended repeat: re-opening a car with a captured key-fob code, re-submitting a captured payment request, or reusing a captured authentication token.
Alice --[ valid signed request ]--> Server (legit) Eve captures the bytes Eve --[ same bytes, later ]-----> Server (replayed!)
Man-in-the-middle (MITM)
If a key exchange is not authenticated, an active attacker sitting between the parties can run two separate exchanges — one with each side — and relay (and read) everything. Plain Diffie-Hellman is vulnerable exactly here.
Alice <==DH==> Mallory <==DH==> Bob
shared shared
key A key B
Mallory decrypts with A, re-encrypts with B — invisible to both.
Common vantage points: rogue Wi-Fi access points, ARP spoofing on a LAN, or BGP hijacking at the network level. The fix is authentication — certificates and the PKI from Section 6 prove the far end really is who it claims. Superfish (2015) is a cautionary tale: Lenovo shipped laptops with a MITM root CA whose private key was extractable, letting anyone forge trusted certificates for those machines. Certificate pinning adds a second line of defense for high-value apps.
Nonce reuse
A nonce is a "number used once" — and the contract is strict. Break it and strong crypto collapses:
- AES-GCM / CTR: reusing a nonce with the same key means two ciphertexts share a keystream. XOR them and the keystream cancels, leaking the XOR of the two plaintexts. In GCM it is worse — an attacker can also recover the authentication subkey and forge messages.
- ECDSA: the per-signature secret k must be unique. Two signatures made with the same k let an attacker solve two linear equations for the private key directly. This is exactly how the PlayStation 3 code-signing key was extracted in 2010 — Sony reused a fixed k for every signature.
Side-channel attacks
Side channels leak secrets through physical or micro-architectural behavior rather than the algorithm itself:
| Channel | What leaks |
|---|---|
| Power analysis (SPA/DPA) | Power draw correlates with key bits — devastating against smartcards |
| Electromagnetic | EM emanations mirror internal computation |
| Cache timing | Data-dependent memory access (e.g. AES T-tables) leaks via cache hits/misses; Spectre/Meltdown are cousins |
| Acoustic / optical | Sound or LED flicker during computation |
The "common mistakes" hall of shame
Every entry below is a real breach caused not by weak math but by misuse:
- 2008 Debian OpenSSL — a packaging change crippled the RNG, so all keys came from only ~32,000 possibilities. Guessable outright.
- 2010 Sony PS3 — reused ECDSA nonce k revealed the console signing key.
- 2012 LinkedIn — 6.5M passwords stored as unsalted SHA-1; cracked en masse within days.
- 2013 Adobe — 150M passwords encrypted with ECB (not hashed) plus plaintext hints; identical passwords produced identical ciphertext, making it a giant crossword puzzle.
- 2004–2013 WEP — RC4 with tiny, repeating IVs; Wi-Fi keys recoverable in minutes.
- ~2013 Dual_EC_DRBG — a standardized random generator with a suspected backdoor; a stark lesson in trusting opaque constants.
- 2014 Heartbleed — an OpenSSL buffer over-read (not a crypto flaw) leaked private keys and memory to any client.
- 2017 KRACK — forced nonce reuse in the WPA2 handshake by replaying a handshake message.