JOVANA
Explore Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

Side Channels: Leaking Through Timing

Guide two locked the doors with privilege levels and the MMU. This one shows that a locked door can still leak — not through what the hardware computes, but through how long it takes — and that the same cache you learned to love is the most famous leaky doorway of all.

The lock is fine — the keyhole whistles

In the last guide you built real walls. Privilege levels keep user code out of the kernel, the MMU enforces memory protection so one process cannot read another's pages, and a load to a forbidden address simply faults. Logically, the secret is unreachable. So here is the unsettling idea this guide is about: an attacker who can never read your secret may still be able to measure it. A side-channel attack does not break the lock; it listens to the noises the lock makes while it works — and a computer makes a lot of noise.

The everyday analogy is a combination safe. You cannot open it, but suppose each correct digit makes the dial click a hair more slowly than a wrong one. You never see inside, yet by timing the clicks you can recover the code one digit at a time. That is a side channel: information leaking through a physical property — time, power draw, heat, electromagnetic hum, even fan noise — that the designer never meant to carry data. The crucial honesty here is that the program is behaving exactly as specified. It computes the right answer and reveals nothing on purpose. The leak rides on something the ISA never promised to keep secret: how long things take.

Why timing leaks: the machine is not flat

Timing only leaks because the hardware is not uniform — and you already know why. Every optimisation you have learned in this ladder works by making some paths faster than others. A cache hit returns in a few cycles while a miss costs a hundred-plus; a taken branch prediction flies while a misprediction flushes the pipeline; even a division can take longer than a multiply. The machine the ISA shows you is a flat, simple contract, but the microarchitecture underneath is a landscape of fast and slow roads. Whenever a secret decides which road the program takes, the time it takes becomes a shadow of that secret.

A classic non-cache example makes the danger vivid. Imagine a password check that compares the typed string to the secret character by character and returns the instant it finds a mismatch. A wrong first letter returns almost immediately; a guess that gets the first three letters right runs three comparisons before failing — and is therefore measurably slower. An attacker who can time the response simply tries each first letter, keeps whichever is slowest, then moves to the second, turning an impossible 2^n brute force into a quick letter-by-letter walk. The fix — a constant-time compare that always examines every character before answering — is the template for all timing defences: remove the dependence of time on the secret.

The cache-timing attack: prime, wait, probe

The most powerful side channels in modern computers run through the cache — the very feature you learned to love for hiding the memory wall. A cache-timing attack exploits one plain fact: after a victim runs, the attacker can tell which memory the victim touched by measuring how fast its own later accesses are. If a line the attacker reads comes back fast, it was already in the cache — meaning the victim (or the attacker earlier) brought it in. The leak is brutal when the victim's address depends on a secret. Many cryptographic table lookups index into an array by a key byte; the address touched is `table + secret_byte`, so the secret literally selects which cache line gets loaded — and timing reveals which line that was.

The textbook recipe is called Prime and Probe, and it needs no shared data with the victim at all — only a shared cache, which any two programs on the same core (or even across cores at the last level) already have. The attacker fills the cache with its own data, lets the victim run, then re-reads its data and times each access. Wherever the attacker now suffers a slow miss, the victim must have evicted that line by loading something of its own that mapped to the same cache set — pinpointing, by set index, which addresses the victim touched, and so which secret-dependent line it pulled in.

Prime and Probe, one cache set:

1. PRIME : attacker reads its own lines A0,A1,A2,A3
           -> they now fill the 4-way set (victim's lines evicted)

2. WAIT  : let the victim run one secret-dependent step
           if victim touches an address mapping to THIS set,
           it evicts one of A0..A3

3. PROBE : attacker re-reads A0,A1,A2,A3 and times each
             fast  (hit)  -> still cached -> victim did NOT use this set
             slow  (miss) -> evicted      -> victim DID  use this set

Threshold example (cycles, illustrative):
   L1 hit   ~   4     |  reads under ~60 cycles -> "hit"
   DRAM miss~ 200     |  reads over  ~60 cycles -> "miss"
Prime and Probe reads a secret without ever reading the victim's memory: it infers which cache set the victim used purely from the attacker's own hit/miss timing.
  1. Prime: the attacker reads its own data to fill a chosen cache set, evicting whatever the victim had there.
  2. Trigger and wait: let the victim run a step whose touched address depends on the secret.
  3. Probe: re-read the primed data and time each access — a slow miss means the victim evicted that line.
  4. Decode: the pattern of which sets went slow maps back to the secret-dependent addresses, recovering the secret bit by bit.

Why this is so hard to stop

What makes cache-timing attacks frightening is how little the attacker needs. There is no buffer overflow, no malicious pointer, no privilege escalation — the attacker only reads its own memory and owns a clock. Everything the victim did was legal and correct. The MMU still enforced process isolation perfectly; not one forbidden byte was ever read. The information escaped through a resource the two programs share by design — the cache — and through a quantity the architecture treats as invisible: latency. You cannot patch this with a permission bit, because no permission was ever violated.

Defences therefore attack the dependence itself, and each carries a cost. Constant-time code is the gold standard for crypto: rewrite the algorithm so that neither the addresses it touches nor the branches it takes depend on the secret, so the timing is flat no matter the key. This is painstaking and often slower, because you deliberately give up data-dependent shortcuts. Other defences partition the shared resource — for example, pinning sensitive code to its own cache region, or flushing caches and buffers on a context switch — trading throughput for isolation. Hardware can add cache designs that resist eviction-based probing. Every one of these is the same bargain in a new suit: you buy safety by spending some of the speed the microarchitecture gave you.

Where this leads

You now hold the master key to the rest of this rung. A side channel turns an invisible internal state — a cache line, a branch outcome, a busy execution unit — into something measurable from the outside, with nothing more than a clock. The cache-timing attack is the canonical example, and Prime and Probe is its sharpest tool, but the pattern is general: any shared, performance-driven resource whose state a secret can touch is a potential leak. This is exactly why the same performance ideas you spent earlier rungs admiring — caching, prediction, out-of-order execution — keep reappearing on the security pages.

The next guide raises the stakes dramatically. So far the victim genuinely ran the secret-dependent code — the leak was a real computation observed sideways. Spectre and Meltdown show something stranger and scarier: the processor can leak data through the cache for work it only speculated on and then threw away — instructions that, architecturally, never happened. The cache-timing channel you just learned is the getaway car; speculation is what loads the loot into it. Master the timing channel here, and Spectre will read like the next sentence, not a new language.