Course module
Security & symmetric encryption
Fits the modes-of-operation and misuse week of an upper-division applied-cryptography or computer-security course. About 87 minutes of core lab time: two 50-minute meetings with little slack, or two 75-minute meetings comfortably. An introductory security unit that stops after AES Modes is a different, shorter assignment — not this module with the last two exhibits skipped mid-sequence.
- Audience
- Upper-division undergraduate computer science and security students, and motivated newcomers already comfortable with XOR, hexadecimal, and AES as a keyed function on 16-byte blocks. An introductory security course can take Hidden Bit, OTP Vault, and AES Modes as a one-meeting cut; Padding Oracle and Nonce Collision assume that cut has already happened.
- Class time
- About 87 minutes of class time for the core sequence. Predict is pre-class reading and Explain is a spoken debrief.
- Last checked
- 2026-09-22
Ready to teach
- Class time
- About 87 minutes for the core sequence. Predict is pre-class reading and Explain is a spoken debrief.
- Checked in
- Chromium 153, Firefox 155 and WebKit 26.6, at desktop width and phone width.
- Known issues
- None recorded in the checks below.
- Worksheets
- Hidden Bit · OTP Vault · AES Modes · Padding Oracle · Nonce Collision
Prerequisites
- XOR on bits and bytes
- Reading hexadecimal byte strings
- AES as a block cipher: a keyed function on 16-byte blocks
- Basic probability: a blind guess of a fair coin is right half the time
- A current desktop browser
Learning outcomes
- Students will be able to explain, using the hidden-bit IND-CPA game, why deterministic AES-ECB and CBC with a predictable chained IV let a named adversary tell which of two messages was encrypted.
- Students will be able to demonstrate that reusing a one-time-pad key or a stream-cipher keystream reduces two ciphertexts to the XOR of their plaintexts, and recover plaintext from that XOR by crib-dragging.
- Students will be able to compare ECB, CBC, CTR, GCM and CCM by whether each provides confidentiality alone or authenticated encryption, and predict how each responds when a ciphertext bit is flipped.
- Students will be able to trace how a padding-validity oracle lets an attacker recover AES-CBC plaintext byte by byte without the key, and explain why verifying a MAC before decryption stops the same attack.
- Students will be able to distinguish the consequences of nonce reuse for AES-CTR, AES-GCM, ChaCha20-Poly1305 and AES-CBC, including which key material the attacker recovers and which it does not.
Which meeting finishes which outcome
- Meeting 1 — Hidden Bit, OTP Vault, AES Modes: finishes outcomes 1, 2, 3
- Meeting 2 — Padding Oracle, Nonce Collision: finishes outcomes 4, 5
Taken from each worksheet's own outcome tags, grouped by the meeting its exhibit sits in. An outcome is listed where a student finishes it, not where it is first met.
Sequence
Nonce Collision: This is where keystream reuse is shown on a real stream cipher. OTP Vault meets the same outcome on an admitted stand-in keystream, so a course that stops after the first meeting has the outcome as written and not that instance of it.
Each exhibit opens in its own site. Roles: Intro builds the idea, Break it has students cause the failure, Fix shows the construction that holds, and Extension is optional depth.
| Exhibit | Role | Time | Worksheet |
|---|---|---|---|
| Hidden Bit | Intro | 15 min | Worksheet for Hidden Bit |
| In Exhibit 01, pick an AES scheme (GCM, CTR, chained-IV CBC or ECB) and an adversary (random guess, re-encrypt and compare, or the BEAST-style IV predictor), run or step real trials, and read the measured advantage, Wilson interval and verdict. | |||
| OTP Vault | Break it | 19 min | Worksheet for OTP Vault |
| Encrypt a message under a fresh random pad, type any same-length plaintext to derive a key that maps the fixed ciphertext to it, then switch on key reuse and crib-drag C1 ⊕ C2 to peel both messages apart, including a built-in challenge. | |||
| Cite this exhibit: Clark, P. A. OTP Vault [Interactive teaching demonstration]. Crypto Lab. Retrieved [date accessed], from https://systemslibrarian.github.io/crypto-lab-otp-vault/ | |||
| AES Modes | Fix | 14 min | Worksheet for AES Modes |
| Encrypt your own plaintext under ECB, CBC, CTR, GCM and CCM, inspect the key, IV or nonce, ciphertext and tag, and run the ECB pattern-leak, CBC bit-flip and GCM tamper-detection demos to see which modes accept a modified ciphertext. | |||
| Cite this exhibit: Clark, P. A. (2026). AES Modes [Interactive teaching demonstration]. Crypto Lab. Retrieved [date accessed], from https://systemslibrarian.github.io/crypto-lab-aes-modes/ | |||
| Padding Oracle | Break it | 24 min | Worksheet for Padding Oracle |
| Predict whether a crafted final padding byte passes the real oracle, run the byte-by-byte attack on a block you type, then run the identical attack against leaky, silent and Encrypt-then-MAC servers and tamper with an AES-GCM ciphertext. | |||
| Cite this exhibit: Clark, P. A. Padding Oracle [Interactive teaching demonstration]. Crypto Lab. Retrieved [date accessed], from https://systemslibrarian.github.io/crypto-lab-padding-oracle/ | |||
| Nonce Collision | Break it | 15 min | Worksheet for Nonce Collision |
| Encrypt two messages under one AES-CTR key and nonce and crib-drag the second out of C1 ⊕ C2, then switch each construction to a reused nonce (or press "Run all four — one reused nonce") and read each card's cryptographic result beside its security verdict. | |||
| Cite this exhibit: Clark, P. A. (2026). Nonce Collision [Interactive teaching demonstration]. Crypto Lab. Retrieved [date accessed], from https://systemslibrarian.github.io/crypto-lab-nonce-collision/ | |||
What students hand in
Mode failure brief. One page that takes each exhibit in the sequence in turn, names the property the mode or key was supposed to provide, points at the line or value from the student's own run where it stopped holding, and names the one change that would have closed it. Every claim and every proposed change has to cite something the student recorded rather than a general statement about the mode.
It is drawn from what the worksheets already produce, so it adds no new task. Values differ from run to run, so there is no key to mark against: what a marker is reading is whether each claim is tied to something the student recorded, and whether the reasoning from it holds.
Discussion questions
- In Hidden Bit, random guessing and re-encryption both flatten against chained-IV CBC, yet the BEAST-style predictor breaks it. What does a flat measurement tell you about a scheme, and what does it not tell you?
- Why does XORing two ciphertexts made with the same one-time pad, or the same CTR nonce, remove the key entirely, and why does that undo what OTP Vault's Panel 2 shows about a single ciphertext?
- AES-CBC with a random IV hides repeated messages, yet Padding Oracle recovers its plaintext without the key. What is CBC missing, and why does the lab call the silent server's protection fragile while Encrypt-then-MAC stops the attack before decryption?
- One reused nonce produces different outcomes across Nonce Collision's cards. Why does AES-GCM lose integrity while AES-CBC leaks a shared prefix, and why is recovering the GHASH subkey H not the same as recovering the AES key?
- Where do repeated nonces come from in real systems, and which remedy the lab names (a persistent counter with a single encryptor, limiting how many random-nonce messages one key encrypts, or a misuse-resistant AEAD such as AES-GCM-SIV) addresses which cause?
Instructor notes
These notes are public, and they are conceptual on purpose: they describe what students should notice and why, never the specific values a run produces.
Expected observations
- Hidden Bit: AES-ECB with re-encrypt-and-compare, and chained-IV CBC with the BEAST-style predictor, earn a BROKEN verdict whose interval excludes zero; AES-GCM and AES-CTR under random guessing or re-encryption report NO ADVANTAGE FOUND BY THESE ADVERSARIES. The lab notes that finite samples fluctuate, so reruns differ slightly. A 200-trial run of an adversary with no real edge occasionally reads BROKEN as well, because the verdict asks only whether the interval’s lower bound sits above zero.
- Hidden Bit: choosing AES-CBC, chained IV reveals the 'A flat line is not a verdict' panel; once random guessing and re-encryption have both flattened, its heading changes to say no advantage was found and the scheme is broken. Exhibit 01 renders after an RSA-2048 key is generated, so allow a moment on first load.
- Hidden Bit: the Exhibit 01 header says “Choose two equal-length messages.”, but the two AES messages are fixed in the lab and never shown, so the worksheet has students record coins and ciphertext bytes instead.
- OTP Vault: Panel 2 produces a valid key for any target of the ciphertext's byte length and refuses other lengths. In Panel 3 the default crib 'the ' exposes stretches of both messages with key reuse on and noise with it off; with reuse on, re-rolling the session keys changes the ciphertexts but not C1 ⊕ C2. The Control challenge in Panel 5 uses independent keystreams and does not yield readable text. The workbench marks any offset where every revealed byte is printable as “a plausible hit”, wrong offsets included, so students decide by whether the text reads as language. The reveal box in Panel 5 stays ticked when another challenge loads.
- AES Modes: in the Compare tab, repeated 16-byte input blocks appear as repeated ciphertext blocks under ECB and not under the other modes. Tampered ECB, CBC and CTR ciphertexts still decrypt (CTR flips the same plaintext bit; CBC garbles one block and flips the matching bit in the next), while GCM and CCM reject the tampered ciphertext and release no plaintext. With a short plaintext the CBC tamper can instead fail the padding check, and the page labels that error a padding oracle, which sets up the next exhibit. The targeted bit-flip demo turns admin=0 into admin=1 without the key. Re-derived against the live page 2026-09-22.
- AES Modes: the targeted bit-flip demo explains that it flips bit 0 of C₀[7], and its result line names the same byte. Until 2026-09-23 that result line read C₀[1] while the code flipped byte 7, so the sentence describing the attack named a byte the attack never touched; fixed in the lab and re-derived here in Chromium, Firefox and WebKit. Re-derived against the live page 2026-09-23.
- AES Modes: the GCM tab’s self-check marks “can forge further messages under that nonce” correct, and its explanation says why the subkey H alone does not forge under a fresh nonce — the tag also carries a mask E_K(J0) that moves with the nonce. Until 2026-09-23 it marked “forge any future message under that key” correct, which reached past the forgery the lab builds and contradicted the lab’s own fresh-nonce control; fixed in the lab and re-derived here in all three engines. Re-derived against the live page 2026-09-23.
- Padding Oracle: Panels 3 and 4 print a byte-for-byte match badge against the plaintext the session encrypted, beside a running oracle-query count. In the Panel 6 bench the leaky server gives up its block, the silent and Encrypt-then-MAC servers exhaust the probes for a byte and stop, and the MAC-rejections column shows Encrypt-then-MAC queries rejected before decryption. Tampering with the AES-GCM ciphertext fails authentication with no plaintext shown. A WebKit-only failure recorded here until 2026-09-22 — WebCrypto accepting a final 0x00 byte as valid padding, which failed three worksheet steps — was re-derived against the live page that day in all three engines and no longer reproduces: the forced 0x00 row answers Invalid, Full Block completes, and the Panel 6 leaky server gives up its block. Whether the lab changed or the engine did is not established here. Re-derived against the live page 2026-09-22.
- Nonce Collision: with a reused nonce, the CTR card reports lost confidentiality, the GCM and ChaCha20-Poly1305 cards report a forged tag accepted by the real verifier with the recovered authentication subkey or one-time key checked against ground truth, and the CBC card reports prefix equality; the GCM and ChaCha20-Poly1305 cards state the encryption key was not recovered. Pressing a cancellation button again prints new numbers, because each press uses a fresh key. With fresh nonces, both authenticated cards now encrypt and verify under one nonce and report VALID, and each card’s banner and the scoreboard follow the computed result. Until 2026-09-23 that path verified under a second random nonce, so an honest tag never verified and the card printed “(mismatched nonce) REJECT” beneath a SAFE heading, while the scoreboard was written from the reuse toggle before the run; fixed in the lab and re-derived here in all three engines. The worksheet still has students record computed values rather than banners, which is the habit worth building whether or not a banner happens to agree. Re-derived against the live page 2026-09-23.
Common misconceptions
- A near-zero measured advantage shows a scheme is IND-CPA secure. Hidden Bit says it means the named adversaries failed, and its chained-IV CBC fixture flattens under two adversaries while falling to a third.
- Re-rolling the key hides key reuse. In OTP Vault, with reuse on, the key cancels, so C1 ⊕ C2 does not change when the session keys are re-rolled.
- ECB is acceptable because each block is still AES-encrypted. AES Modes' threat model notes the attacker cannot decrypt a single block but can see which blocks repeat and can splice or reorder blocks undetected.
- The padding oracle attack breaks AES or recovers the key. Padding Oracle describes it as exploiting CBC together with observable padding validation, and AES Modes lists key recovery among what the attacker cannot do.
- Returning one uniform error response is as good as authenticating. Padding Oracle's silent server still runs the padding check, and the lab warns that real deployments can leak the same bit through timing or downstream behaviour, as Lucky Thirteen did; the Encrypt-then-MAC server rejects modified ciphertexts before decryption.
- Nonce reuse in GCM or ChaCha20-Poly1305 hands over the encryption key. Nonce Collision recovers the GHASH authentication subkey or the Poly1305 one-time key, which enables forgery, and states the AES or ChaCha20 key is not learned.
- Nonce Collision shows these ciphers are weak. The lab says it demonstrates that violating the unique-nonce rule fails, construction by construction, not that the ciphers are weak when used as specified.
Conceptual answers
- A measured advantage estimates how one named strategy performs over a finite number of trials. An interval that excludes zero is evidence of a break; an interval that crosses zero means those strategies found no pattern. The chained-IV CBC fixture shows a scheme can flatten for weak adversaries and still fall to a better one, which is why the lab says a flat histogram is not a proof and points to reductions in its later exhibit.
- Each ciphertext is the plaintext XOR the same pad, so XORing the two ciphertexts cancels the pad and leaves P1 ⊕ P2. For a single ciphertext, any plaintext of the right length has a key that produces it, so the ciphertext reveals nothing beyond length. A second message under the same pad removes that freedom: a correct guess about part of one plaintext exposes the matching bytes of the other, which is crib-dragging. A reused CTR or ChaCha20 nonce repeats the keystream and reduces to the same situation.
- CBC provides confidentiality without integrity, so an attacker can submit modified ciphertexts and learn whether the padding check passed. The silent server still performs that check but answers identically, and the lab warns the same bit can leak through timing, logs or downstream behaviour. Encrypt-then-MAC verifies a MAC over the ciphertext first, so modified ciphertexts are rejected before AES-CBC decryption and the padding check is not reached. AEAD modes such as GCM check the authentication tag before releasing plaintext.
- In GCM the tag is a GHASH value keyed by H with a per-nonce mask XORed on top. Under one reused nonce, XORing two tags cancels the mask and leaves an equation in H; solving it lets the attacker compute valid tags for forged ciphertexts under that nonce, and the keystream reuse also exposes P1 ⊕ P2. H is derived from the AES key but is not the AES key, so the attacker does not gain decryption under fresh nonces. CBC with a repeated IV becomes deterministic, so equal leading plaintext blocks give equal leading ciphertext blocks: an equality leak rather than a keystream collapse.
- Random nonces collide by the birthday bound, far sooner than the size of the nonce space suggests, which is why SP 800-38D limits how many messages one key may encrypt with random IVs. Counters repeat when state rewinds, for example after a VM snapshot, a process fork or a container rollback. A persistent counter with a single encryptor addresses uniqueness; a misuse-resistant AEAD such as AES-GCM-SIV limits the damage of a repeat to revealing whether two plaintexts were identical, which the lab describes but does not run.
Checks
Browser support. Every exhibit in this module, and every step of its worksheet, was run in Chromium, Firefox and WebKit at a desktop width and at a phone width (1280 by 720 and 390 by 720), checked 2026-09-22. No exhibit had a problem at either width.
Privacy. Opening these exhibits sends nothing to anyone but the site they are served from: no exhibit sets a cookie, and none stores anything beyond the setting that pins its dark theme.
Detailed check results — engine versions, every step run, transfer sizes, and the source line behind each run-specific verdict. The worksheet drift check reads this module’s anchors manifest.
For your syllabus
Crypto Lab exhibits are teaching demonstrations, not production libraries. Do not use exhibit code to protect real data. https://crypto-lab.systemslibrarian.dev/teach/symmetric/
How to cite this module’s exhibits
Each exhibit's citation is in the Sequence table above, in that exhibit's own row. Exhibits change as they are improved, so the retrieval date is what says which version you used; it is filled in from your device's clock when the page loads.
BibTeX
@misc{clark_hidden_bit,
author = {Clark, Paul A.},
title = {Hidden Bit},
year = {2026},
howpublished = {\url{https://systemslibrarian.github.io/crypto-lab-hidden-bit/}},
note = {Crypto Lab. Accessed [date accessed]}
}
@misc{clark_otp_vault,
author = {Clark, Paul A.},
title = {OTP Vault},
howpublished = {\url{https://systemslibrarian.github.io/crypto-lab-otp-vault/}},
note = {Crypto Lab. Accessed [date accessed]}
}
@misc{clark_aes_modes,
author = {Clark, Paul A.},
title = {AES Modes},
year = {2026},
howpublished = {\url{https://systemslibrarian.github.io/crypto-lab-aes-modes/}},
note = {Crypto Lab. Accessed [date accessed]}
}
@misc{clark_padding_oracle,
author = {Clark, Paul A.},
title = {Padding Oracle},
howpublished = {\url{https://systemslibrarian.github.io/crypto-lab-padding-oracle/}},
note = {Crypto Lab. Accessed [date accessed]}
}
@misc{clark_nonce_collision,
author = {Clark, Paul A.},
title = {Nonce Collision},
year = {2026},
howpublished = {\url{https://systemslibrarian.github.io/crypto-lab-nonce-collision/}},
note = {Crypto Lab. Accessed [date accessed]}
}To cite the whole collection, see How to cite.