# Lucky 13: Timing Attacks on TLS-CBC

**Source**: https://quantumsequrity.com/blog/lucky-13-timing
**Category**: Threats & Attacks

---

[← Back to Blog](../../blog.html) Threats & Attacks

# Lucky 13: Timing Attacks on TLS-CBC

12 min read

In February 2013, two cryptographers at Royal Holloway, University of London, published a paper that quietly broke another piece of TLS. Nadhem AlFardan and Kenny Paterson titled it "Lucky Thirteen: Breaking the TLS and DTLS Record Protocols," and the attack it described used precise timing measurements to recover plaintext from any TLS connection that used CBC mode with HMAC, which was almost every TLS deployment in existence. The number 13 in the name refers to the size of the TLS MAC header in bytes. The attack itself was a clever exploitation of how MAC computation time depends on input length, and it earned a CVE designation (CVE-2013-0169) that became a milestone in TLS history. Lucky 13 was the third in a sequence of attacks (after BEAST and CRIME) that pushed the industry toward AEAD encryption and away from the old MAC-then-encrypt construction.

This post explains Lucky 13 in plain language, walks through the timing leak that makes it possible, and shows why authenticated encryption modes like AES-GCM and ChaCha20-Poly1305 were designed specifically to eliminate this entire family of attacks.

## Why MAC Computation Time Matters

When TLS 1.0 through 1.2 encrypts a record using a CBC-mode cipher, the order of operations is MAC-then-encrypt. The plaintext is run through HMAC-SHA1 or HMAC-SHA256 to produce a tag. The tag is appended to the plaintext. Padding is added to fill the block. The combined plaintext-MAC-padding is encrypted with CBC. This is the construction TLS used until AEAD modes arrived.

When the receiver decrypts, the order reverses. CBC decryption produces the padded plaintext-plus-MAC. The receiver strips the padding, computes the HMAC over the plaintext, and compares it to the included tag. If anything fails, the record is rejected.

Lucky 13 exploits the fact that HMAC computation time depends on the length of the input, specifically on how many compression function blocks SHA-1 or SHA-256 has to process. SHA-1 processes input in 64-byte blocks. If the plaintext-plus-MAC is, say, 55 bytes, SHA-1 processes one block. If it is 65 bytes, SHA-1 processes two blocks, taking roughly twice as long. The boundary lies at 64 minus 9 bytes (because SHA-1's padding requires 9 bytes of overhead), which works out to 55 bytes of plaintext including the 13-byte MAC header.

If an attacker can manipulate the ciphertext so that the receiver decrypts something with a varying length (because of varying padding interpretation), they can measure the time to reject and infer the length of what the receiver actually treated as plaintext. From that inferred length, they can deduce the padding bytes, which combined with the CBC structure lets them recover plaintext byte by byte.

## The TLS Padding That Made This Possible

CBC mode requires plaintext to be a multiple of the block size, so TLS adds padding. The TLS 1.0/1.1/1.2 padding format is more careful than SSL 3.0's: it sets the last padding byte to a length value, and all preceding padding bytes must equal the same length value. The receiver checks that all padding bytes match.

This sounds robust, but the receiver's padding-check behavior leaked timing. A bad padding might look like a single bad length byte, or it might look like a length byte followed by inconsistent fill bytes. Different implementations took different code paths, and those paths took different amounts of time. If an attacker could measure the difference reliably, they could distinguish "valid padding with bad MAC" from "invalid padding."

That distinction sounds tiny, but it gave the attacker the same kind of oracle that POODLE later exploited via SSL 3.0's weaker padding. With Lucky 13, the attacker could perform a chosen-ciphertext attack against TLS 1.0/1.1/1.2 by injecting modified ciphertexts and timing the resulting reject responses.

## How the Attack Recovers Plaintext

The mechanic of Lucky 13 is similar in spirit to BEAST and POODLE but operates through timing rather than direct error-code differences. The attacker takes a captured ciphertext block they want to decrypt and substitutes it for the last block of a fresh TLS record. The CBC chaining property means the decrypted version of the substituted block depends on the previous ciphertext block, which the attacker can manipulate freely.

By varying the previous ciphertext block, the attacker controls what the decrypted plaintext-MAC-padding will look like. If the manipulation produces a plaintext where the last byte happens to equal a valid padding length value, the receiver strips that many bytes as padding, computes the MAC over the remaining bytes, and rejects with one timing profile. If the manipulation produces invalid padding, the receiver does something slightly different, with a different timing profile.

By measuring the timing carefully (often requiring a vantage point on the same network as the target server, or a co-resident attacker on the same host), the attacker can distinguish the cases. Each distinguishable case leaks one byte of information. With enough measurements (the original paper estimated around 2^23 ciphertexts per byte for full TLS, less for DTLS), the attacker can recover the entire plaintext.

CVE-2013-0169 was the assigned identifier. The attack is "lucky" because, in the original paper's framing, the attacker has to be lucky to land on the right padding value, but the probability is high enough that the attack works on average.

## The Defensive Patches

Once the paper went public, TLS implementations rushed to add defenses. The standard fix was to make the MAC computation take constant time regardless of the input. This means computing HMAC over a fixed-length input (typically the maximum possible TLS record size minus padding minus MAC), padding shorter inputs internally with zero bytes, and only at the very end comparing the result to the expected tag.

OpenSSL, GnuTLS, NSS, and other major TLS stacks shipped patches within weeks. The patches were tricky to write correctly, because making cryptographic code constant-time without sacrificing performance is genuinely hard. Several of the early Lucky 13 patches had subtle bugs that had to be re-patched in subsequent releases.

The DTLS variant of the attack was harder to defend against because UDP-based DTLS allowed the attacker to inject many test records cheaply, with no congestion control. DTLS also handled MAC verification slightly differently in some implementations. Patches for DTLS lagged TLS by a few months.

## TLS 1.2 With AEAD: The Real Solution

The deeper fix for Lucky 13 was not to make HMAC computation constant-time. It was to abandon the MAC-then-encrypt construction entirely. AEAD modes like AES-GCM and ChaCha20-Poly1305 fold authentication and encryption together, with the tag computed as a function of both the encrypted ciphertext and the associated data. There is no MAC-then-encrypt order. There is no separate padding. There is nothing for a timing attack to peel apart.

TLS 1.2 (RFC 5246, August 2008) had supported AEAD ciphers from the start. The ciphersuite TLS_RSA_WITH_AES_128_GCM_SHA256 and its siblings were available. But adoption was slow. Most servers continued negotiating CBC ciphers because they were widely supported. After Lucky 13, the migration accelerated. By 2015, AEAD ciphers were the default in most modern stacks.

TLS 1.3 (RFC 8446, August 2018) finished the job. TLS 1.3 removes CBC entirely, removes MAC-then-encrypt entirely, and mandates AEAD for all encryption. The timing-leak surface that Lucky 13 exploited has no analogue in TLS 1.3. See [AES-256-GCM Explained](aes-256-gcm-explained.md) for how AEAD modes structurally avoid the MAC-then-encrypt timing risk.

## Why Constant-Time Code Is Hard

Lucky 13 highlighted a deep truth about cryptographic engineering: writing code that runs in constant time is much harder than it looks. Modern CPUs have caches, branch predictors, and out-of-order execution, all of which create timing variations even when the code looks straightforward. A compiler optimization can introduce a data-dependent branch that does not exist in the source. A library function call (like memcmp) often returns early on the first byte mismatch, leaking position information.

Cryptographic libraries spend enormous engineering effort to ensure that critical operations run in time independent of secret data. Constant-time HMAC, constant-time AES, constant-time elliptic curve operations: each is a careful piece of code that has been reviewed, tested, and sometimes formally verified.

Even with all this effort, new timing attacks keep appearing. The 2018 Spectre and Meltdown attacks showed that CPU microarchitecture itself leaks timing through speculative execution. The 2020 Hertzbleed paper showed that CPU frequency scaling could leak timing. Cryptographic engineers have to keep up with all of these.

## Lucky 13 in the Context of CBC Doom

Lucky 13 was one of several attacks that made CBC mode in TLS effectively unusable. BEAST broke TLS 1.0 CBC via predictable IVs (2011). CRIME broke TLS-with-compression via length leaks (2012). Lucky 13 broke TLS 1.0/1.1/1.2 CBC via timing (2013). POODLE broke SSL 3.0 CBC via padding (2014). The pattern was clear: any time you used CBC mode in TLS, something would eventually leak.

This is the lesson that TLS 1.3 took to heart. Rather than try to patch every CBC-related timing or padding issue individually, TLS 1.3 removed CBC entirely. The protocol got simpler, faster, and structurally safer. See [What Is Post-Quantum Cryptography](what-is-post-quantum-cryptography.md) for a parallel discussion of how the post-quantum migration is being designed with simplicity and safety as primary goals, with [NIST FIPS Guide](nist-fips-guide.md) covering how the standards bodies are evaluating algorithms.

## How QNSQY Avoids the Timing-Leak Pattern

QNSQY uses AES-256-GCM for symmetric encryption, which is an AEAD construction with no MAC-then-encrypt order, no separate HMAC verification step, and no padding-byte-by-padding-byte parsing. The authentication tag is computed over the ciphertext, not the plaintext, and verification is done with a constant-time comparison. There is no Lucky-13-style oracle.

The post-quantum key encapsulation step uses ML-KEM combined with X25519 in a hybrid construction. ML-KEM's design includes implicit rejection: a ciphertext that fails to decapsulate produces a deterministic but unrelated shared secret, rather than an explicit reject. This means an attacker cannot mount a chosen-ciphertext attack to distinguish "valid but wrong" from "invalid" ciphertexts. The design is structurally similar to TLS 1.3's removal of explicit padding error paths.

If you read [Hybrid Encryption](hybrid-encryption.md), you will see how the layered construction reduces the impact of any single-layer timing flaw. Even if a future timing attack were found in the X25519 layer or the ML-KEM layer, the combined hybrid would still hide the underlying secret.

## FAQ

**Was Lucky 13 ever exploited in the wild?**
There are no public reports of Lucky 13 being used in real attacks before the disclosure. After the disclosure, the patches landed quickly enough that opportunistic exploitation was difficult. Lucky 13 was primarily a "yellow card" for the industry: a clear sign that CBC-MAC constructions were structurally fragile and had to be abandoned.

**Is Lucky 13 still a risk today?**
For TLS 1.3, no. TLS 1.3 has no CBC mode and no MAC-then-encrypt construction. For TLS 1.2 with CBC ciphers, there is still some residual risk on poorly patched servers, which is why every modern compliance framework (PCI-DSS, FedRAMP, etc.) recommends disabling CBC ciphers entirely.

**What about the DTLS variant?**
DTLS 1.2 had the same Lucky 13 issue, possibly worse because of UDP's lack of congestion control. DTLS 1.3 (RFC 9147, April 2022) follows TLS 1.3 in eliminating CBC. DTLS 1.0 and 1.2 deployments without proper patches should be considered vulnerable.

**Does HMAC have an inherent timing issue, or was it a TLS construction issue?**
HMAC itself is fine when used correctly. The Lucky 13 issue was in how TLS combined HMAC with CBC encryption, particularly the order (MAC-then-encrypt) and the way TLS implementations handled padding errors. HMAC in other contexts (such as JWT signing or HKDF key derivation) does not have this problem.

**Is QNSQY vulnerable to timing-based oracles?**
QNSQY uses constant-time comparisons for tag verification and uses AEAD encryption that has no MAC-then-encrypt order. The post-quantum KEM uses implicit rejection, so chosen-ciphertext probing produces no distinguishable signal. The design is specifically structured to avoid Lucky-13-style timing leaks.

## Sources

1. AlFardan, N., and Paterson, K. G. "Lucky Thirteen: Breaking the TLS and DTLS Record Protocols." IEEE Symposium on Security and Privacy, 2013. https://www.isg.rhul.ac.uk/tls/Lucky13.html
2. CVE-2013-0169. MITRE CVE database. Published 2013-02-08. https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2013-0169
3. Dierks, T., and Rescorla, E. "The Transport Layer Security (TLS) Protocol Version 1.2." RFC 5246, IETF, August 2008. https://www.rfc-editor.org/rfc/rfc5246
4. Rescorla, E. "The Transport Layer Security (TLS) Protocol Version 1.3." RFC 8446, IETF, August 2018. https://www.rfc-editor.org/rfc/rfc8446
5. Rescorla, E., Tschofenig, H., and Modadugu, N. "The Datagram Transport Layer Security (DTLS) Protocol Version 1.3." RFC 9147, IETF, April 2022. https://www.rfc-editor.org/rfc/rfc9147
6. Krawczyk, H. "The Order of Encryption and Authentication for Protecting Communications." CRYPTO 2001. https://www.iacr.org/archive/crypto2001/21390309.pdf

## Related Articles

- [AES-256-GCM Explained](aes-256-gcm-explained.md)
- [Hybrid Encryption](hybrid-encryption.md)
- [ML-KEM Explained](ml-kem-explained.md)
- [What Is Post-Quantum Cryptography](what-is-post-quantum-cryptography.md)
- [NIST FIPS Guide](nist-fips-guide.md)

---

### Protect Your Data Before Q-Day Arrives

QNSQY's NIST-standardized post-quantum encryption protects files against both current and quantum-era threats.

[Try QNSQY](../../pricing.html)
