Timing Attacks in Application-Level Code
Learn how string comparison timing leaks secrets and how constant-time comparison prevents them.
Timing Attacks in Application-Level Code is a free Cryptology Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Cryptology Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Non-Constant-Time String Comparison
The standard string equality operator in most programming languages terminates as soon as a mismatch is found. Python's == on bytes objects, C's strcmp, and Java's String.equals all return immediately when the first differing byte is found. For normal string comparison this is an optimization, but for comparing secret values like MAC tags or passwords, it creates a measurable timing side channel that leaks information.
Measuring HMAC Comparison Time
An attacker measures the time taken to compare a submitted HMAC tag against the correct value. Submitting an HMAC where the first byte matches correctly takes slightly longer than one where the first byte is wrong (one additional byte comparison). By submitting many values with each possible first byte and measuring response times, the attacker identifies the correct first byte. This process repeats byte by byte until the full tag is recovered.
Practical Attack Timing Precision
Modern network timing attacks can resolve timing differences of tens to hundreds of nanoseconds over the internet. A 32-byte HMAC comparison where each correct byte adds about 10-100ns of processing time provides a measurable signal with enough repeated measurements to average out network jitter. In a local network context, even single nanosecond differences can be exploited with sufficient statistical sampling.
Python == Operator Vulnerability
In Python, comparing MAC tags with == is unsafe: if mac == submitted_mac returns True or False based on position of first mismatch. An attacker submitting thousands of crafted tags and measuring response times can recover the expected tag byte by byte. This vulnerability has appeared in production web applications that incorrectly implemented session token or API key comparison without constant-time functions.
hmac.compare_digest in Python
Python's hmac.compare_digest(a, b) compares two bytes or string values in constant time, taking the same amount of time regardless of where the first mismatch occurs. It is implemented in C to ensure constant-time behavior even under Python bytecode interpretation overhead. Always use hmac.compare_digest for comparing MAC tags, session tokens, API keys, or any value where timing information would be dangerous.
CRYPTO_memcmp in OpenSSL
OpenSSL provides CRYPTO_memcmp(a, b, length) for constant-time memory comparison. Unlike memcmp, it always processes all length bytes regardless of early mismatches. The return value is zero if equal, non-zero if different. It is important to always compare the full expected length: comparing different-length values by the shorter length can still leak length information. Use CRYPTO_memcmp in any security-critical comparison in C/C++ code using OpenSSL.
Timing Attacks on RSA: Bleichenbacher
Timing attacks extend beyond string comparison. Bleichenbacher's 2006 attack on RSA PKCS#1 v1.5 decryption demonstrated a practical timing oracle against SSL/TLS implementations. The RSA private key operation timing varied based on whether the decrypted value had valid PKCS#1 padding. By submitting thousands of crafted ciphertexts, attackers could recover RSA private keys. This motivated RSA-OAEP and constant-time RSA implementations.
Cache Timing Attacks on AES
AES implementations using lookup tables (common for performance) access different table entries based on the key and plaintext. Cache hits versus cache misses create measurable timing differences that leak information about which table entries were accessed. This side channel can reveal AES keys. The defense is using AES implementations that do not rely on table lookups, such as AES-NI hardware instructions or bitsliced software implementations.
Constant-Time Implementation Principles
Writing constant-time code requires avoiding: conditional branches on secret data (use branchless selection with masking), memory access patterns that depend on secret data (avoid lookup tables indexed by secrets), and any operations whose latency depends on secret values (e.g., division on some processors). Compilers can optimize away constant-time constructs, so assembly or volatile memory accesses may be needed in critical sections.
AEAD Eliminates Application-Level MAC Comparison
The best defense against timing attacks on MAC comparison is to use AEAD modes (GCM, ChaCha20-Poly1305) and delegate MAC verification to the cryptographic library. Library implementations perform constant-time verification internally. If you are using AEAD correctly (decrypt fails on any tampering, never decrypt before verifying the tag), you never need to compare MAC tags in application code, eliminating the timing vulnerability entirely.
Testing for Timing Vulnerabilities
Testing for timing vulnerabilities requires statistical analysis of response time distributions. Tools like tlsfuzzer, timing-attack testing scripts, and the dudect framework help detect timing differences in cryptographic implementations. A t-test on response time samples for inputs that should produce equal timing can reveal statistically significant differences. False negatives are possible; constant-time code review is also essential alongside testing.
Constant-Time Comparison
Which Python function should be used to safely compare an HMAC tag to prevent timing attacks?
Timing Attacks Recap
Timing attack recap: early-exit string comparison leaks secret values byte by byte through response time differences, measurable over network with sufficient samples, use hmac.compare_digest in Python and CRYPTO_memcmp in OpenSSL for constant-time comparison, RSA padding timing attacks compromise private keys (use constant-time RSA and OAEP), AES table lookup timing attacks leak key bits (use AES-NI or bitsliced implementations), and AEAD library verification eliminates application-level MAC comparison needs.
Frequently asked questions
Is the “Timing Attacks in Application-Level Code” lesson free?
Yes — the full text of “Timing Attacks in Application-Level Code” is free to read here on the web, and the Cryptology Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Cryptology Academy course, upgrade to CoddyKit PRO.
What will I learn in “Timing Attacks in Application-Level Code”?
Learn how string comparison timing leaks secrets and how constant-time comparison prevents them. You practise Cryptology Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Cryptology Academy?
No prior experience is required. Cryptology Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Timing Attacks in Application-Level Code” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Cryptology Academy lesson?
Yes. Every Cryptology Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Padding Oracle Attacks in Detail
- Replay Attacks and Nonce Reuse Vulnerabilities
- Timing Attacks in Application-Level Code
- Top Cryptographic Misuse Patterns