Applied Cryptography for Developers
Applied cryptography flashcards
Flashcards for applied cryptography: bytes and encodings, hashes and MACs, passwords, encryption, signatures, tokens, TLS, post-quantum plans and code review.
336 cards. Read the question, answer it in your head, then open the card to check.
-
Which four guarantees does cryptography give, and which tool gives each one?
Confidentiality: encryption. Integrity: a MAC, the tag of an authenticated cipher or a signature. Authenticity: a MAC (a key holder made it) or a signature (the owner of the private key made it). Non-repudiation: a digital signature, with a record of whose key it is.
From the lesson What cryptography can and cannot do
-
Why can a MAC not give non-repudiation?
Both sides hold the same key, so either of them could have made a valid tag, and an auditor cannot tell which did. A signature comes from a private key that only the signer holds, so it can point at one party, although whether it binds the signer is in the end a legal decision, not a mathematical one.
From the lesson What cryptography can and cannot do
-
What does Kerckhoffs's principle say, and why does it still hold?
A cryptosystem must stay secure when everything about it except the key is known, so its security rests on the key alone. Designs leak through shipped apps, repositories and former staff; a leaked key can be replaced in minutes but a leaked design cannot; and a public algorithm has been attacked by many people before you trust it.
From the lesson What cryptography can and cannot do
-
A team stores a database password Base64-encoded in a config file so that nobody can read it. What is wrong?
Base64, hex, compression and obfuscation need no key to undo, so anyone who can read the file decodes it at once. Keep secrets in a secret store such as a key management service or the operating system's keychain, and treat anything inside a shipped app as public.
From the lesson What cryptography can and cannot do
-
What are the four lines of a quick threat model?
What we protect; who might attack and from where; what they can see, change, replay or guess; and what must still hold. Each ability points at a need: reading calls for confidentiality, changing for integrity and authenticity, guessing for enough randomness (ASVS 5.0 asks for at least 128 bits from a secure generator), replaying for a freshness check.
From the lesson What cryptography can and cannot do
-
Why does a valid MAC or signature not stop a replayed message?
A resent copy verifies exactly like the original. The design needs its own freshness rule: a timestamp, a single-use token, or a record of what was already accepted.
From the lesson What cryptography can and cannot do
-
A request passes TLS and carries a genuine session token, yet Asha reads Ben's invoice by changing the number in the address. What failed?
Access control, not cryptography: the handler never asked whether the invoice belonged to the user in the verified session. Check ownership on every request. Encrypting or randomising the invoice number only hides the link, which still works for anyone who sees it.
From the lesson What cryptography can and cannot do
-
Name the higher-level choice for each: a cipher plus a MAC you combine yourself; SHA-256 of a password; raw RSA encryption; a home-made secure channel.
An authenticated cipher (AES-GCM or ChaCha20-Poly1305); a password hash (Argon2id, scrypt, bcrypt or PBKDF2); HPKE or a library's sealed box; TLS 1.3 from the platform. Use the platform's maintained cryptography and its highest-level operation that fits.
From the lesson What cryptography can and cannot do
-
Why can one word, such as café, have two different SHA-256 digests?
The letter é has two Unicode spellings: the single code point U+00E9, which NFC produces, or a plain e with the combining mark U+0301 after it, which NFD produces. In UTF-8 one café is then 5 bytes and the other 6, and their digests have nothing in common. That is why NIST SP 800-63B-4 wants passwords normalised to NFC before they are hashed.
From the lesson Bytes, hex and Base64 in crypto code
-
Why must a key or a field be measured in bytes, not in characters?
Crypto code reads bytes, and the byte count depends on the encoding. नमस्ते is 6 characters but 18 bytes in UTF-8, so a 16-character check passes it and a 16-byte field cannot hold it. One emoji is 1 character in Python, 2 in JavaScript and 4 bytes in both.
From the lesson Bytes, hex and Base64 in crypto code
-
How much bigger does hex or Base64 make data, and how long is a 32-byte key in each?
Hex uses two characters per byte, so it doubles the size. Base64 packs 3 bytes into 4 characters, so it grows data by a third. A 32-byte key is 64 hex characters or 44 in Base64. Anyone can reverse either, so neither protects anything.
From the lesson Bytes, hex and Base64 in crypto code
-
How does Base64url differ from Base64, and what does the final = stand for?
Base64url uses - and _ instead of + and /, so it is safe in URLs, cookies and file names. The = is padding for the byte the last group of three lacks. JSON Web Signatures (RFC 7515) and most tokens write Base64url with the trailing = left out.
From the lesson Bytes, hex and Base64 in crypto code
-
Why must a webhook's tag be checked on the raw body, before the JSON is parsed?
A MAC or signature covers exact bytes. Parsing the JSON and serialising it again changes them: in the lesson's run the copy gained three spaces, so the check failed on a genuine message. Verify the bytes as they arrived and parse only after the check passes.
From the lesson Bytes, hex and Base64 in crypto code
-
Why compare decoded bytes instead of text spellings?
Several strings can stand for the same bytes. YQ== and YR== both decode to a in a lenient decoder, and upper-case hex is the same tag as lower-case. Code that compares, stores or blocks text sees two values where the bytes hold one.
From the lesson Bytes, hex and Base64 in crypto code
-
How do you decode untrusted Base64 strictly?
Match a pattern that allows only the alphabet and the two legal endings, decode, then encode the result again and compare it with the input. The round trip catches non-zero unused bits. RFC 4648 says implementations must reject characters outside the alphabet unless the using specification says otherwise.
From the lesson Bytes, hex and Base64 in crypto code
-
In what form does HOTP feed its counter to HMAC?
As 8 bytes, high-order byte first (big-endian), as RFC 4226 sections 5.1 and 5.2 say. JavaScript's DataView.setBigUint64 writes big-endian unless asked otherwise; Python's struct needs a > in its format.
From the lesson Bytes, hex and Base64 in crypto code
-
What does n bits of security mean, and how long does searching a 56-bit and a 128-bit key take?
NIST defines security strength as the work needed to break an algorithm: s bits means about 2^s operations (112, 128, 192 or 256). Each extra bit doubles the work. At a trillion guesses a second a 56-bit key falls in 20 hours; a 128-bit key needs about 1.1 × 10^13 years even at a billion billion a second.
From the lesson Security levels, key sizes and attack cost
-
Why is RSA-2048 not 2,048 bits of security?
Strength follows the best attack, not the key size. Factoring the modulus is far cheaper than trying 2^2048 keys, so RSA-2048 gives 112 bits. Only for a good symmetric cipher do the key size and the strength match.
From the lesson Security levels, key sizes and attack cost
-
Which AES, RSA and elliptic-curve sizes give 112, 128, 192 and 256 bits of security?
112: three-key triple DES, RSA-2048, P-224. 128: AES-128, RSA-3072, P-256 or Curve25519. 192: AES-192, RSA-7680, P-384. 256: AES-256, RSA-15360, P-521. These are the pairings of NIST SP 800-57 Part 1, Table 2.
From the lesson Security levels, key sizes and attack cost
-
Why does a 256-bit elliptic curve give 128 bits of security?
The best known attacks need about the square root of the size of the curve's group, so a curve gives about half the bit length of its group order (SP 800-186). A 256-bit curve therefore gives 128 bits, with private keys of 32 bytes.
From the lesson Security levels, key sizes and attack cost
-
How many bits of security does SHA-256 give, and why are there two answers?
128 bits where collisions matter, as in digital signatures, and 256 bits where only finding an input for a given output matters, as in HMAC and key derivation (SP 800-57, Table 3). Finding any two inputs with the same digest takes about 2^128 tries, not 2^256.
From the lesson Security levels, key sizes and attack cost
-
After how many random b-bit values does a repeat become likely?
After about 1.18 × 2^(b/2): the square root of the number of possibilities, not the number itself. Among 23 people the chance of a shared birthday is already 50.7 %, although a year has 365 days. Size hashes, nonces and identifiers for the square root of their space.
From the lesson Security levels, key sizes and attack cost
-
How many encryptions may one AES-GCM key make when its 96-bit nonces are random?
At most 2^32. Among 2^32 random 96-bit nonces a repeat has a chance of about 1.2 × 10^-10, and NIST SP 800-38D requires that chance to stay at 2^-32 or below. A repeated nonce with one key can break the protection.
From the lesson Security levels, key sizes and attack cost
-
What would a large quantum computer change for RSA, elliptic curves and AES, and what is 'harvest now, decrypt later'?
Shor's algorithm would break RSA, Diffie-Hellman and every elliptic curve outright; longer keys would not save them. Grover's search is only quadratic, and RFC 9958 argues AES-128 stays secure. Traffic recorded today can be decrypted later, so data that must stay secret for years needs quantum-resistant key exchange now.
From the lesson Security levels, key sizes and attack cost
-
What are the five parts of a symmetric cipher, and which one must stay secret?
The plaintext p, the key k (chosen from the key space), the encryption algorithm E with c = E(k, p), the ciphertext c, and the decryption algorithm D with D(k, c) = p. Only the key is secret: both sides hold the same one, delivered in advance, which is the key distribution problem.
From the lesson The symmetric cipher model and the Caesar cipher
-
What does the attacker hold in the four attack models, and which one does a cookie of encrypted user input give every user?
Ciphertext only: ciphertexts. Known plaintext: pairs of plaintext and ciphertext. Chosen plaintext: ciphertexts of messages they choose. Chosen ciphertext: decryptions, or decryption errors, of ciphertexts they choose. A cookie that holds encrypted user input hands every user a chosen-plaintext attack.
From the lesson The symmetric cipher model and the Caesar cipher
-
How does the Caesar cipher encrypt and decrypt, and what is special about ROT13?
With A = 0 to Z = 25, c = (p + k) mod 26 and p = (c − k) mod 26. With k = 3, Z (25) becomes 28 mod 26 = 2, the letter C. ROT13 is the shift by 13; two of them go all the way round, so it is its own inverse. It hides a spoiler from a glance, never a secret from a reader who wants it.
From the lesson The symmetric cipher model and the Caesar cipher
-
Why does a Caesar function with a negative key break in JavaScript but not in Python?
JavaScript's % keeps the sign of the left side, so -3 % 26 is -3 and String.fromCharCode(65 + ((n + k) % 26)) turns A into >. Reduce the key first with ((k % 26) + 26) % 26. Python's % already returns 0 to 25 for a positive divisor.
From the lesson The symmetric cipher model and the Caesar cipher
-
How is a Caesar ciphertext broken without anyone reading the results?
Only 25 keys change anything, so decrypt with all of them. To choose, measure how far each decryption's letter counts are from English with the chi-squared statistic; the lowest score wins. On the lesson's passage the true key scored 32.1 and the next best 76.9. It needs enough text: the true key ranked first in 49.4 % of 5-letter runs, 82.6 % at 10 and 100 % at 25.
From the lesson The symmetric cipher model and the Caesar cipher
-
Why is a large key space necessary but not sufficient?
Exhaustive search is ruled out, yet a simple substitution cipher with 26! keys (roughly 4.0 × 10^26, or 88.4 bits) still falls to letter counts. AES-128 has 2^128 keys and no known attack much better than trying them.
From the lesson The symmetric cipher model and the Caesar cipher
-
What is the difference between computational and unconditional security?
A cipher with computational security resists the best known attack by a comfortable margin over any attacker's resources, as AES-128 does at 128 bits. Unconditional security, which no amount of computing breaks, needs a key at least as long as the message: the one-time pad.
From the lesson The symmetric cipher model and the Caesar cipher
-
How can a test catch a home-made classical cipher inside an 'encrypt' function?
Measure how often output bytes repeat. Real ciphertext repeats about 1.0 times the random rate; output that keeps the shape of text repeats far more (the Caesar output: 20.4 times). A pass proves nothing, because a broken cipher can look random; only a vetted authenticated cipher used as documented earns trust.
From the lesson The symmetric cipher model and the Caesar cipher
-
How does the affine cipher work, and which multipliers does it allow?
c = (a·p + b) mod 26 and p = a⁻¹(c − b) mod 26. The inverse exists only when gcd(a, 26) = 1, which leaves 12 multipliers and 12 × 26 = 312 keys, as easy to try as Caesar's 25. Decrypt in reverse order: take b off first, then multiply: a_inv * (c − b) % 26.
From the lesson Monoalphabetic ciphers and frequency analysis
-
How does the extended Euclidean algorithm find a modular inverse?
It rests on gcd(a, b) = gcd(b, a mod b), so the numbers shrink until the second is 0 and the last remainder is the gcd. It also tracks how each remainder is made from the inputs; when the gcd is 1, the coefficient of a is the inverse. For a = 5 and m = 26 it is 21. Python does it with pow(a, -1, m), which raises ValueError when no inverse exists.
From the lesson Monoalphabetic ciphers and frequency analysis
-
What does Euler's totient φ(n) count, and what are φ(26), φ(37) and φ(35)?
The numbers that have an inverse modulo n. φ(26) = 12, exactly the affine cipher's multipliers. φ(37) = 36, because for a prime every number below it qualifies. φ(35) = 24: 35 = 5 × 7 loses its multiples of 5 and 7.
From the lesson Monoalphabetic ciphers and frequency analysis
-
How many keys does a monoalphabetic substitution cipher have, and why do keyword alphabets weaken it?
26! keys, about 2^88.4; at a trillion keys a second a search would take 12.8 million years. A keyword alphabet leaves far less to guess, because people choose words they can remember and an attacker tries a list of likely words. The tail also barely moves: under KRYPTOS, Z maps to itself.
From the lesson Monoalphabetic ciphers and frequency analysis
-
Why does frequency analysis still work after any substitution?
A substitution renames letters and changes no count: each count moves to a new letter, but the set of counts stays the same. Sort the ciphertext's counts and match them with English: E appears 84 times in the lesson's passage and T 84 times in its KRYPTOS ciphertext, so T stands for E.
From the lesson Monoalphabetic ciphers and frequency analysis
-
What is the index of coincidence, and what values do random letters and English give?
The chance that two letters drawn from a text are equal: the sum of f(f − 1) over the letter counts divided by n(n − 1). Random letters give 1/26 = 0.0385; English gives about 0.066 to 0.069 (0.0667 is usually quoted). A substitution cannot change it, so it needs no key and no table of English.
From the lesson Monoalphabetic ciphers and frequency analysis
-
What is unicity distance, and how many letters of ciphertext does a simple substitution need?
The ciphertext needed before only one key can give meaningful plaintext: the key's entropy divided by the language's redundancy. English carries about 1.5 bits a letter of a possible 4.7, so about 3.2 are predictable; 88.4 ÷ 3.2 ≈ 28 letters (a skilled analyst needs about 25). The answer is unique then, but finding it still takes a search.
From the lesson Monoalphabetic ciphers and frequency analysis
-
How can you tell that an 'encrypt' function you own is only a substitution?
Encrypt a long sample and compare the indexes of coincidence of input and output. If they are equal, the function substitutes letters or bytes, whatever its name says, and must be replaced with a vetted authenticated cipher.
From the lesson Monoalphabetic ciphers and frequency analysis
-
How do the Vigenère and autokey ciphers shift letters, and what do they do to the index of coincidence?
Vigenère shifts letter i by key letter i mod t, t Caesar ciphers interleaved; number only the letters, so spaces use no key letter. MEETATTHEGATE under STORM gives EXSKMLMVVSSMS. Under MONSOON the index fell from 0.0692 to 0.0483. The autokey cipher keys later letters with the plaintext itself, so the key never repeats (index 0.0394).
From the lesson Playfair, Vigenère and Hill ciphers
-
How do Kasiski's method and the index of coincidence find a Vigenère key length?
Kasiski: the same plaintext under the same part of the key gives the same ciphertext, so repeated segments sit a multiple of the key length apart (48 of 65 distances had the factor 7). Index of coincidence: take every t-th letter; only for the right t is each column English-like (0.0700 at 7, 0.0458 to 0.0489 elsewhere). Each column is then a Caesar cipher.
From the lesson Playfair, Vigenère and Hill ciphers
-
Why is an 'encrypt' function that XORs data with a short fixed key readable, and how can a check catch it?
It is a Vigenère cipher on bytes: its period is the key length, and each byte column falls to statistics on its own. Split the output into columns for periods 1 to 16 and fail when the columns of any period repeat bytes three times as often as random ones (20.6 times at period 8). AES-GCM passes. Replace the function with an authenticated cipher.
From the lesson Playfair, Vigenère and Hill ciphers
-
How does Playfair encipher a pair of letters, and what does it leave behind?
With a 5 × 5 key square (I and J share a cell): same row, each letter moves right; same column, each moves down; otherwise each takes the corner in its own row. Single letters are hidden (index 0.0504), but a pair always becomes the same pair, so digram counts are only renamed (index 0.01067 before and after).
From the lesson Playfair, Vigenère and Hill ciphers
-
How does the Hill cipher work, and why must code state its convention?
It multiplies a block of n letters by an n × n key matrix modulo 26, and decrypts with the inverse matrix, which exists only when the determinant shares no factor with 26. The practical writes blocks as rows (C = P K); the Handbook writes columns (C = K P). The same matrix then gives RRL or LNS, so say which you use.
From the lesson Playfair, Vigenère and Hill ciphers
-
Why do a few known blocks give away a Hill key?
The mixing is linear: each known block gives three linear equations in the key's nine entries. Three known blocks give all nine, in matrix form C = P K, and if the 3 × 3 matrix P of the known blocks has an inverse modulo 26, the key is K = P⁻¹ C, found by algebra and not by search. Modern ciphers pair linear mixing with non-linear substitution to break this link.
From the lesson Playfair, Vigenère and Hill ciphers
-
What does each classical cipher hide, and what does it keep?
Substitution hides letter names and keeps counts. A repeating key hides the profile and keeps a period. Playfair hides letters and keeps pair counts. Hill mixes whole blocks and keeps linearity. What works is many rounds of keyed, non-linear substitution and transposition on large blocks, so that no statistic of the plaintext survives.
From the lesson Playfair, Vigenère and Hill ciphers
-
What does a transposition cipher keep, and how do the rail fence and columnar ciphers work?
It moves letters and changes none, so it keeps every letter count, the index of coincidence (about 0.069) and a low chi-squared score as it stands. The rail fence writes the text in a zigzag over its rails, turning at both ends. Columnar transposition writes rows as wide as the key and reads whole columns in the order of the key's digits.
From the lesson Transposition, product ciphers and one-time pads
-
How do you tell a transposition from a substitution without a key?
Read two numbers. An index of coincidence near 0.069 with a low chi-squared score as it stands (51.5 to 57.0 in the lesson) points to a transposition; the same index with a high score (1,207 to 4,050) points to a substitution. A transposition also breaks common letter pairs: only the right key restores them, which gives the key away.
From the lesson Transposition, product ciphers and one-time pads
-
What do confusion and diffusion mean, and how well does one classical round do?
Confusion is a complicated relation between key and ciphertext, which substitution adds. Diffusion is the plaintext's redundancy spread over the ciphertext, which transposition and mixing add. A substitution followed by a transposition is a round of a product cipher. One classical round changed only 1 of 28 ciphertext letters per changed plaintext letter.
From the lesson Transposition, product ciphers and one-time pads
-
How many ciphertext bits change when one plaintext bit of an AES-128 block is flipped?
Between 49 and 77 of the 128 bits, 63.83 on average: about half, as if the output were random. AES substitutes with a non-linear S-box, mixes bytes across the 16-byte block and repeats the round 10 times with a new round key each time. That is the diffusion a single classical round lacks.
From the lesson Transposition, product ciphers and one-time pads
-
What makes a one-time pad unconditionally secure, and what does it cost?
A truly random key at least as long as the message, kept secret and used once. Then every plaintext of that length is equally possible (a pad exists that turns the ciphertext of ATTACK AT DAWN into RETREAT AT TEN), so an attacker learns only the length. The cost is delivery: backing up 2 GB a day would need 730 GB of pad a year.
From the lesson Transposition, product ciphers and one-time pads
-
Why does using a pad or a keystream twice leak both messages?
c1 ⊕ c2 = (p1 ⊕ k) ⊕ (p2 ⊕ k) = p1 ⊕ p2: the key cancels and leaves the XOR of the two plaintexts, which keeps their redundancy (zero in 18 of 23 bytes where two payment messages agreed). NIST SP 800-38A section 6.5 requires every counter block under one key to be distinct.
From the lesson Transposition, product ciphers and one-time pads
-
Where do counter blocks repeat in real code?
When a counter kept in memory starts from zero after a restart, when two servers or containers share a key but keep their own counters, and when state is restored from a backup. Persist the counter, give each instance its own key, or use random nonces within their limits.
From the lesson Transposition, product ciphers and one-time pads
-
What does malleable mean, and which mode shows it?
Decryption is the same XOR as encryption, so a flipped ciphertext bit becomes a flipped plaintext bit with no error: AES-CTR returned PAY 400 instead of PAY 500. AES-GCM refused the changed ciphertext because of its 16-byte tag. A keystream hides content but does not protect it, so use an authenticated cipher with unique nonces.
From the lesson Transposition, product ciphers and one-time pads
-
Why can a reset token made with Python's random module, seeded with the clock, be rebuilt?
Its output follows from the seed by a fixed formula, and a clock reading is easy to narrow down. In the lesson's run one of 3,601 seeds, one for each second of the hour before, rebuilt the 128-bit token exactly, although it had 62 one-bits out of 128 like a random value. A secrets token has no seed to find. Seeding with the time or process ID is CWE-337.
From the lesson Secure random numbers in browsers, Node and Python
-
Does seeding random with os.urandom(32) make random.getrandbits(128) safe for a token?
No. The seed is unpredictable, but the generator is still a fast formula over its state, built for statistics rather than against someone working backwards from outputs it has shown. Take secrets straight from secrets or crypto.getRandomValues, which never let you choose a seed.
From the lesson Secure random numbers in browsers, Node and Python
-
Where do secure random bytes come from, and which NIST standards describe the layers?
From the operating system's CSPRNG, which you neither build nor seed. SP 800-90B covers the entropy sources that measure unpredictable physical events, SP 800-90A the deterministic random bit generators that stretch them (Hash_DRBG, HMAC_DRBG, CTR_DRBG), and SP 800-90C how to combine the two. A CSPRNG is one whose next bit no practical computation predicts better than a coin toss.
From the lesson Secure random numbers in browsers, Node and Python
-
What does crypto.getRandomValues refuse, and how do you fill a larger buffer?
It throws TypeMismatchError for anything but an integer typed array (a Float64Array fails) and QuotaExceededError for more than 65,536 bytes in one call. Fill a larger buffer in slices, using subarray views so each call writes into the right part without copying: the lesson filled 1 MiB in 16 calls.
From the lesson Secure random numbers in browsers, Node and Python
-
Which random calls does Node.js add beyond getRandomValues?
randomBytes(n) returns a Buffer with no 65,536-byte limit, randomUUID() a version 4 UUID, and randomInt(min, max) an integer that avoids modulo bias. In a browser, randomUUID() exists only on secure pages, while getRandomValues works on any page.
From the lesson Secure random numbers in browsers, Node and Python
-
How many random bytes do common secrets need, and how do Python's secrets functions size their output?
Session IDs, reset links and API tokens: 16 or more bytes (ASVS 5.0, 11.5.1). AES-128 key 16, AES-256 key 32, password salt 16, AES-GCM nonce 12. With no argument the token functions use secrets.DEFAULT_ENTROPY, which may change, so pass the size: token_bytes(16) is 16 bytes, token_hex(16) 32 characters, token_urlsafe(16) 22.
From the lesson Secure random numbers in browsers, Node and Python
-
How should tests get predictable randomness without a seed in the code that makes secrets?
Pass the random source in as a parameter that defaults to the system generator: def issue_token(source=secrets.token_bytes). Tests hand in a fixed source such as lambda n: bytes(range(n)). A seed parameter on production code lets anyone who learns it, or a code path that forgets the default, rebuild the tokens.
From the lesson Secure random numbers in browsers, Node and Python
-
What real failure shows the danger of a poorly seeded generator?
A change made only in Debian's OpenSSL package left the generator seeded with little more than the process ID, so SSH, OpenVPN, DNSSEC and certificate keys made on those systems could be guessed (Debian advisory DSA-1571, CVE-2008-0166). MITRE lists the weakness as CWE-337.
From the lesson Secure random numbers in browsers, Node and Python
-
What do version 4 and version 7 UUIDs contain?
Both are 128 bits with 4 bits of version and 2 of variant (the 13th hex digit is the version). Version 4 has 122 random bits. Version 7 starts with the Unix time in milliseconds, so new ones sort after old ones and database inserts stay close together, and has at most 74 random bits, random or a counter.
From the lesson Random tokens, UUIDs and unbiased sampling
-
Why is a version 4 UUID the wrong password-reset token?
Under RFC 9562 a UUID may never act as a security capability, a value that grants access to whoever holds it, and nobody should assume UUIDs are hard to guess. ASVS 5.0 requirement 11.5.1 says UUIDs fall short of its rule for values nobody may guess: a CSPRNG and 128 bits or more. Version 7 also reveals when a record was created. Use a random token; keep UUIDs for naming records.
From the lesson Random tokens, UUIDs and unbiased sampling
-
How many bits does a token carry, and how long must it be for 128 bits?
With every character uniform and independent, length × log2(alphabet size): hex carries 4 bits a character, Base64url 6, a decimal digit 3.32. For 128 bits use 32 hex, 26 Crockford Base32, 22 Base58, Base62 or Base64url characters, or 39 digits. Thirty-two decimal digits carry only 106 bits, so count bits, not characters.
From the lesson Random tokens, UUIDs and unbiased sampling
-
What is modulo bias, and how big is it for byte % 10 and byte % 62?
A byte has 256 values and 256 = 25 × 10 + 6, so the bytes 250 to 255 land on 0 to 5: those digits come from 26 bytes each, 6 to 9 from 25, and each of 0 to 5 is 4 % more likely. For 62 characters 8 are 25 % more likely. Sizes that divide 256, such as 16 and 64, have no bias.
From the lesson Random tokens, UUIDs and unbiased sampling
-
How does rejection sampling remove modulo bias?
Use only values that split evenly: keep a byte only if it is below 250, the largest multiple of 10 that fits in a byte, and draw again otherwise. Every digit then comes from exactly 25 bytes. The result is exactly uniform and the expected number of draws stays below 2; the seeded run threw away 2.32 % of bytes and scored chi-squared 13.8 against 319.9 for byte % 10.
From the lesson Random tokens, UUIDs and unbiased sampling
-
Which ready-made calls give unbiased random numbers and picks?
Node's crypto.randomInt(min, max), unbiased for ranges below 2^48, and Python's secrets.randbelow(n) and secrets.choice(seq). Write your own only where no such call exists, such as picking characters from your own alphabet, and test it on every byte value.
From the lesson Random tokens, UUIDs and unbiased sampling
-
How do a collision and a guess differ as risks for random identifiers?
A collision, two identifiers that are equal, matters for uniqueness and grows with the square of the number made (birthday bound). A guess, hitting any live identifier, matters for security and grows with live values times guesses. A trillion version 4 UUIDs collide with a chance of 9.4 × 10^-14, so they name records well; secrets get 128 bits even where 64 would be unique enough.
From the lesson Random tokens, UUIDs and unbiased sampling
-
What keeps a six-digit one-time code safe, given that it carries only about 20 bits?
The verifier, not the code: it throttles failed attempts and the code expires. NIST SP 800-63B-4 caps consecutive failures at 100, requires rate limiting for any such secret under 64 bits, and gives an out-of-band code at most 10 minutes. With 100 tries the chance of hitting a 6-digit code is 1 in 10,000; with unlimited tries it is certain.
From the lesson Random tokens, UUIDs and unbiased sampling
-
How does a linear congruential generator work, and does a long period make a generator secure?
It keeps one number x and replaces it with (a·x + c) mod m; the output is the whole state. Java's java.util.Random is an LCG with a 48-bit seed; Python's random is a Mersenne Twister with a period of 2^19937 − 1. Both are documented as unsuitable for cryptography: a period says when the sequence repeats, not how hard the next value is to compute.
From the lesson PRNG families: LCG, Blum Blum Shub and CSPRNGs
-
What do the uniformity, scalability and consistency checks measure?
Uniformity: cut the range into 16 buckets and score the counts with chi-squared; with 15 degrees of freedom a fair generator scores above 24.996 only 5 % of the time. Scalability: parts of the sequence, such as the even-indexed half, pass the same test. Consistency: it holds for many seeds (195 of 200 passed). All ask whether output looks random, none whether it can be predicted.
From the lesson PRNG families: LCG, Blum Blum Shub and CSPRNGs
-
How do three consecutive outputs of an LCG with a known prime modulus predict every later one?
Subtracting one step from the next removes c: x2 − x1 = a·(x1 − x0) mod m. Because m is prime, x1 − x0 has a modular inverse, so a follows by one multiplication and c from any one step. The lesson's predictor recovered a = 1103515245 and c = 12345 and got the next five outputs right. Unknown parameters do not save an LCG either.
From the lesson PRNG families: LCG, Blum Blum Shub and CSPRNGs
-
The LCG passed a uniformity test. What does passing statistical tests prove?
Only that output looks random. The LCG scored 12.2 against a limit of 24.996 and still gave up its whole future from three outputs, so tests are necessary but not sufficient. Suites such as NIST SP 800-22 catch broken generators and entropy sources; they never prove a generator unpredictable.
From the lesson PRNG families: LCG, Blum Blum Shub and CSPRNGs
-
How does Blum Blum Shub make bits, and what is it secure under?
Pick different primes p and q that each leave 3 when divided by 4, let n = p·q, square a seed to get x0, then for each output bit square again modulo n and output the lowest bit. It is secure if factoring n is intractable, so n must be as large as an RSA modulus of the same strength: 3,072 bits for 128 bits of security.
From the lesson PRNG families: LCG, Blum Blum Shub and CSPRNGs
-
Why is Blum Blum Shub a poor choice for production code?
Each output bit costs a modular squaring of a number thousands of bits long. The recorded run measured 8,192 squarings modulo a 2048-bit number, which make 1 KiB at one bit each: about a tenth of a second, roughly three thousand times longer than 1 KiB from secrets.token_bytes. The system's DRBG gives the same unpredictability at a tiny fraction of the cost.
From the lesson PRNG families: LCG, Blum Blum Shub and CSPRNGs
-
Which random calls should a review flag in each language, and what replaces them?
JavaScript Math.random() → crypto.getRandomValues, randomBytes, randomInt. Python random.random, randint, choice, getrandbits → secrets, os.urandom. Java java.util.Random, ThreadLocalRandom, SplittableRandom, Math.random() → SecureRandom. C rand(), random(), srand(time(NULL)) → getrandom(). Go math/rand → crypto/rand. MITRE files the misuse as CWE-338.
From the lesson PRNG families: LCG, Blum Blum Shub and CSPRNGs
-
How does a test keep a weak generator from returning to token code?
Give the token code its random source as a parameter and keep a test that feeds it an LCG. With the LCG the last 4 bytes of a token are the generator's state, so the next token follows, and the check reports True; with secrets.token_bytes it reports False. The test fails the day someone wires in a fast generator.
From the lesson PRNG families: LCG, Blum Blum Shub and CSPRNGs
-
What are the three promises of a cryptographic hash, and what does each cost an attacker at n bits?
Preimage resistance (given a digest, find an input) and second-preimage resistance (given an input, find a different one with the same digest) cost about 2^n hashes. Collision resistance (find any two inputs with one digest) costs about 2^(n/2), by the birthday bound. For SHA-256 that is 2^256, 2^256 and 2^128.
From the lesson Hash functions: SHA-2, SHA-3 and BLAKE2
-
Which promise does each use need: a stored hash of a reset token, a published file digest, a signature over a digest?
A stored token hash needs preimage resistance, so a leaked table does not give back the tokens. A published file digest needs second-preimage resistance, so nobody can make another file to match. A signature needs collision resistance: someone who chooses the message could prepare two that collide, have one signed and reuse the signature.
From the lesson Hash functions: SHA-2, SHA-3 and BLAKE2
-
On SHA-256 cut down to 16 bits, how many hashes did a collision take compared with a preimage?
About 388 on average for a collision (320 predicted), against 56,171 for a second preimage and 60,564 for a preimage, close to 2^16 = 65,536. ASVS 5.0 (11.4.3) turns this into a rule: an output of at least 256 bits where collision resistance is needed, at least 128 bits where only second preimages matter.
From the lesson Hash functions: SHA-2, SHA-3 and BLAKE2
-
Which functions make up SHA-2, SHA-3 and BLAKE2, and what is special about SHAKE and BLAKE2?
SHA-2 (FIPS 180-4): SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224 and SHA-512/256. SHA-3 (FIPS 202): SHA3-224 to SHA3-512 and the extendable-output functions SHAKE128 and SHAKE256, which give as many bytes as you ask for. BLAKE2 (RFC 7693): BLAKE2b (1 to 64 bytes) and BLAKE2s (1 to 32), which can take a key and so also work as a MAC.
From the lesson Hash functions: SHA-2, SHA-3 and BLAKE2
-
What is the avalanche effect, and how large was it for SHA-256?
Flipping one input bit flips about half of the output bits. Over 1,000 one-bit flips, 127.7 of the 256 bits changed on average, never fewer than 101 or more than 153. A digest that changed in only a few places would leak what changed in the input.
From the lesson Hash functions: SHA-2, SHA-3 and BLAKE2
-
How do you hash a large file in Web Crypto, Node.js and Python?
Web Crypto's digest() takes one buffer and does not support streaming, so the whole input must be in memory. In Node.js, createHash() with update() takes it piece by piece, and crypto.hash() is the one-shot call. In Python repeated update() calls equal one call on the joined data, and hashlib.file_digest() (3.11 and later) reads a file for you.
From the lesson Hash functions: SHA-2, SHA-3 and BLAKE2
-
What is length extension, and why is SHA-256(secret ∥ message) not a MAC?
A SHA-256 digest is the complete state after the last block, so anyone who knows a message's digest and length can go on hashing more blocks without knowing the message. A tag made as SHA-256(secret ∥ message) can therefore be extended to a longer message. HMAC, SHA-3 and SHA-512/256 are not open to it; use the language's HMAC.
From the lesson Hash functions: SHA-2, SHA-3 and BLAKE2
-
What is the status of MD5 and SHA-1, and where are they still met?
RFC 6151 rules MD5 out wherever collision resistance is needed. SHA-1 has a public collision (two PDFs, found with 110 GPU-years and 6,500 CPU-years of work), and NIST has set the end of 2030 for phasing it out. Still met: download checksums (they catch damage, never a swap), old HMAC-SHA-1 protocols, and MD5 cache keys, where Python's usedforsecurity=False says nothing is defended. Never deduplicate uploads by SHA-1.
From the lesson Hash functions: SHA-2, SHA-3 and BLAKE2
-
Why does a build that fetches a tool and its SHA-256 checksum from the same mirror gain nothing?
A digest proves integrity, that the bytes are unchanged since it was made, never who made them. Whoever can change the file on the mirror can change the checksum too. The expected digest must come from a source the mirror cannot change: the project's own site over HTTPS or a committed lock file, a MAC with a shared key, or a digital signature.
From the lesson Integrity checks, SRI and canonical hashing
-
What do HTTP's Content-Digest and Repr-Digest fields protect against?
Accidents, not deliberate tampering. RFC 9530 says they are not meant as general protection, because someone who can change the body in transit can replace the field too. For that, use TLS or HTTP Message Signatures (RFC 9421).
From the lesson Integrity checks, SRI and canonical hashing
-
Why is storing the SHA-256 of a reset token fine, but storing the SHA-256 of a password is not?
A 128-bit random token cannot be guessed, so a leaked table of hashes gives back nothing. A password is not random: its SHA-256 can be found by hashing likely passwords, so passwords need slow, salted password-hashing functions.
From the lesson Integrity checks, SRI and canonical hashing
-
How does Subresource Integrity pin a script, and what makes the attribute useless?
The integrity attribute holds an algorithm, a hyphen and the Base64 of a digest, and browsers must support SHA-2 at 256, 384 and 512 bits. If one byte of the file changes, the browser refuses the response, and a cross-origin element needs crossorigin="anonymous". An md5- or sha1- value is ignored, and an attribute with no usable value checks nothing. Generate sha384- values in the build and fail it when one is missing.
From the lesson Integrity checks, SRI and canonical hashing
-
Why does joining fields before hashing give ambiguous digests, and how do you fix it?
user 12 with 3/report.pdf and user 123 with /report.pdf join to the same text, so a link signed for one user works for the other. Put each field's length in bytes in front of it, so the encoding reads back only one way, and add a label such as download-link/v1 for domain separation, so that a value made for one purpose cannot pass as another's.
From the lesson Integrity checks, SRI and canonical hashing
-
What does the JSON Canonicalization Scheme (RFC 8785) fix?
One text per JSON value: no whitespace, object keys sorted by their UTF-16 code units at every level, and numbers and strings written by the ECMAScript rules. Texts that differ in key order, spacing and 500.00 against 5e2 then give one canonical text and one digest. Hash or sign the canonical form; send the JSON as it is.
From the lesson Integrity checks, SRI and canonical hashing
-
Why do XOR sums and CRC-32 protect nothing against an attacker?
They detect transmission errors, but a message with any chosen checksum is easy to build. CRC-32 is affine: for messages of equal length crc(m ⊕ d) = crc(m) ⊕ crc(d) ⊕ crc(zeros), so the checksum of a changed message follows from the old one. WEP put a CRC-32 inside its encrypted frames and frames could be modified undetected; against HMAC the same patch fails.
From the lesson Integrity checks, SRI and canonical hashing
-
How does RFC 9162 compute the root of a Merkle tree?
No entries: SHA-256 of nothing. One entry: SHA-256(0x00 ∥ entry), its leaf hash. For n > 1 entries, take k as the biggest power of two below n; the root is SHA-256(0x01 ∥ root of the first k ∥ root of the rest), so seven entries split 4 + 3. One 32-byte root commits to every entry, in order.
From the lesson Merkle trees and transparency logs
-
How long is a Merkle inclusion proof?
About log2 n sibling hashes: 3 for 7 entries, 20 for a million and 30 for 2^30, so at most 960 bytes for a log of over a billion entries. That is why logs use trees.
From the lesson Merkle trees and transparency logs
-
Why do leaf hashes start with 0x00 and node hashes with 0x01?
It is domain separation, which RFC 9162 requires for second-preimage resistance. Without prefixes an interior node is just the hash of 64 bytes, and anyone can submit those 64 bytes as one entry: the tree of two entries and the tree of one 64-byte entry made of their hashes then share a root. With prefixes no input can be both a leaf and a node.
From the lesson Merkle trees and transparency logs
-
What does an inclusion proof prove, and what must the verifier already have?
That an entry is at a given position in the tree. The verifier rebuilds the path from the entry and the proof's sibling hashes and compares the result with a root it trusts, so it needs the entry, its index, the tree size, the proof and that root, never the other entries. It does not prove the root is honest or current.
From the lesson Merkle trees and transparency logs
-
What does a consistency proof show, and when does it catch a dishonest log?
That the tree of size n begins with exactly the m entries of an earlier tree: the log is append-only. A log that rewrote an old entry cannot prove consistency with a root it published before. It is caught only by someone who kept an older root, and a log showing different views to different clients can escape, which is why many parties compare what they see.
From the lesson Merkle trees and transparency logs
-
Do Certificate Transparency logs prevent misissued certificates?
No. They let interested parties, above all the domain owners named in certificates, detect misissuance. Monitors inspect every new entry of the logs they watch, which is how an owner learns of a certificate they never asked for.
From the lesson Merkle trees and transparency logs
-
What are a signed certificate timestamp and a signed tree head?
A signed certificate timestamp (SCT) is a log's signed promise to add an entry to its tree within its Maximum Merge Delay. A signed tree head is the log's signed statement of its current size and root. Chrome's policy asks for 2 SCTs from distinct logs for a certificate valid 180 days or less and 3 for longer ones, with at least two of them from different log operators.
From the lesson Merkle trees and transparency logs
-
Which other record is kept in a transparent Merkle log?
Go's checksum database, sum.golang.org: a log of the hashes of go.sum lines. The go command checks inclusion and consistency proofs before it adds new lines to the main module's go.sum.
From the lesson Merkle trees and transparency logs
-
Why does a message tag need a key, and what does a MAC promise?
A hash has no key, so anyone who can change a body can compute the SHA-256 of the new one. A MAC is a function of a secret key and the message whose tag nobody can compute without the key; the receiver recomputes it over the bytes it received and accepts only an equal tag. The promise is unforgeability: after seeing tags of many chosen messages you still cannot tag another.
From the lesson HMAC and constant-time verification
-
Which constructions give a valid MAC: SHA-256(message), SHA-256(key ∥ message), HMAC-SHA-256, KMAC256?
SHA-256(message) has no key, so anyone can make it. SHA-256(key ∥ message) falls to length extension. HMAC-SHA-256 (RFC 2104, FIPS 198-1) has no practical attack known. KMAC256 (NIST SP 800-185) is also sound because SHA-3 has no length extension, but fewer platforms offer it; most webhooks use HMAC.
From the lesson HMAC and constant-time verification
-
How does HMAC compute its tag?
HMAC(K, m) = H((K′ ⊕ opad) ∥ H((K′ ⊕ ipad) ∥ m)). K′ is the key padded with zero bytes to one block (64 bytes for SHA-256), after a key longer than a block is replaced by its hash; ipad is 0x36 repeated and opad 0x5c repeated. The tag is never the state of a hash that an outsider could continue.
From the lesson HMAC and constant-time verification
-
What key and tag sizes does RFC 2104 set for HMAC-SHA-256, and how do you make the key?
The key should be random and at least as long as the hash output, 32 bytes; shorter keys are strongly discouraged. Make it with a CSPRNG: secrets.token_bytes(32) or crypto.getRandomValues(new Uint8Array(32)). A tag may be truncated to no fewer bits than half the hash output and never below 80, so 128 bits is the shortest. A t-bit tag is guessed once in 2^t tries.
From the lesson HMAC and constant-time verification
-
Why test HMAC against the vectors of RFC 4231?
It gives seven test cases for each of SHA-224, SHA-256, SHA-384 and SHA-512, chosen for the edges where implementations slip: a key shorter than the output, keys longer than a block (which are hashed first) and a truncated tag. Web Crypto, createHmac and Python's hmac gave identical bytes on them and on GitHub's published webhook value.
From the lesson HMAC and constant-time verification
-
How do Web Crypto, createHmac and Python's hmac compute and verify a tag?
Web Crypto turns the secret into a key with importKey (naming HMAC and its hash); sign returns the tag and verify recomputes and compares for you. In Node, createHmac(hash, key) takes update(data) then digest(). Python's hmac.new needs the hash name (required since 3.8) and hmac.digest does it in one call. Extendable-output functions such as SHAKE128 will not work.
From the lesson HMAC and constant-time verification
-
Why does an early-exit comparison of tags leak, and what do you use instead?
A loop that returns at the first differing byte, like ==, does work that grows with the number of leading bytes that are right, and averaging many requests makes the difference measurable (ASVS 5.0, 11.2.4). The early exit made 1, 9, 17 and 32 comparisons for guesses with 0, 8, 16 and 31 right bytes; the full check made 32 every time. Use hmac.compare_digest, crypto.timingSafeEqual or subtle.verify.
From the lesson HMAC and constant-time verification
-
How should a receiver check a sha256= signature header?
Check the prefix and the length, decode the hex strictly and compare the 32 bytes in constant time; never compare the header as text. Buffer.from(text, 'hex') silently stops at the first non-hex character, timingSafeEqual throws for inputs of different lengths (a tag's length is not secret, so check it first), and compare_digest returns False. Malformed tags must give false, not an error.
From the lesson HMAC and constant-time verification
-
Which bytes should a MAC cover, and how should extra tagged fields be joined?
The request body exactly as it arrived, verified before any framework parses it: parsing JSON and writing it out again changes spacing, key order and the spelling of numbers. If a design tags structured data, both sides apply a canonical form such as RFC 8785. When the tag also covers a key ID, time or nonce, frame each field by its length so the bytes read back only one way.
From the lesson Designing signed messages: context and replay
-
What belongs inside the tagged bytes of a message, and why?
Every field that decides how the receiver acts: a version (refuse unknown versions, never fall back to a weaker one), a key ID (looked up in the receiver's own key ring), a purpose label for domain separation (so one kind of message's tag is never valid as another) and the recipient (a message for orders fails at refunds). Otherwise a message made for one use can be offered to another.
From the lesson Designing signed messages: context and replay
-
Why can a valid tag arrive twice, and what makes a copy worthless?
Networks repeat requests, providers retry and anyone who recorded a message can resend it, and no MAC alone tells a copy from the original. Three tools together: a signed time, refused outside a replay window around the receiver's clock; a random nonce kept in a replay cache while its message could still pass the window; and an event ID recorded once the application has acted.
From the lesson Designing signed messages: context and replay
-
How are the replay window and the nonce cache related, and how big does the cache get?
The window decides how long the cache must remember a nonce, so the cache holds only the messages of the last window: for 300 seconds at 200 messages a second that is 60,000 nonces, about 0.96 MB of 16-byte values. A replay older than the window is refused without reading the cache. Set the window for clock differences and delivery time, not for convenience; a tolerance of 0 turns the time check off.
From the lesson Designing signed messages: context and replay
-
A provider's signature covers only the body, with no time. What defends against a replayed delivery?
The event ID: record each event you have processed and skip it when it arrives again. GitHub's and Razorpay's signatures cover the body alone, and Razorpay sends a unique event-ID header. Retries are new messages about the same event, so event IDs are needed even with timestamps: Stripe signs a new timestamp for every retry.
From the lesson Designing signed messages: context and replay
-
How do forging and replaying a message differ, and what stops each?
A forgery is a message the attacker made with a tag they had to invent: the MAC stops it, and a constant-time check keeps failed tries from teaching anything. A replay is a genuine message sent again unchanged, so its tag is valid. It needs freshness inside the tagged bytes and memory on the receiver. A receiver needs both defences, since each is blind to the other attack.
From the lesson Designing signed messages: context and replay
-
In what order do you rotate a MAC key without refusing messages in flight?
Receivers learn the new key first, senders switch, both keys verify during an overlap, and receivers forget the old key last. Keep the old key at least as long as the sender retries old messages; Stripe lets two secrets stay active up to 24 hours. The message names a key ID inside its tagged bytes, and the receiver never uses a key, or an address to fetch one, taken from the message.
From the lesson Designing signed messages: context and replay
-
When do you choose a signature instead of an HMAC for messages?
With HMAC both sides hold the same key, so either could have made a tag: fine between two services that trust each other, weak when many receivers share a key, and no evidence for a third party. Use a signature (private key signs, public key verifies) when many parties verify, a third party must be convinced or a receiver cannot keep a secret. RFC 9421 supports both, hmac-sha256 and ed25519.
From the lesson Designing signed messages: context and replay
-
Why derive keys from a shared secret instead of using the secret itself?
The secret from a key agreement is unpredictable but not uniformly random, and it is one value where a protocol needs several. Using one key for both AES and an HMAC tag ties their security together. Key separation gives one key per algorithm, purpose and direction, and a key-derivation function such as HKDF produces them from the one secret.
From the lesson Deriving keys with HKDF
-
What do HKDF's Extract and Expand steps do?
Extract turns the input keying material and a salt into a uniform pseudorandom key: PRK = HMAC(salt, IKM). Expand turns the PRK and an info label into as many bytes as asked: T(n) = HMAC(PRK, T(n−1) ∥ info ∥ n), from an empty T(0). The PRK is never used directly. Extract may be skipped for an already uniform key, but not for Diffie-Hellman outputs.
From the lesson Deriving keys with HKDF
-
How long can an HKDF output be, and why?
At most 255 × HashLen bytes, 8,160 for SHA-256, because the block counter is a single byte. For 42 bytes Expand makes two blocks: all 32 bytes of T(1) and 10 of T(2).
From the lesson Deriving keys with HKDF
-
What are the roles of HKDF's salt and info inputs, and must either be secret?
Neither is secret. The salt is the HMAC key of Extract: optional, reusable, ideally random and HashLen bytes long; without one HKDF uses HashLen zero bytes. The info label binds each output to one use, such as a protocol, purpose and direction, and must not depend on the secret itself. Only the input keying material must be secret, and it must already be hard to guess.
From the lesson Deriving keys with HKDF
-
Which rules does Web Crypto's HKDF enforce?
The secret must be imported as a non-extractable HKDF key (an extractable one throws SyntaxError), and the parameters must name a salt and an info label even when both are empty, as new Uint8Array(0), or a TypeError follows. deriveBits takes its length in bits, 336 for 42 bytes. deriveKey derives an AES-GCM or HMAC key and imports it in one step, so your code never holds its bytes.
From the lesson Deriving keys with HKDF
-
Why must an HKDF info label name the key's length and frame its parts?
Expand's output for 16 bytes is the first 16 bytes of its output for 32 under the same label, since both start with T(1), so an AES-128 and an AES-256 key derived under one label are related. Joined parts are ambiguous too: msc with 1enc and msc1 with enc make the same text and the same key. Name the protocol, version, purpose, direction and length, each part framed.
From the lesson Deriving keys with HKDF
-
Why is HKDF not a password hash?
HKDF assumes input that is already hard to guess: extraction concentrates entropy but cannot add any, and slowing attackers down is not its job. In the lesson's run HKDF allowed hundreds of thousands of password guesses a second on one core, while scrypt allowed a few, each needing 128 MiB. Use Argon2id, scrypt or PBKDF2 first; HKDF-Expand with labels can then split the result into keys.
From the lesson Deriving keys with HKDF
-
Which key-derivation approach fits which input?
A Diffie-Hellman or X25519 secret: HKDF, Extract with a salt, then Expand. A random 32-byte root key: HKDF-Expand, or a counter-mode KDF as in SP 800-108. A password or passphrase: Argon2id, scrypt or PBKDF2. A key from a password hash that must become several keys: the password hash once, then HKDF-Expand with labels. ASVS 5.0 requirement 11.4.4 asks for key stretching for keys from passwords.
From the lesson Deriving keys with HKDF
-
Why does a fast hash fail for stored passwords, in numbers?
People choose passwords from a small set of likely words, so a thief with the table guesses rather than breaks the hash. In the recorded run one core tried about a million SHA-256 guesses a second, so ten million likely passwords took under ten seconds; with Argon2id at 19 MiB the same core managed about 37 a second, 75 hours for every record.
From the lesson Password hashing: Argon2id, scrypt and bcrypt
-
What do slowness, a salt and memory-hardness each add to a password hash?
A cost factor makes each guess slow, and you raise it as computers get faster. A random salt stored with each record gives equal passwords different records, so every record is a separate target. A memory-hard function needs a block of memory for every guess, so hardware that runs many guesses side by side pays for memory in each, not only for arithmetic.
From the lesson Password hashing: Argon2id, scrypt and bcrypt
-
How does OWASP rank Argon2id, scrypt, bcrypt and PBKDF2?
Argon2id first. scrypt when Argon2id is missing. bcrypt only for legacy systems that have neither. PBKDF2 whenever FIPS-140 compliance is required.
From the lesson Password hashing: Argon2id, scrypt and bcrypt
-
Which starting settings does OWASP list for each password function?
Argon2id (RFC 9106): 19 MiB of memory, 2 passes, 1 lane. scrypt (RFC 7914): N = 2^17, r = 8, p = 1. bcrypt: cost 10 or more, and it ignores everything after the first 72 bytes of a password. PBKDF2 (RFC 8018, SP 800-132): 600,000 iterations of HMAC-SHA-256.
From the lesson Password hashing: Argon2id, scrypt and bcrypt
-
How do Argon2id, scrypt, bcrypt and PBKDF2 differ in design?
Argon2id sets memory, passes and lanes apart and is the variant RFC 9106 says to choose when unsure. scrypt is memory-hard with one cost, N, that sets memory and time together. bcrypt is slow but not memory-hard. PBKDF2 repeats HMAC as often as you ask: slow, but cheap to run on many guesses at once.
From the lesson Password hashing: Argon2id, scrypt and bcrypt
-
What does a stored password record in PHC string format hold, and why?
The function, its version, the settings, the salt and the hash. Because the record carries its own settings, a login years later still checks it correctly, whatever the policy has moved to by then.
From the lesson Password hashing: Argon2id, scrypt and bcrypt
-
Which login rules come from NIST SP 800-63B-4, and which from OWASP?
NIST: passwords of at least 15 characters when they are the only factor, a blocklist of compromised values, and at most 100 consecutive failed attempts on an account. OWASP: a hash that takes less than a second on your own servers and grows stronger as they do.
From the lesson Password storage and login security
-
What are the six decisions around a password hash?
Cost: measure the hash on your own hardware. Upgrades: rehash old records after a successful login. Pepper: a secret kept outside the database and mixed into every hash. Policy: length in code points after Unicode normalisation, a blocklist, no rules on kinds of characters. Breach checks: a range query that sends five characters of a hash. Online guessing: limits per account, with growing waits rather than quick lockouts, checked before the slow hash runs.
From the lesson Password storage and login security
-
Why upgrade a stored password hash at login?
A successful login is the one moment the server holds the password, so a record made under older settings can be rehashed with the current ones right then.
From the lesson Password storage and login security
-
What is a pepper, and what does it add?
A secret key kept outside the database and mixed into every hash, for example as Argon2's secret input. A stolen table alone then cannot be checked against guesses.
From the lesson Password storage and login security
-
How can a service check a new password against breach data without sending the password?
With a range query that sends only five characters of the password's hash, never the password itself.
From the lesson Password storage and login security
-
What goes wrong when passwords are hashed without NFC normalisation?
The same password typed on a laptop and a phone can arrive as different code points: é as a single character, or as e with a combining accent after it. In the lesson's run the two strings had 15 and 16 code points and different hashes, so the person signed up on one device and was told the password was wrong on the other. NIST SP 800-63B-4 asks verifiers to apply NFC before hashing.
From the lesson Password storage and login security
-
What does AES do on its own, and what can a block cipher not do?
AES is a keyed permutation of 16-byte blocks, with a key of 128, 192 or 256 bits and 10, 12 or 14 rounds. It handles whole blocks only (17 bytes are refused), and the same block under the same key always gives the same output. A mode of operation decides how longer data is cut into blocks, what is mixed in and what extra value, an IV or a counter, is stored. Web Crypto offers AES only through modes.
From the lesson Block ciphers and modes: why ECB and raw CBC fail
-
Why does ECB mode leak, even though AES is strong?
ECB cuts the data into 16-byte blocks and encrypts every block separately, and SP 800-38A notes that under one key a given plaintext block always comes out as the same ciphertext block. The lesson's padlock picture of 216 blocks became just 2 distinct ciphertext values, and rows holding the same 16 bytes at the same position look identical to anyone reading the table. AES is not broken; the mode has nothing that changes from one call to the next. ASVS 5.0 (11.3.1) rules it out.
From the lesson Block ciphers and modes: why ECB and raw CBC fail
-
How does CBC chain blocks, and what must its IV be?
C1 = E_K(P1 ⊕ IV) and Cj = E_K(Pj ⊕ C(j−1)), so every block depends on all before it. The IV need not be secret but must be unpredictable (SP 800-38A): 16 fresh random bytes per message, stored in front of the ciphertext, never a constant, record ID or timestamp. A fixed IV brought back the ECB leak for the start of each message. PKCS#7 padding adds 1 to 16 bytes, each equal to the number added.
From the lesson Block ciphers and modes: why ECB and raw CBC fail
-
How does CTR mode work, and what must never happen?
AES encrypts a sequence of counter blocks and the outputs form a keystream that is XORed with the data, so no padding is needed. Across all messages under a key, every counter block must be distinct. In Web Crypto, the length parameter says how many of the rightmost bits of the 16-byte counter block are incremented.
From the lesson Block ciphers and modes: why ECB and raw CBC fail
-
Does CBC or CTR notice a changed ciphertext?
No: SP 800-38A calls them confidentiality modes. CBC accepted 30 of 48 one-bit changes: every IV change went through and altered one byte of the message, and a change in the first ciphertext block scrambled it and flipped the same bit in the next. The 18 refusals came only from broken padding. CTR refused nothing, because a changed ciphertext bit flips exactly the same plaintext bit.
From the lesson Block ciphers and modes: why ECB and raw CBC fail
-
What does ASVS 5.0 require to detect changes to encrypted data?
Requirement 11.3.3: detect changes, ideally with an authenticated encryption mode, otherwise with a standard cipher paired with a standard MAC. Requirement 11.3.5 fixes the order of that pair: encrypt-then-MAC. OWASP's Cryptographic Storage Cheat Sheet names it as the fallback when GCM or CCM is not available.
From the lesson Block ciphers and modes: why ECB and raw CBC fail
-
What does an encrypt-then-MAC format need to be safe?
Encrypt first, then compute a MAC over the ciphertext and everything the reader relies on, and check the tag before decrypting anything. Use two keys from one root key through HKDF, one label each; cover the version, the IV or counter block, the ciphertext and any header; verify in constant time first; and give one error for every failure. All 79 one-bit changes were refused.
From the lesson Block ciphers and modes: why ECB and raw CBC fail
-
Why is MAC-then-encrypt, or decrypting before checking, the wrong order?
The receiver then decrypts and unpads bytes nobody has vouched for. RFC 7366 notes that TLS's MAC-then-encrypt was the subject of security vulnerabilities over many years. Encrypt, MAC the ciphertext with its IV and header, and check the MAC before anything else.
From the lesson Block ciphers and modes: why ECB and raw CBC fail
-
What does an AEAD take and return?
RFC 5116 gives every AEAD one interface. Sealing takes a key, a nonce, the plaintext and associated data, and returns the ciphertext with an authentication tag; opening takes the same inputs and returns the plaintext, or FAIL and nothing else. AES-256-GCM sealed 16 bytes into 32, and one changed bit anywhere made opening fail.
From the lesson Authenticated encryption: AES-GCM and ChaCha20
-
How do AES-GCM and ChaCha20-Poly1305 differ?
AES-GCM (NIST SP 800-38D) runs AES in counter mode and authenticates with GHASH; it is fastest on processors with AES instructions, and SP 800-38D recommends a 96-bit IV. ChaCha20-Poly1305 (RFC 8439) takes a 256-bit key and a 96-bit nonce and gives a 128-bit tag. The RFC puts ChaCha20 at around three times the speed of AES in software on platforms without AES hardware, and notes it is not sensitive to timing attacks.
From the lesson Authenticated encryption: AES-GCM and ChaCha20
-
What does a failed AEAD open look like in Web Crypto and Node.js 24?
Flip a single bit in the ciphertext, or in the associated data, and decryption throws OperationError rather than returning any plaintext. In Node.js 24, ChaCha20-Poly1305 in Web Crypto is experimental and imported as raw-secret, never raw; node:crypto offers the same AEAD as a stable API, with the same tag.
From the lesson Authenticated encryption: AES-GCM and ChaCha20
-
What is associated data, and what do you put in it for a database field?
Data that is authenticated but neither encrypted nor stored in the ciphertext: the reader rebuilds it from where it found the record. RFC 5116 names fields such as addresses, sequence numbers and protocol versions. For a database use the table, the column, the record ID and the format's version, each field framed by its length so that two places never give the same bytes.
From the lesson Authenticated encryption: AES-GCM and ChaCha20
-
Why bind a sealed field to its table, column and row?
Otherwise a valid ciphertext copied into another user's row would decrypt there. Sealed without associated data, the lesson's copy opened in the wrong row; bound to its table, column and row it opened only in row 4211, and not in another row or column. The binding cost nothing to store: the blob was 44 bytes either way.
From the lesson Authenticated encryption: AES-GCM and ChaCha20
-
What does one repeated nonce under the same key expose?
In AES-GCM a nonce used twice under the same key leaks the XOR of two plaintexts, and NIST SP 800-38D warns that it may let an attacker forge messages from then on. In ChaCha20-Poly1305 (RFC 8439) a repeat repeats the keystream and the one-time Poly1305 key together, so the XOR of the two ciphertexts shows where the plaintexts agree. ASVS 5.0 (11.3.4) makes it a check: no nonce twice with one key.
From the lesson Nonces, usage limits and AEAD failure modes
-
What is NIST's rule for nonce uniqueness, and what does it cap for random nonces?
Across every message under a key, the chance that two use the same IV must be no more than 2^-32 (SP 800-38D), which it calls almost as important as keeping the key secret. With random 96-bit nonces that caps a key at 2^32 messages.
From the lesson Nonces, usage limits and AEAD failure modes
-
How soon does a key reach the random-nonce limit?
At 10,000 encryptions a second, the 2^32 cap arrives in 5 days; at 100 a second in 497 days; at a million a second in 1.2 hours. At 2^32 messages a repeat among random 96-bit nonces has a chance of 1.2 × 10^-10; at 2^48 it is 0.39, while 192-bit nonces stay at 6.3 × 10^-30.
From the lesson Nonces, usage limits and AEAD failure modes
-
Which five approaches answer nonce repetition?
Random 96-bit nonces: no state, but a cap of 2^32 messages per key. Counter nonces (a writer field and a counter): 2^64 per writer, if the counter survives restarts. XChaCha20-Poly1305: 192-bit random nonces that practically never repeat. AES-GCM-SIV: tolerates a repeat, revealing only that two messages were equal. A fresh key for every message, derived through HKDF with a random salt, makes the nonce irrelevant.
From the lesson Nonces, usage limits and AEAD failure modes
-
Which two AEAD failure modes come from the reader, and how are both prevented?
Decryption errors that differ by their cause, and plaintext used before its tag has been checked. Both are prevented the same way: one error for every failure and no output before the check.
From the lesson Nonces, usage limits and AEAD failure modes
-
Why is sealing each chunk of a file independently not enough?
Web Crypto has no streaming AEAD, so a large file is cut into 64 KiB chunks. Chunks sealed independently with random nonces are each protected, but not their order or their number: the file still decrypts after its last chunk is dropped, two chunks are swapped or a chunk is added.
From the lesson Encrypting files, streams and passphrase data
-
How does the age file format keep its chunks in place?
A random file key for this file alone, a 16-byte stream nonce, a payload key from HKDF over both, and 64 KiB chunks sealed with ChaCha20-Poly1305. Each chunk's 12-byte nonce is an 11-byte chunk counter and a flag that is 1 only for the last chunk. The counter stops reordering; the flag stops a file from being cut short or extended. The payload is a variant of STREAM.
From the lesson Encrypting files, streams and passphrase data
-
How much larger is a file sealed in age-style chunks, and what about empty files?
A 200,000-byte file seals into three full 64 KiB chunks and a last one of 3,392 bytes, and grows by 80 bytes: a 16-byte stream nonce plus a 16-byte tag for each of four chunks. An empty file still has one empty final chunk, so that its end is checked, and a file of exactly two chunks ends in a full final chunk, never an extra empty one.
From the lesson Encrypting files, streams and passphrase data
-
What does passphrase-protected data need before any key exists?
A slow key-derivation function, such as scrypt or PBKDF2 at 600,000 iterations. Its salt and cost, such as an age file's scrypt work factor, belong in the header of the passphrase data, where a reader finds them.
From the lesson Encrypting files, streams and passphrase data
-
When may a streaming reader write or show plaintext?
Not until the chunk's tag has checked, and for the whole file not until the final chunk has checked. A reader that releases plaintext earlier hands out bytes that nobody has verified.
From the lesson Encrypting files, streams and passphrase data
-
Why can a Feistel network decrypt even when its round function f cannot be inverted?
A round is L_i = R_(i−1) and R_i = L_(i−1) ⊕ f(R_(i−1), K_i). The right half moves left unchanged, so whoever holds the round key computes f again, forwards, on a value they already have and XORs it out. After the last round the halves are swapped once, so decryption is the same procedure with the round keys reversed. The toy's f maps 65,536 inputs onto 41,290 outputs and still decrypted 20,000 of 20,000 blocks.
From the lesson Feistel networks and a worked DES example
-
What are the four steps of the DES round function?
f(R, K) = P(S(E(R) ⊕ K)). Expand: E copies 16 of the 32 bits and makes 48. Add the key: the 48-bit round key is XORed in, the only place the key enters. Substitute: eight S-boxes each turn 6 bits into 4, the only non-linear part, which gives confusion. Permute: P moves the 32 bits so each S-box feeds several in the next round, which gives diffusion.
From the lesson Feistel networks and a worked DES example
-
How is a DES S-box read?
Of its 6 input bits, the outer two (the first and the last) choose one of 4 rows, and the inner four choose one of 16 columns. For 011000 the outer bits are 00 and the inner bits 1100, so S1 is read at row 0, column 12, which holds 5, or 0101.
From the lesson Feistel networks and a worked DES example
-
How does the DES key schedule turn 64 key bits into 16 round keys?
PC-1 drops the 8 parity bits (bits 8, 16, … 64), which makes two keys that differ only in those bits the same key, one of 56 bits. It splits the 56 into two 28-bit halves, which rotate left by 1 or 2 places before each round (1 in rounds 1, 2, 9 and 16; 28 in all), and PC-2 picks 48 bits as the round key. Decryption uses the 16 keys in reverse.
From the lesson Feistel networks and a worked DES example
-
What makes a DES key weak?
If both 28-bit halves are all zeros or all ones, rotating changes nothing, all 16 round keys are equal, and decryption, which only reverses their order, equals encryption. The 4 weak keys undo themselves and the 6 semi-weak pairs undo each other (4 of 4 and 6 of 6 in the lesson's run). A random key hits one of these 16 with a chance of about 2^-52, but a typed key can.
From the lesson Feistel networks and a worked DES example
-
How quickly does DES spread one flipped plaintext bit?
Averaged over 300 trials, one flipped bit changed 2.9 of the 64 state bits after round 1, 21.6 after round 3 and about half, 31 to 32, from round 5 on. One flipped key bit changed 31.9 of the 64 ciphertext bits. Diffusion is complete by round 5; the other rounds are a margin against shortcuts such as linear and differential cryptanalysis.
From the lesson Feistel networks and a worked DES example
-
Why is single DES retired, and what is complementation?
Its 56-bit key: an exhaustive search needs about 2^55 trials and one known plaintext block, and a machine the EFF built for under $250,000 tested more than 88 billion keys a second and found the key of RSA's DES Challenge II in 56 hours. Complementation, E(~K, ~P) = ~E(K, P), lets a chooser of plaintexts test two keys per encryption, halving the search to about 2^54.
From the lesson Feistel networks and a worked DES example
-
Can DES still be reached in Node.js 24, and how can single DES hide inside Triple DES?
des-ecb and des-cbc are not listed unless Node starts with --openssl-legacy-provider, and Web Crypto has no DES. But des-ede3 is still listed, and with three equal keys it computes single DES. So a check that looks only for des-ecb and des-cbc misses it: a Triple DES key whose three 8-byte parts are equal is a single DES key.
From the lesson Feistel networks and a worked DES example
-
What does double encryption under two independent keys buy, and how is it attacked?
About one bit. With one known plaintext P and its ciphertext C, the middle value M = E(K1, P) = D(K2, C) lets an attacker search each half alone and compare the two lists: a meet-in-the-middle attack costing about 2^k operations and 2^k stored values for a k-bit key. At DES's size that is about 2^57 calls, not 2^112.
From the lesson Multiple encryption, 3DES and 64-bit block limits
-
How many cipher calls did the lab's meet-in-the-middle search take, and what did it show?
131,072: 65,536 to fill the table and 65,536 to look values up, against up to 8,589,934,592 to try every pair of 16-bit keys. A single 16-bit key falls to at most 65,536 trials, so the second key only doubled the attacker's work: about one bit.
From the lesson Multiple encryption, 3DES and 64-bit block limits
-
How does Triple DES work, and why is its middle call a decryption?
Three DES calls on each block: encrypt with K1, decrypt with K2, encrypt with K3. With K1 equal to K2 the first two calls cancel and the result is single DES under K3, so 3DES equipment could still talk to old DES systems.
From the lesson Multiple encryption, 3DES and 64-bit block limits
-
What are the Triple DES keying options and their status?
Three-key (3TDEA): K1, K2, K3 all different, 168 key bits, 112 bits of strength, disallowed after 2023. Two-key (2TDEA): K3 = K1, 112 key bits, up to 80 bits, disallowed. K1 = K2, K2 = K3 or all equal: single DES in disguise, 56 bits, not a valid key bundle (SP 800-67). OpenSSL computes the invalid bundles without complaint.
From the lesson Multiple encryption, 3DES and 64-bit block limits
-
Why does a 64-bit block limit the data under one key, whatever the key length?
Among n random blocks the chance that two are equal is about n² ÷ 2^65, near one half at n = 2^32 blocks: 32 GiB for DES and 3DES, against 2^64 blocks (256 EiB) for AES's 128-bit block. In CBC two equal ciphertext blocks reveal the XOR of two plaintext blocks, which Sweet32 (2016) turned into a practical attack on long-lived 3DES connections.
From the lesson Multiple encryption, 3DES and 64-bit block limits
-
What limit does NIST put on one Triple DES key bundle?
At most 2^20 blocks, 8 MiB, down from 2^32 in the 2012 edition of SP 800-67. A 64-bit block retires a cipher even when its key is long enough to survive any search.
From the lesson Multiple encryption, 3DES and 64-bit block limits
-
What are the four steps of an AES round, and which one uses the key?
AES lays the 16-byte block out as a 4 × 4 grid of bytes, the state. SubBytes replaces every byte through a fixed 256-byte table, the S-box. ShiftRows moves row r r places to the left. MixColumns mixes the four bytes of each column so each output byte depends on all four. AddRoundKey XORs 16 bytes of the round key in, and is the only step that uses the key. The last round leaves out MixColumns.
From the lesson AES rounds and key expansion, step by step
-
How many rounds and round keys does AES use?
10, 12 or 14 rounds for a 128-, 192- or 256-bit key, and 11, 13 or 15 round keys, because AddRoundKey also runs once before round 1. Key expansion stretches the cipher key into all of them.
From the lesson AES rounds and key expansion, step by step
-
Why is AES a substitution-permutation network and not a Feistel network?
Every AES step works on the whole state, so every step must be invertible for decryption to undo it. A Feistel network, like DES, works on half a block at a time and never inverts its round function.
From the lesson AES rounds and key expansion, step by step
-
What does FIPS 197's worked example let you check?
The block 3243f6a8…e0370734 becomes 3925841d…196a0b32 under the key 2b7e1516…09cf4f3c, and the standard prints the state after every step. In round 1's first column SubBytes turns 19 3d e3 be into d4 27 11 ae, MixColumns turns d4 bf 5d 30 into 04 66 81 e5, and the first column of round key 1 makes it a4 9c 7f f2.
From the lesson AES rounds and key expansion, step by step
-
How do CFB and OFB turn one AES call into a stream cipher, and how do they differ?
One AES call E(K, B) makes 16 bytes of mask, which is XORed with the data, so nothing needs padding. CFB starts with the IV and feeds the ciphertext just produced into the next call: c_i = p_i ⊕ E(K, c_(i−1)). OFB feeds back the cipher's own output: c_i = p_i ⊕ O_i with O_i = E(K, O_(i−1)). In NIST's example both give the same first block and differ from the second on.
-
Does decrypting in CFB or OFB run the block cipher backwards?
No. The mask only ever comes from the encrypt direction, so decrypting is the same XOR with the same E, and one AES function builds either mode. Data that ends before a whole block needs no padding in OFB, in CFB8 or in OpenSSL's CFB, because its last piece takes the leading bytes of the last mask.
-
What is CFB's segment size, and what does CFB8 cost?
NIST's parameter s is the number of bits each cipher call handles. CFB128 uses all 128 bits of the output; CFB8 uses only 8, so it makes one AES call per byte, 16 times as many: 160 bytes take 160 calls instead of 10.
-
Which other legacy block cipher modes sit in old code and file formats?
Old code and file formats also hold ECB (each block on its own), CBC (each ciphertext block chained into the next) and CTR (a counter encrypted to make the mask), used without an authentication tag. CFB and OFB resemble CTR in one way: the block cipher only makes masks, so one AES function is enough to build any of them.
-
How does CBC-MAC compute its tag?
It is CBC encryption with the IV fixed at zero: H1 = E(K, m1), Hi = E(K, H(i−1) ⊕ mi), and the tag is the last H. A receiver that shares the key recomputes it. Whoever lacks the key cannot make a tag for a message of their choice, which is the property the lesson puts to the test.
From the lesson CBC-MAC, CMAC and hashes built from block ciphers
-
How does CMAC differ from CBC-MAC?
CMAC (NIST SP 800-38B, RFC 4493) keeps the chain and changes only the last block: it derives two subkeys from the one key and XORs one into the final block, which lets it handle a message of any length, the empty message included. RFC 4493 publishes four test messages of 0, 16, 40 and 64 bytes; the first tag is bb1d6929…, and a correct implementation reproduces all four.
From the lesson CBC-MAC, CMAC and hashes built from block ciphers
-
How can a block cipher make a hash, and what does the Davies-Meyer form add?
Every message block serves as the cipher's key, and a chaining value is handed from block to block. The plain chain computes Hi = E(Mi, H(i−1)); the Davies-Meyer hash (HAC Algorithm 9.42) adds the old value back: Hi = E(Mi, H(i−1)) ⊕ H(i−1).
From the lesson CBC-MAC, CMAC and hashes built from block ciphers
-
CBC-MAC, CMAC and block-cipher hashes all run a cipher along a chain. What differs in what protects them?
In a MAC the secret key protects the chain: without it nobody can make a tag for a message of their choice. A hash has no secret, so every step of its chain is open to a searcher, and the design must hold up in the open.
From the lesson CBC-MAC, CMAC and hashes built from block ciphers
-
What problem does envelope encryption solve?
With one key for a table, rotating it means rewriting every record (41 GB for 10 million records of 4 KiB), one theft opens everything, and erasing one customer's data means rewriting the table. Envelope encryption seals each record with its own data encryption key (DEK) and encrypts only DEKs with a key-encryption key (KEK): re-wrapping 10 million 60-byte keys touches 600 MB.
From the lesson Envelope encryption and data at rest
-
What are the steps of a write and a read in envelope encryption?
Write: make a DEK for this record and encrypt the data with it (AES-GCM); the key store seals the DEK under the KEK and returns the wrapped key; store the KEK's id, the wrapped DEK, the nonce and the data. Read: the reverse, with one call to the key store per record. The KEK should be a key that code can use but not export; in production it lives in a KMS or an HSM.
From the lesson Envelope encryption and data at rest
-
What goes into the associated data of an envelope-encrypted record?
The row (table, column and id) goes into the associated data of both the data and the wrap, so a record opens only where it belongs. The KEK's id goes into the wrap's associated data only, so that a rotation never has to touch the data.
From the lesson Envelope encryption and data at rest
-
After which events do you re-wrap keys, and after which do you re-encrypt data?
A calendar rotation: new KEK, re-wrap every DEK, leave the data. A leaked KEK: new KEK, re-wrap, then re-encrypt the data under fresh DEKs and treat earlier copies as exposed, because an old wrap plus the leaked KEK still opens today's data. A leaked DEK: re-encrypt the records it protects. The old KEK stays until the last record and the last backup holding an old wrap are done.
From the lesson Envelope encryption and data at rest
-
What is crypto-shredding, and what is its catch?
Erasing data by destroying the key that protects it: destroy a record's DEK and every copy of it. It works only if no copy of the key survives. With the KEK destroyed, 0 of 3 records opened; with the key store restored from a backup, 3 of 3 opened again. Copies of the plaintext in backups, logs and caches must go as well.
From the lesson Envelope encryption and data at rest
-
What does a blind index or deterministic encryption cost in what a table reader learns?
Equal values show as equal. A blind index stores, in an extra column, the HMAC of each normalised value, keyed with a key that belongs to that column alone. The 8-value state column's index gave exactly the plain column's frequency table, and a short index returns extra rows to decrypt and drop: 1.03 per lookup at 16 bits in 2,000 rows, about 154 in 10 million. Index only what must be searched by exact value.
From the lesson Envelope encryption and data at rest
-
How do encryption, masking and tokenisation differ?
Encryption: the value comes back with the key, a database copy shows each value's length, and you protect the keys. Masking removes part of the value for good, a display decision rather than storage: keeping the last 2 digits left 1,000 numbers in 100 groups. Tokenisation swaps the value for a random token and keeps it in a vault: equal numbers get equal tokens, and you protect the vault, its backups and its audit trail.
From the lesson Envelope encryption and data at rest
-
What does Rule 6 of India's DPDP Rules, 2025 say about encryption and logs?
Rule 6(1)(a) gives encryption, obfuscation, masking and virtual tokens mapped to the data as examples of appropriate security measures. Rule 6(1)(c) asks for visibility on access through logs, monitoring and review, and Rule 6(1)(e) for keeping the logs and personal data needed to detect and investigate unauthorised access for one year. The Rules prescribe no algorithm.
From the lesson Envelope encryption and data at rest
-
What are the states of a key's lifecycle in NIST SP 800-57?
Pre-activation: generated, protects nothing. Active: protects new data and opens old. Suspended: protects nothing new while a possible exposure is checked. Deactivated: protects nothing new but may still open old data. Compromised: exposed or suspected, revoked, never protects again. Destroyed: only metadata such as its name and history may stay.
From the lesson Key lifecycle, rotation and KMS
-
What is a cryptoperiod, and what does SP 800-57 advise for a data-encryption key?
The span in which a key is authorised for use. The originator-usage period is when it may protect data; the recipient-usage period is when it may still open what it protected. Advice: a day or a week when it encrypts large volumes quickly, up to two years for smaller volumes, with a recipient period of no more than three years beyond. AWS KMS automatic rotation makes new key material every 365 days by default.
From the lesson Key lifecycle, rotation and KMS
-
Why put a version and a key ID in the header of every ciphertext?
A ciphertext that does not name its key can only be opened by trying keys, which is how rotations go wrong. The version fixes the algorithm and layout and the key ID picks the key. The header is not secret but must not be changeable, so it goes into the AEAD's associated data. ASVS 5.0 asks for it: 11.2.2 wants keys that can be replaced, with the data re-encrypted, and 11.1.2 a list of all keys, algorithms and certificates in use.
From the lesson Key lifecycle, rotation and KMS
-
What happened in the key ring when k1 was retired too early?
After the rotation, new records used k2 while the three k1 records still opened. Retiring k1 too early left only 1 of 4 records readable, because the three that still named k1 could not be opened; re-encrypting those three first left 4 of 4. A changed header, an unknown key, another row's associated data and a truncated blob all gave the same error.
From the lesson Key lifecycle, rotation and KMS
-
What do a KMS, an HSM, an encryption context and an audit log each add?
A key ring inside your process lets any code in it read the key. A KMS generates, stores and uses keys for you, so key material never leaves it. An HSM is tamper-resistant hardware that does the cryptography inside it. An encryption context is non-secret data, such as a tenant id, bound to a ciphertext so it opens only when presented again. An audit log records who called, which operation, key and context, and whether it succeeded.
From the lesson Key lifecycle, rotation and KMS
-
What does a secrets manager do?
A service that keeps secrets such as passwords and tokens, rotates them, and passes them to applications while they run.
From the lesson Key lifecycle, rotation and KMS
-
What are the three jobs of a key pair, and which algorithms do them?
Key encapsulation: anyone with the public key wraps a fresh symmetric key and only the private key unwraps it (RSA-OAEP; ML-KEM later). Key agreement: each side combines its own private key with the other's public key and gets the same secret (X25519, ECDH). Signatures: the private key signs and anyone with the public key checks (Ed25519, ECDSA, RSA-PSS). None encrypts a file itself; AES-GCM or ChaCha20-Poly1305 does the bulk work.
From the lesson Public-key cryptography: RSA and elliptic curves
-
Why does textbook RSA fail?
With c = m^e mod n it is deterministic, so the same message always gives the same ciphertext and a watcher learns when two messages are equal; and malleable, since the product of two ciphertexts is the ciphertext of the product. On the toy key 250 gave 148,245 both times, and a ciphertext times 2^e mod n opened as 500 with no private key. RSA-OAEP passed both checks.
From the lesson Public-key cryptography: RSA and elliptic curves
-
Which RSA schemes should new code use?
RSAES-OAEP for encryption and key wrapping, and RSASSA-PSS for signatures; RFC 8017 requires both for new applications. RSAES-PKCS1-v1_5 is kept for old systems (ASVS 11.3.1 rules it out), and RSASSA-PKCS1-v1_5 only to talk to old systems (ASVS Appendix C disallows it). A few random bytes glued to a message are not padding.
From the lesson Public-key cryptography: RSA and elliptic curves
-
Which curves serve which jobs, and why is Ed25519 the usual first choice for signing?
NIST P-256, P-384 and P-521 (SP 800-186) serve ECDSA and ECDH. Curve25519 and Curve448 (RFC 7748) serve key agreement as X25519 and X448, and their Edwards forms serve signatures as Ed25519 and Ed448 (RFC 8032). Ed25519 needs no fresh random number per signature, has small keys and 64-byte signatures, and needs no costly checks of untrusted public keys. P-256 stays where a standard asks for NIST curves.
From the lesson Public-key cryptography: RSA and elliptic curves
-
How large are public keys at 128-bit security?
P-256: 65 bytes raw (91 as SPKI). Curve25519 and Edwards25519: 32 bytes raw (44 as SPKI). RSA-3072: 422 bytes as SPKI, a 384-byte modulus against a 32-byte Ed25519 key, 12 to 1. RSA-2048 reaches only 112 bits, RSA-4096 still only 128, and 192 bits need 7,680.
From the lesson Public-key cryptography: RSA and elliptic curves
-
What does NIST's draft transition plan do to 112-bit keys, RSA and elliptic curves?
It deprecates 112-bit security after 2030 and disallows RSA and elliptic curves after 2035, in favour of ML-KEM and ML-DSA. A key that must sign or agree beyond 2035 needs a post-quantum algorithm, and RSA-2048 is a poor choice for anything new even before then.
From the lesson Public-key cryptography: RSA and elliptic curves
-
What does Web Crypto bind to every key it makes?
One algorithm and the operations it may perform, its usages: an RSA-OAEP private key unwraps or decrypts, X25519 and ECDH keys use deriveBits or deriveKey, and Ed25519, ECDSA and RSA-PSS keys sign. An RSA-OAEP private key refused to sign with InvalidAccessError, although an RSA-PSS key of the same size could.
From the lesson Public-key cryptography: RSA and elliptic curves
-
A signature check passes. Why is that not enough to trust an update?
Every key verifies what it signed itself. An attacker who swaps the vendor's key can sign their own update and send their key along. Decide which key is authentic first: a pinned fingerprint (the swapped key's deb2ded3… did not match the pinned 06e3fd8f…), a certificate from an authority you trust, or a directory you trust.
From the lesson Public-key cryptography: RSA and elliptic curves
-
How do two parties agree on a secret over a public channel with X25519?
Each picks a private number, a or b, and publishes a·G or b·G. Alice multiplies Bob's public key by a, Bob multiplies Alice's by b, and both reach (ab)·G. A watcher who holds both public keys must solve the Diffie-Hellman problem on the curve, about 2^126 steps on Curve25519. Only two public values cross the network; no secret is ever sent.
From the lesson Key agreement with X25519 and ECDH
-
How do X25519 and ECDH on P-256 compare?
X25519: a 32-byte public key, any 32 bytes import as a key, a 32-byte secret; in Web Crypto from Chrome 133, Firefox 130 and Safari 17. ECDH on P-256: public keys of 65 bytes (0x04, then x and y), a point off the curve is refused with DataError, the 32-byte secret is the x-coordinate; wherever Web Crypto exists. X25519 is the usual choice; P-256 when a policy allows only NIST curves or older browsers must be served.
From the lesson Key agreement with X25519 and ECDH
-
Which published vectors check X25519 and ECDH, and what did the run show?
RFC 7748 section 6.1 for X25519 (shared secret 4a5d9d5b…1e161742) and RFC 5903 section 8.1 for ECDH on P-256 (d6840f6b…4b9442de), computed from each side. Once the keys are chosen, agreement uses no randomness: generated keys gave the same secret on both sides and again on a repeat.
From the lesson Key agreement with X25519 and ECDH
-
Why is the raw shared secret not yet a key to encrypt with?
Four things are missing. A key for each direction and purpose: HKDF turns the secret into separate keys bound to both public keys. A way to know who the other side is: agreement alone says nothing about identity, so a signature over the exchange made with a key the peer already trusts supplies it. A key used once. And a refusal of bad peer values.
From the lesson Key agreement with X25519 and ECDH
-
What do ephemeral keys give, and what does a small-order peer value do?
Ephemeral keys, deleted after the exchange, give forward secrecy: a later leak of a long-term key opens no recorded session. A peer value of small order makes the shared secret all zero, and careful code rejects it.
From the lesson Key agreement with X25519 and ECDH
-
How does a web app use X25519 in every browser?
Feature-test it: try X25519 first and fall back to ECDH on P-256 when the call throws, so that the app works in every browser.
From the lesson Key agreement with X25519 and ECDH
-
What does verifying a signature answer, and what does it leave open?
One question: did the private key that matches this public key sign exactly these bytes? It says nothing about who owns the key, whether the message is fresh or what it means, and the public key must be authentic before the answer counts. A verify call returns a boolean and never a reason, and a boolean is all a verifier should act on.
From the lesson Digital signatures: Ed25519, ECDSA and RSA-PSS
-
How do Ed25519, ECDSA on P-256 and RSA-PSS 3072 compare in size and randomness?
Ed25519 (RFC 8032): 32-byte public key, 64-byte signature, no random number. ECDSA on P-256 (FIPS 186-5): 65-byte public key, 64-byte raw signature (usually 70 to 72 bytes as DER), a secret random number, fresh for each signature. RSA-PSS 3072 (RFC 8017): 422-byte public key, 384-byte signature, a salt that is not secret.
From the lesson Digital signatures: Ed25519, ECDSA and RSA-PSS
-
Why should a cross-browser test verify an Ed25519 signature instead of comparing its bytes?
RFC 8032 derives the per-signature value from the key and the message, so Node.js gave identical bytes when signing twice. Safari's Web Crypto adds fresh randomness to its Ed25519 signatures, which still verify. Verify the signature; do not compare it.
From the lesson Digital signatures: Ed25519, ECDSA and RSA-PSS
-
What happened to the Ed25519 signatures of RFC 8032 under small changes?
Both test signatures equalled the RFC's, 64 bytes each. A flipped bit of the signature, or one added byte of the message, made verification return false.
From the lesson Digital signatures: Ed25519, ECDSA and RSA-PSS
-
What shape do ElGamal, Schnorr and DSA signatures share?
Each signs with a fresh secret number, the signing nonce, and publishes its power as a commitment. A response then mixes the message hash, the private key x and the nonce k, so only the key's owner can produce it and anyone can check it from public values alone. The public key is y = g^x.
From the lesson DSA, ElGamal and Schnorr signatures
-
What weakness do all three schemes share, and what repairs it?
Each gives up the private key if the signing nonce repeats, is guessed or is too short: one reused nonce is enough. Ed25519 and ECDSA come from this family, so the audit applies to them too. Deterministic nonces derived from the key and the message need no random number, and every verifier should range-check.
From the lesson DSA, ElGamal and Schnorr signatures
-
How do ElGamal, Schnorr and DSA signatures differ in form and size?
ElGamal: r = g^k modulo p, and s is k⁻¹ times (h − x·r) modulo p − 1; two numbers modulo p, 512 bytes in a 2,048-bit group. Schnorr: a hashed challenge e and s = k + x·e, 64 bytes with a 256-bit order; Ed25519 is a variant. DSA folds ElGamal into a subgroup of prime order q, so its two numbers are modulo q and take 64 bytes too.
From the lesson DSA, ElGamal and Schnorr signatures
-
What do the lesson's toy ElGamal numbers show, and why does the check work?
With p = 31, g = 3, private key 7, hash 10 and nonce 11, the public key is 17 and the signature (13, 9); both sides of the check equal 25. The check holds because y^r · r^s collapses to g^(x·r + k·s). Now k·s equals h − x·r modulo p − 1, so the exponent is just h.
From the lesson DSA, ElGamal and Schnorr signatures
-
Where does DSA stand in current standards?
NIST no longer allows DSA for making new signatures, so a new design uses Ed25519 or ECDSA; DSA remains only for verifying old signatures.
From the lesson DSA, ElGamal and Schnorr signatures
-
How much can RSA-OAEP encrypt directly?
RFC 8017 leaves k − 2·hLen − 2 bytes for the message, where k is the modulus length in bytes and hLen the hash length. Found by trying, the limit is 190 bytes for the 2,048-bit key and 318 for the 3,072-bit key with SHA-256; one byte more throws OperationError, so a 1 MiB file does not fit.
From the lesson Public-key encryption, hybrid schemes and HPKE
-
Why does public-key encryption wrap a key instead of encrypting the data?
It protects a short key and a symmetric cipher protects the data under it. Encrypting a 1 MiB file directly with a 2,048-bit RSA key would take 5,519 RSA operations and give 1,412,864 bytes. The hybrid way takes one operation to wrap a 32-byte key into 256 bytes and one AES-GCM call for the file, 1,048,860 bytes in all.
From the lesson Public-key encryption, hybrid schemes and HPKE
-
What is hybrid encryption?
Public-key encryption wraps a fresh symmetric key, and an AEAD encrypts the data under that key, so the cost and size of the message follow the cipher and not the modulus. Hybrid schemes in general encapsulate a fresh key for the recipient.
From the lesson Public-key encryption, hybrid schemes and HPKE
-
What is HPKE?
The standard hybrid scheme, defined in RFC 9180: it fixes one key encapsulation, one key derivation function and one AEAD, and comes with test vectors for all of them. RSA-OAEP, by contrast, only wraps a short key under an RSA public key, with random padding that decryption checks.
From the lesson Public-key encryption, hybrid schemes and HPKE
-
What are the forms of a public key, and what does each carry?
Raw: the bare bytes (32 for Ed25519), naming no algorithm. SPKI: the X.509 SubjectPublicKeyInfo in binary DER, with an algorithm identifier in front (44 bytes for Ed25519). PEM: DER in Base64 between two label lines (RFC 7468). JWK: JSON (RFC 7517) with the key type in kty. A private key is PKCS#8 in DER, or a JWK that adds d.
From the lesson Key formats: PEM, DER, JWK and raw keys
-
How are Ed25519 keys laid out as SPKI and PKCS#8?
The SPKI is a 12-byte prefix and the 32 key bytes (44 in all). The PKCS#8 form of the private key is a 16-byte prefix and the 32-byte seed. All the forms of the public key load back as the same key.
From the lesson Key formats: PEM, DER, JWK and raw keys
-
How do the SHA-256 of an SPKI and a JWK thumbprint differ?
They are two distinct names for the same key. For RFC 8032's TEST 1 key, the SHA-256 of the SPKI starts 06e3fd8f…, while the JWK thumbprint is kPrK_qmx…, equal to the one in RFC 8037. A system that stores one name and is handed the other finds no match.
From the lesson Key formats: PEM, DER, JWK and raw keys
-
How does handing a function the wrong key form fail?
Rarely with a message about formats: it fails with DataError, with a decoder code, or, worst of all, with no error. Which form a function expects decides whether the key loads.
From the lesson Key formats: PEM, DER, JWK and raw keys
-
What is a bearer secret, and how many random bits must it carry?
RFC 6750: any party in possession of the token can use it, and the server checks nothing about who sent it, so the only protection against guessing is the random bits behind it. ASVS 5.0 requirement 11.5.1 sets the floor: a CSPRNG and at least 128 bits of entropy for every value meant to be non-guessable. OAuth (RFC 6749 section 10.10) asks for a guessing chance of at most 2^-128, preferably 2^-160. A UUID does not qualify.
From the lesson Bearer secrets: reset links, API keys and CSRF
-
How long does guessing take for 32, 64 and 128 bits, and why can a six-digit code be safe?
With 100,000 valid tokens and 10,000 guesses a second, a 32-bit token fell in 4.3 seconds and 64 bits take about 585 years (213 days against a guesser a thousand times faster). With 128 bits even a guesser a billion times faster needs about 10^13 years. A six-digit emailed code has 20 bits and is safe only because it lives at most 10 minutes and attempts are limited: five attempts leave a 0.0005 % chance.
From the lesson Bearer secrets: reset links, API keys and CSRF
-
What should the database keep for a reset token, and why is a fast hash enough?
A selector, the public name of the row, and the SHA-256 of the verifier, the secret. The link carries both; the server looks the row up by selector, hashes the presented verifier and compares the digests in constant time. The selector alone is never accepted. A fast hash is enough because 128 random bits leave no list of likely values to hash; ASVS 6.5.2 lets a secret with at least 112 bits use a standard hash.
From the lesson Bearer secrets: reset links, API keys and CSRF
-
What makes a password-reset flow safe in time and in state?
The link lives for minutes (an out-of-band code at most 10 minutes) and works once, and a newer request, a used link or a password change ends older links. Serve the reset page with Referrer-Policy: no-referrer, and let the server swap the token for a short-lived session that may only set a password. Build the link from a configured address, never the Host header; answer the same whether or not an address has an account; log the selector, never the verifier.
From the lesson Bearer secrets: reset links, API keys and CSRF
-
What makes an API key format easy for scanners to recognise?
A prefix that names the kind of token and its environment (demo_live_), then 43 Base62 characters from 32 random bytes (256 bits), then six characters that are the CRC-32 of everything before. The server stores the SHA-256 of the whole key, and the prefix and last four characters to show in a list. The checksum is no security feature: it only makes false alarms cheap to dismiss. RFC 8959 registers the secret-token URI scheme.
From the lesson Bearer secrets: reset links, API keys and CSRF
-
How do opaque, signed and encrypted session tokens differ?
Opaque: a random ID, with the data on the server. Signed: the data plus an HMAC tag that detects changes; the holder can still read it. Encrypted: the data under an authenticated cipher such as AES-GCM, which hides it and detects changes. Delete the opaque row and the cookie is refused at once; signed and encrypted cookies stay valid until they expire unless you keep a list of ended tokens, a per-user cut-off or a rotated key (ASVS 7.4.1).
From the lesson Bearer secrets: reset links, API keys and CSRF
-
How is a session-bound CSRF token built and checked?
OWASP's signed double-submit cookie: the token is the HMAC in hex, a dot and a random value (64 bytes as 128 hex characters). The HMAC's message holds the length and value of the session ID and of the random value, with ! between the parts; the session ID goes into the HMAC but never into the token. The server keeps no table: it recomputes the HMAC and compares in constant time. Lengths stop a!b with c and a with b!c from making one string.
From the lesson Bearer secrets: reset links, API keys and CSRF
-
Does a SameSite cookie replace a CSRF token?
No, it is defence in depth. It is scoped to a registrable domain, not to an origin, and the Lax setting still sends the cookie on a top-level navigation with a safe method such as GET. OWASP also advises against an expiry time in a CSRF token: it lives as long as the session, and a new session gets a new token.
From the lesson Bearer secrets: reset links, API keys and CSRF
-
What is a compact JWS made of, and what does its signature cover?
Three Base64url strings joined by dots: header, payload and signature. The header says how the signature was made (alg) and often which key (kid); the payload is any bytes, a JWT's claims in a JWT. The signature covers the ASCII text of the first two strings with the dot between them, the signing input, and nothing else: in RFC 7515's 179-character example, 135 characters are signed and 43 are the signature.
From the lesson JOSE internals: JWS, JWE and JWK
-
Why must a verifier check a JWS over the strings exactly as they arrived?
RFC 7515's header has a carriage return, a line feed and a space inside it, so the signed text is not the compact JSON that a parser writes back. Reading the header as JSON and writing it out again gave a different Base64url string, and the check failed although the JSON means the same thing. Check the two strings as received, then read their contents.
From the lesson JOSE internals: JWS, JWE and JWK
-
Who chooses the algorithm and the key when verifying a JWT?
The verifier, never the token. RFC 8725 says to take the set of algorithms from your own configuration and use each key with exactly one algorithm, checking that the header agrees; ASVS 5.0 (9.1.2) asks for an allowlist per context that never includes none. Until the signature is checked, alg is text anyone could have written.
From the lesson JOSE internals: JWS, JWE and JWK
-
What does a verifier that follows the token's header accept?
alg: none, so no check runs; alg: HS256 with the MAC keyed by the RSA public key, which anyone holding that key could have built (algorithm confusion); and a jku or jwk header naming the sender's own key. A verifier that pins one algorithm to each key refuses the first two and ignores the third, finding the key by kid.
From the lesson JOSE internals: JWS, JWE and JWK
-
How should a verifier use kid, jku, x5u and jwk headers?
RFC 7515 calls kid a hint about which key was used, so use it only to pick among keys the verifier already trusts. A header that points at a key (jku, x5u or jwk) is never followed to wherever the token says.
From the lesson JOSE internals: JWS, JWE and JWK
-
What are a JWE, a JWK and a JWKS?
A JWE encrypts instead of signing: one layer protects a content key and a second layer encrypts the data with it. A JWK writes a key as JSON. A JWKS is a set of JWKs that a service publishes so that others can find its public keys by kid.
From the lesson JOSE internals: JWS, JWE and JWK
-
Why is a bearer access token a problem, and what are the three ways to bind it?
A copy from a log, a proxy or a crash report works for anyone until it expires, often an hour. PKCE ties an authorization code to a secret that only the app that started the login holds. DPoP ties an access token to a key pair, with a fresh signed proof for every request. Certificate-bound tokens, using mutual TLS, tie an access token to the client's TLS certificate.
From the lesson PKCE, DPoP and certificate-bound tokens
-
How does PKCE protect an authorization code?
Before the request the app draws a random code verifier, 32 random bytes written as 43 characters, and sends just the SHA-256 hash of it, the code challenge, with the authorization request. It sends the verifier itself later, with the code, to the token endpoint, and the server hashes it and compares. RFC 7636 defines it; RFC 9700 requires it for public clients and recommends it for confidential ones.
From the lesson PKCE, DPoP and certificate-bound tokens
-
Why can the PKCE challenge travel in an address another app may read?
It is one-way: the hash cannot be turned back into the verifier. A token request with the copied code and no verifier, or with the challenge in place of the verifier, was refused. RFC 7636's example matched: the 43-character verifier hashes to the challenge the RFC prints.
From the lesson PKCE, DPoP and certificate-bound tokens
-
What does PKCE protect, and what do DPoP and certificate binding protect?
PKCE protects the authorization code. DPoP and certificate-bound tokens protect the access token it is exchanged for: a DPoP-bound token works only with a signature, made for each request, by the key it was issued to; a certificate-bound token works only on a mutual TLS connection, where the client presents that certificate in the handshake.
From the lesson PKCE, DPoP and certificate-bound tokens
-
How does HOTP turn a key and a counter into a six-digit code?
HMAC-SHA-1 of the shared key (20 random bytes in the RFC) and the counter written as 8 bytes, most significant first. Dynamic truncation (RFC 4226 section 5.3) shortens the 20-byte result: the last 4 bits of its final byte are an offset, the 4 bytes starting there form a 31-bit number, which is reduced modulo 10^6 to give the code. The RFC requires at least six digits and allows seven or eight.
From the lesson HOTP and TOTP: one-time passwords done right
-
How do HOTP and TOTP differ?
HOTP (RFC 4226) computes the code from a counter that rises with every use. TOTP (RFC 6238) feeds the same function a count of 30-second steps since 1970, so the code changes by itself twice a minute. In both, the shared key never crosses the network at login, only a short code.
From the lesson HOTP and TOTP: one-time passwords done right
-
Which values check an HOTP implementation?
RFC 4226 Appendix D: the 20-character key 12345678901234567890 and the ten codes for counters 0 to 9, all of which matched. The hand-worked sample of section 5.4 ends in offset 10 and the code 872921.
From the lesson HOTP and TOTP: one-time passwords done right
-
Why does an HOTP server accept a few counter values ahead?
The app's counter goes up each time a code is shown, whether or not the code is sent, so the server keeps its own counter and accepts a few values ahead of it. RFC 4226 section 7.4 asks for that look-ahead to be as small as usability allows.
From the lesson HOTP and TOTP: one-time passwords done right
-
What does 'done right' mean for one-time passwords, and what do they still not stop?
Exact arithmetic that passes the RFC test vectors, a small clock window, each code accepted once, a cap on wrong guesses, a key encrypted at rest and recovery codes stored as hashes. Even then a code is not phishing-resistant: a look-alike page can pass a fresh code to the real site while it is valid.
From the lesson HOTP and TOTP: one-time passwords done right
-
Why does a passkey resist a look-alike sign-in page?
The device makes a key pair for one site, keeps the private key and signs a fresh challenge; the site keeps only the public key, so nothing typed exists to be passed on. What is signed includes the site's identity: the authenticator data holds the SHA-256 hash of the RP ID and the client data holds the origin the browser saw. A look-alike has another origin and cannot use the real RP ID.
From the lesson Passkeys: verifying WebAuthn assertions
-
In what order is a WebAuthn assertion verified?
Check the challenge first, then the origin, the RP ID hash, the flags, the signature, and the counter last.
From the lesson Passkeys: verifying WebAuthn assertions
-
What do the client data and the authenticator data hold in a WebAuthn sign-in?
The client data is JSON written by the browser: the type webauthn.get, the challenge in Base64url and the origin (the browser fills in the origin, not the page). The authenticator data is written by the authenticator: 32 bytes of the SHA-256 of the RP ID, one byte of flags and a 4-byte counter, 37 bytes in all.
From the lesson Passkeys: verifying WebAuthn assertions
-
What does a WebAuthn signature cover, and what do the flags 0x19 say?
The authenticator data with the SHA-256 hash of the client data appended: 37 + 32 = 69 bytes in the specification's test vector. A look-alike origin changes the client data, so the hash changes and the signature stops matching. The flags byte 0x19 says the user was present and not verified, and the credential is backup eligible and backed up.
From the lesson Passkeys: verifying WebAuthn assertions
-
What are the three secrets of the TLS 1.3 key schedule, and what does each add?
Early Secret: HKDF-Extract of the pre-shared key, or 32 zero bytes when there is none (a missing secret does not skip a round), giving the early-data key. Handshake Secret: Extract of the key exchange result under a salt derived from the Early Secret, giving the handshake traffic secrets. Main Secret: Extract of 32 zero bytes under a salt derived from the Handshake Secret, giving the application traffic, exporter and resumption secrets. A lower secret cannot be computed without all those above it.
From the lesson TLS 1.3 key schedule and handshake secrets
-
What do HKDF-Expand-Label and Derive-Secret compute in TLS 1.3?
HKDF-Expand-Label(Secret, Label, Context, Length) is HKDF-Expand with an info made of the output length (2 bytes), the label behind the six characters tls13 with a length byte, and the context with a length byte. Derive-Secret(Secret, Label, Messages) is Expand-Label with the transcript hash of the messages as context and a hash-sized output. Keys and IVs use the labels key and iv with an empty context.
From the lesson TLS 1.3 key schedule and handshake secrets
-
What is the context of Derive-Secret(secret, "derived", ""), and what happens if you get it wrong?
Not an empty string: the 32-byte SHA-256 of nothing, e3b0c442…, which is what hashing no messages gives. The info is then 49 bytes (2 for the length, 1 and 13 for the label, 1 and 32 for the context). The wrong version runs and returns 32 plausible bytes with no error, so only a test against RFC 8448's values catches it.
From the lesson TLS 1.3 key schedule and handshake secrets
-
Why does the transcript hash go into every TLS 1.3 traffic secret?
So that a message changed on the way gives the two sides different keys. With one bit of the ServerHello flipped, TLS 1.3 derived b67b7d69… and ad0201ec…, no shared key, while a schedule that left the hash out derived identical keys and said nothing about the change. The hash covers the handshake messages in order, each with its 4-byte header and none of the 5-byte record headers.
From the lesson TLS 1.3 key schedule and handshake secrets
-
How does TLS 1.3 make a record's key and nonce?
Each direction takes a key and an IV from its traffic secret with the labels key and iv and an empty context (16-byte key and 12-byte IV for TLS_AES_128_GCM_SHA256). The nonce of each record is the IV XORed with the record's 64-bit sequence number, left-padded with zeros, so the first record uses the IV itself. A counter nonce cannot repeat under one key: when a sequence number would wrap, the connection rekeys or ends.
From the lesson TLS 1.3 key schedule and handshake secrets
-
What do the record's AEAD tag, CertificateVerify and Finished each show?
The AEAD tag shows that the sender holds the handshake key. CertificateVerify, a signature over 64 spaces, the context string TLS 1.3, server CertificateVerify, a zero byte and the transcript hash up to the Certificate, shows that the sender controls the private key of the certificate it sent. Finished, an HMAC under a finished key over the transcript up to CertificateVerify, shows that the sender holds the traffic secret and saw the same handshake. None says whether the certificate belongs to the host you meant.
From the lesson TLS 1.3 key schedule and handshake secrets
-
What are the risks of TLS 1.3 early data (0-RTT)?
It is keyed from the pre-shared key and the ClientHello alone, so assume no forward secrecy, and nothing ties it to one connection, so a recorded flight can be replayed: it ran three times against a server that checked only the tag and once against one that recorded ClientHellos. RFC 9846 says each server instance must accept a given 0-RTT handshake only once, so 12 servers with no shared record may run a request up to 12 times. Send only requests safe to repeat; a server may answer 425 Too Early (RFC 8470).
From the lesson TLS 1.3 key schedule and handshake secrets
-
Which RFCs now define TLS 1.3 and the status of TLS 1.2?
RFC 9846 replaces RFC 8446 as the specification of TLS 1.3. It renames the last secret of the ladder the main secret but keeps RFC 8446's wire labels, so no derived value changes. RFC 9852 says new protocols using TLS must require TLS 1.3, and RFC 9851 puts TLS 1.2 in feature freeze.
From the lesson TLS 1.3 key schedule and handshake secrets
-
Which five facts does certificate validation check?
That the signatures lead to a trust anchor the client already holds; that every certificate is valid now; that the leaf covers the name asked for; that the leaf and its issuers are fit for their roles; and that nothing has been revoked, a status that comes from outside the certificate.
From the lesson Certificate validation and lifecycle in code
-
Why is checking that a leaf's issuer name matches not enough?
In the lesson's chain the forged leaf's names pointed at the intermediate, so checkIssued said yes, but the intermediate's key had not signed it, so verify said no. A name that points at an issuer proves nothing until the issuer's key verifies the signature.
From the lesson Certificate validation and lifecycle in code
-
Which names does a client match under RFC 9525?
Only the subject alternative name entries; the common name must not be used to identify a server. Names compare without regard to letter case. A wildcard is valid only as the complete left-most label, as in *.example.test, and stands for exactly one label: it covers a.example.test, not example.test or a.b.example.test. An IP address matches only an entry of the IP type.
From the lesson Certificate validation and lifecycle in code
-
Where do Node.js defaults differ from RFC 9525, and how do you fix it?
By default Node.js reads the common name of a certificate that has no DNS names, and lets f*.example.test cover foo.example.test; RFC 9525 allows neither. Pass subject: 'never' and turn partial wildcards off. checkHost does not read address entries, so ask checkIP for an IP address.
From the lesson Certificate validation and lifecycle in code
-
How are public certificate lifetimes shrinking, and what does it mean for renewal?
The CA/Browser Forum Baseline Requirements cap the validity of a new TLS certificate in steps: 398 days, then 200, 100 and 47, with domain-validation reuse falling to 10 days. Renewing at about two thirds of the lifetime means about 12 issuances a year for each name at the last step, which nobody does by hand.
From the lesson Certificate validation and lifecycle in code
-
How do the Requirements count a certificate's days?
A certificate's validity runs from notBefore through notAfter, both days included, and any part of a day counts as a whole day. A certificate that lasts exactly 200 days is therefore counted as 201 and is too long for a 200-day cap. Renew after a fraction of the lifetime read from the certificate, never after a fixed number of days.
From the lesson Certificate validation and lifecycle in code
-
What do the TLS defaults of Node.js and Python verify?
Node.js leaves rejectUnauthorized true, so tls.connect checks the server's chain against the CAs it was given and the name against servername, which is also sent as Server Name Indication. Python's ssl.create_default_context() requires a certificate, checks the host name and sets a TLS 1.2 minimum; since Python 3.13 its defaults also apply strict X.509 checks.
From the lesson Using TLS safely in Node.js and Python
-
What happens when a client with verification off meets an impostor?
The impostor holds a certificate for the right name from a CA the client has not been told to trust. The defaults refuse it with SELF_SIGNED_CERT_IN_CHAIN; with verification off the connection goes on, and the impostor receives whatever the client sends.
From the lesson Using TLS safely in Node.js and Python
-
Which settings switch off TLS checks in Node.js and Python?
Chain and time checks: Node.js rejectUnauthorized: false or NODE_TLS_REJECT_UNAUTHORIZED=0; Python verify_mode = ssl.CERT_NONE, ssl._create_unverified_context() or verify=False in requests. Name check: a checkServerIdentity that returns nothing, or check_hostname = False. Protocol floor: minVersion: 'TLSv1', or minimum_version = ssl.TLSVersion.TLSv1.
From the lesson Using TLS safely in Node.js and Python
-
Why are the chain, name and version switches three separate decisions?
Without chain checks a client is open to an impostor. Without the name check it is open to anyone who holds a certificate from a CA it trusts, issued for another name. A low protocol floor lets a connection fall to versions that RFC 8996 deprecated. A test that needs a private CA should trust that CA explicitly and leave verification on.
From the lesson Using TLS safely in Node.js and Python
-
What would a large quantum computer break, and what would it leave standing?
Shor's algorithm solves factoring and discrete logarithms, so it would break RSA, Diffie-Hellman, ECDH, ECDSA and EdDSA at every key size; longer keys cannot save them. Grover's algorithm cuts a 2^128 key search to about 2^64 quantum steps, but it parallelises poorly (1,024 quantum computers cut the time by a factor of 32), so AES-128 remains secure in practice (RFC 9958). Key establishment and signatures are what must be replaced.
From the lesson Post-quantum crypto: ML-KEM and ML-DSA
-
Why does key establishment move to post-quantum algorithms before signatures?
A recording cannot be taken back. An eavesdropper copies traffic and waits (harvest now, decrypt later); the future machine only has to recover the private value behind one public key share. A session protected by ML-KEM leaves an ML-KEM ciphertext in the recording, and no known quantum algorithm recovers its secret. A forged signature harms only once the machine exists, so a signature checked once in a handshake can wait, but a key devices trust for years cannot.
From the lesson Post-quantum crypto: ML-KEM and ML-DSA
-
What is the Mosca model, and what did it show for medical images?
Let x be the years the data must stay secret, y the years the migration to post-quantum algorithms will take, and z the years until a cryptographically relevant quantum computer exists. Recorded data is exposed for x + y − z years whenever that is positive. Medical images (x = 30, y = 5) are exposed for 25 years if z = 10 and for 5 years if z = 30. The values of z are assumptions, because nobody knows it.
From the lesson Post-quantum crypto: ML-KEM and ML-DSA
-
What are the three operations of a KEM, and how does a KEM differ from encrypting a key?
KeyGen makes a key pair. Encaps takes the public encapsulation key and returns a ciphertext and a shared secret. Decaps takes the private key and the ciphertext and returns the same secret. The sender does not choose the secret: it falls out of Encaps. ML-KEM (FIPS 203, once called Kyber) has ML-KEM-512, 768 and 1024, always gives a 32-byte secret, and NIST recommends 768 as the default.
From the lesson Post-quantum crypto: ML-KEM and ML-DSA
-
What does ML-KEM decapsulation do with a damaged ciphertext?
Implicit rejection: a ciphertext with a flipped bit does not make Decaps throw; it returns 32 bytes that are not the sender's secret, the same bytes each time, built from a hash of the ciphertext and a secret in the private key. A ciphertext of the wrong length is no ciphertext and throws. So derive keys with HKDF, and let the first authenticated message show whether both sides agree.
From the lesson Post-quantum crypto: ML-KEM and ML-DSA
-
How large are ML-KEM-768 and ML-DSA-65 next to X25519 and Ed25519?
ML-KEM-768 sends a 1,184-byte key and gets a 1,088-byte ciphertext: 37.0 and 34.0 times X25519's 32 bytes. ML-DSA-65 has a 1,952-byte public key and a 3,309-byte signature: 61.0 and 51.7 times Ed25519's 32 and 64. ML-DSA-44 signs in 2,420 bytes; SLH-DSA-SHA2-128s keeps a 32-byte public key but has the largest signature of the table, 7,856 bytes.
From the lesson Post-quantum crypto: ML-KEM and ML-DSA
-
What are hedged signing and the context string in ML-DSA?
FIPS 204 signs by default with fresh randomness mixed with a random value stored in the private key, so signing twice gives two different signatures that both verify and a weak random generator does not by itself break the scheme; a deterministic variant exists for devices with no randomness. A context string of up to 255 bytes added to what is signed (such as msc/release/v1) stops a signature made for one purpose from verifying for another.
From the lesson Post-quantum crypto: ML-KEM and ML-DSA
-
Which checks must run on a peer's ML-KEM encapsulation key before Encaps?
FIPS 203 section 7.2: a type check, exactly 384k + 32 bytes (1,184 for ML-KEM-768), and a modulus check, that every 12-bit number packed into the first 384k bytes is below q = 3,329. The key one byte short and a key whose first number was 3,329 were refused; a first number of 3,328, the largest valid one, was accepted. RFC 10024 makes the checks mandatory for a TLS server receiving a hybrid key share.
From the lesson Post-quantum crypto: ML-KEM and ML-DSA
-
What is a hybrid key exchange, and why use one?
RFC 9954: two or more algorithms with different assumptions joined so that the session key stays secure while at least one of them remains unbroken. ML-KEM is young, so a flaw is possible; X25519 is well studied but falls to a large quantum computer. The hybrid loses only if both halves fail, and what it costs is bytes.
From the lesson Hybrid post-quantum and crypto agility
-
Which hybrid groups does RFC 10024 name for TLS 1.3, and how do the halves meet?
X25519MLKEM768 (widely deployed), SecP256r1MLKEM768 (P-256 with ML-KEM-768, for policies that allow only NIST curves) and SecP384r1MLKEM1024 (P-384 with ML-KEM-1024, for high security). Each key share is the two values written one after the other, and the two shared secrets are concatenated and used where the key schedule expects the Diffie-Hellman secret.
From the lesson Hybrid post-quantum and crypto agility
-
What does a hybrid TLS handshake cost?
Bytes, not a round trip. Node.js offered X25519MLKEM768 (a 1,216-byte share) and plain X25519 (32 bytes) together: the ClientHello record was 1,596 bytes against 362, 1,234 more. A server that knew the group answered with 1,120 bytes (1,088 + 32); one that did not answered with 32, with no extra round trip.
From the lesson Hybrid post-quantum and crypto agility
-
How do TLS, SSH and age combine the two halves of a hybrid?
TLS 1.3 concatenates the two secrets inside its key schedule. SSH hashes them: sntrup761x25519-sha512 (RFC 9941) and mlkem768x25519-sha256 (RFC 10042). age wraps the file key using HPKE with a hybrid KEM built from ML-KEM-768 and X25519. RFC 10024 warns that the TLS analysis relies on the TLS transcript, so a similar hybridization in another protocol is not automatically secure.
From the lesson Hybrid post-quantum and crypto agility
-
What does crypto agility need, and what goes wrong without each part?
An algorithm identifier in every format (else the reader must guess). Negotiation with downgrade protection (else an attacker edits the offer toward a weaker choice). Key identifiers (else keys and algorithms cannot coexist). A re-encryption job (else old data stays under the retired algorithm). ASVS 5.0 asks for agility in 11.2.2, an inventory in 11.1.2 and a migration roadmap in 11.1.4.
From the lesson Hybrid post-quantum and crypto agility
-
What did Chrome 131 show about crypto agility?
It changed the hybrid group from the pre-standard Kyber code point 0x6399 to 0x11EC, because the final ML-KEM is not compatible with Kyber, and it could do so because TLS names its groups in the handshake.
From the lesson Hybrid post-quantum and crypto agility
-
What does a known-answer test prove that a round trip does not?
A known-answer test runs your code on an input that someone else published and compares the output with their answer, so a pass means the code computes the standard function. A round trip shows only that opening undoes sealing: an encrypt that XORs every byte with one constant opens its own output perfectly and agrees with no published answer.
From the lesson Testing crypto code with official test vectors
-
Where do official test vectors come from, and in what formats?
RFC appendices, as text (RFC 5869 appendix A, RFC 4231). NIST CAVP response files: .rsp text with groups headed by [Keylen = 256] and records of Count, Key, IV, PT, AAD, CT and Tag, where a decrypt record that must fail ends in FAIL. NIST ACVP vector sets: JSON, prompt.json and expectedResults.json matched by tcId, for HMAC, AES-GCM, HKDF, the TLS 1.3 key derivation, ML-KEM and ML-DSA.
From the lesson Testing crypto code with official test vectors
-
Why keep a control that is wrong on purpose in a vector suite?
A suite that cannot fail proves nothing. In the lesson, every real suite passed and the control, the same five ACVP cases checked against HMAC-SHA-1, failed as it should. A FAIL record in a CAVP file tests a refusal, which matters as much as a plaintext.
From the lesson Testing crypto code with official test vectors
-
How does Project Wycheproof label its test vectors?
Each test has a result and flags. Valid: the code must return the plaintext. Invalid: it must refuse, and an exception counts. Acceptable: either is fine because the parameters are weak. Flags name the targeted bug, such as ModifiedTag for a check that does not read the whole tag, or ZeroLengthIv. It is a community-managed JSON repository, now maintained by C2SP.
From the lesson Testing crypto code with official test vectors
-
Which wrapper bugs did the Wycheproof AES-GCM vectors find?
A wrapper that never calls final() returned plaintext before the tag was checked and accepted all five modified tags. One that checked only 4 bytes of the tag refused the flips at bit 0 and bit 31 but failed exactly the tests that change bit 32 and bit 127, which is why the file flips bits along the whole tag.
From the lesson Testing crypto code with official test vectors
-
A wrapper passes every Wycheproof AES-GCM vector. Is it safe?
Not necessarily. One wrapper passed all 12 vectors yet accepted tags cut to 12 and 4 bytes, since the file holds only 16-byte tags. Vectors test the primitive as the standard defines it; rules your wrapper adds, such as one tag length and one IV size, need policy tests of your own. A tag of 32 bits is guessed with a probability of 1 in 2^32 for each try, which is not what 128 bits promise.
From the lesson Testing crypto code with official test vectors
-
Which five properties cover a sealed-box wrapper, and what do random tests miss?
It opens what it sealed; sealing one message twice gives two different boxes; a single changed bit makes opening fail; a changed AAD makes it fail; a box with a byte missing fails. A thousand random cases find a bug that 1 input in 1,000 triggers with a probability of 63.2 %, but a 1-in-2^32 bug with next to none: rare triggers are what vectors are for.
From the lesson Testing crypto code with official test vectors
-
How should an interoperability test compare results, and what is the golden-file trap?
Give every implementation the same inputs and compare the bytes and the class of outcome, accepted or refused, never the wording of an error message. A golden file made by running the new function pins today's behaviour, bugs included: take the expected value from a standard, another implementation or a hand calculation, and keep its source next to it.
From the lesson Testing crypto code with official test vectors
-
What is a side channel, and which four channels cause most real leaks?
Information a program gives away through its behaviour rather than its output. Timing (how long it took), errors (which status or message came back), length (how many bytes were sent) and logs and memory (what is stored beside the answer). Each needs its own rule.
From the lesson Side channels and failing safely
-
What habit closes each of the four side channels?
Timing: call platform primitives and do the same work on every path. Errors: answer every failure alike. Length: pad to a bucket when the length matters. Logs and memory: scrub at the source and wrap values in a type that will not print.
From the lesson Side channels and failing safely
-
What does failing safely mean, and what does ASVS 5.0 require?
Every refusal looks the same from outside, whatever went wrong inside, so a failure teaches the observer nothing. ASVS 5.0 requirement 11.2.5: cryptographic modules fail securely, and errors do not enable vulnerabilities such as padding-oracle attacks. The status, the body and the amount of work are identical, and the real cause goes to a private log beside a request id.
From the lesson Side channels and failing safely
-
What is an oracle in cryptographic code?
A service that keeps answering a yes-or-no question about data it holds, to anyone who asks and as often as they ask. A decrypt endpoint that says bad padding for one failure and bad MAC for another is one: every answer tells the asker which check a guess got past.
From the lesson Side channels and failing safely
-
How did the weak and the fixed decrypt services differ in the lesson's run?
The weak service gave three statuses and three texts, and its work differed too: 0 AEAD opens for two failures and 1 for the third, so a stopwatch separates them. The fixed service answered all three with one status, 400, and one body, an error saying only that it cannot open, and it opened exactly once per request, an unknown key id included, using a key that cannot match. The test that failures are indistinguishable found 3 distinct answers against 1.
From the lesson Side channels and failing safely
-
Why is cryptographic code hard to review?
Because it keeps working when it is unsound. A fixed IV, a guessable token or an early-exit comparison still returns the right answer in every test that checks only the answer. Read the diff once for what it does, and again for what each key, nonce and check does.
From the lesson Reviewing crypto code: a practical checklist
-
What are the twelve questions of a crypto code review?
Which algorithms and modes? Where does randomness come from? Where does each key live? How many jobs does a key do? Can a key be replaced? Is each nonce new? What does a message belong to? Is it verified before use? How are secrets compared? Who chooses how a token is checked? Is TLS verification on? What does a failure look like? They follow the life of a key.
From the lesson Reviewing crypto code: a practical checklist
-
What does a passing answer look like for questions 1 to 6?
1: algorithms suited to the job, from a maintained library. 2: the system generator for every key, salt, token and nonce. 3: a key store, never source or a log. 4: one job per key. 5: a version in the format, so two keys can coexist. 6: a nonce unique for its key, by random draw or a counter that cannot repeat.
From the lesson Reviewing crypto code: a practical checklist
-
What does a passing answer look like for questions 7 to 12?
7: the message's id, owner and purpose as associated data. 8: tag, signature or MAC checked before any data is used. 9: constant-time comparison, after format and length checks. 10: the code, not the token, chooses how a token is checked. 11: certificate and host name verified in every client. 12: one answer for every cause, with no secret in message, log or timing.
From the lesson Reviewing crypto code: a practical checklist
-
In a crypto code review, what is a question the diff cannot answer?
A finding in itself: whoever wrote the code has to be able to tell you where each key is kept and who is able to replace it. A checklist does not make anyone an expert in a primitive, so anything new, such as a protocol or an algorithm built by hand, should be handed to a specialist.
From the lesson Reviewing crypto code: a practical checklist
-
What do forward secrecy and post-compromise security promise after a device is copied?
Forward secrecy: a thief who copies the device cannot read what was said before the copy. Post-compromise security, called break-in recovery in the Double Ratchet specification: once the thief is out again, messages sent after a fresh key exchange are closed to a thief who only listens. One key for the whole chat gives neither: a copy opens every message.
From the lesson End-to-end encryption: Signal protocols and MLS
-
How does the symmetric-key ratchet give forward secrecy?
Each chain key makes the next chain key and one message key with HMAC-SHA-256: the message key is HMAC(CK, 0x01) and the next chain key HMAC(CK, 0x02) (Double Ratchet specification 7.2). The message key encrypts one message; then the sender overwrites the chain key and discards the message key. A copy after message 5 opened 0 of 5 earlier messages but still all later ones.
From the lesson End-to-end encryption: Signal protocols and MLS
-
Why is keeping used message keys "for a retry" a mistake?
The chain was right and the key store ruined it: a copy then opened 5 of 5 earlier messages, as with one key for everything. Keep the ciphertext or the plaintext for a retry, and delete the key as soon as the message is sealed.
From the lesson End-to-end encryption: Signal protocols and MLS
-
How does a ratchet receiver handle late, repeated and far-ahead messages?
Behind the chain with no stored key: refuse. Behind with a stored key: open and delete the key. The next number: open and step on. Ahead by at most MAX_SKIP: step ahead, store the skipped keys, then open. Ahead by more: refuse. A message that fails its tag check must change nothing, or one forged packet would move the chain. A claim of message 1,000,000 would cost about 32 MB of stored keys before any tag check.
From the lesson End-to-end encryption: Signal protocols and MLS
-
How does the Diffie-Hellman ratchet heal a copied phone?
Every header carries the sender's current ratchet public key. When the direction changes, the receiver runs X25519 between it and her own private ratchet key, feeds the result into HKDF with the root key as salt to get a new root and chain key, then makes a new ratchet key pair and repeats. The old private key is overwritten. A thief reads nothing after the owner's next reply. Recovery targets a thief who only listens (specification 8.2).
From the lesson End-to-end encryption: Signal protocols and MLS
-
How do X3DH and PQXDH start a session with someone who is offline?
Bob leaves a prekey bundle on a server: his identity key IK, a signed prekey SPK (signed with IK) and one-time prekeys OPK, each handed out once. Alice adds her identity key and a fresh ephemeral key and computes four DH values; the first two authenticate, the last two give forward secrecy. PQXDH adds a KEM secret (ML-KEM-1024 keys and ciphertexts are 1,568 bytes). The client must verify the signature on every prekey.
From the lesson End-to-end encryption: Signal protocols and MLS
-
How does MLS make a group update cheap?
Members are the leaves of a ratchet tree. An update picks new secrets for the member's path and encrypts each to the subtree that hangs off the path at that level: about log N ciphertexts, 10 for 1,000 members against 999 for pairwise sessions (3 against 7 for eight members). A Commit applies proposals and starts a new epoch, and a Welcome brings in a new member. The first update in a never-committed group costs as much as pairwise.
From the lesson End-to-end encryption: Signal protocols and MLS
-
What does end-to-end encryption still leave visible?
Metadata: who talks to whom, when and how often (MLS headers carry the group ID, epoch and message type in the clear). Message length, since padding is optional. Whose key it is, unless keys are verified by a code or QR code or logged by key transparency. What a device holds now: a ratchet limits what one copy reveals, not what the phone stores. And PQXDH authentication, which is still classical.
From the lesson End-to-end encryption: Signal protocols and MLS
-
What is an oblivious PRF, and how does blinding make it work?
A pseudorandom function split between two parties (RFC 9497): the server holds the key and the client the input, and at the end the client has the output while the server has learned neither. The client hides its input with a secret random number, the server applies its key to what it receives, and the client removes the hiding and hashes the result with the input.
From the lesson OPAQUE, Privacy Pass and threshold signatures
-
What did the server learn in the toy OPRF run?
Two logins with the same password sent the server different values, yet the client got the same output both times. The server tried 1,000 candidate passwords against what it had received: with no blind it found the password, and with the blind it found nothing. RFC 9497 calls this unconditional input secrecy, since it holds even against unlimited computing power.
From the lesson OPAQUE, Privacy Pass and threshold signatures
-
What are the three modes of RFC 9497, and what is its status?
The plain mode; a verifiable mode, where the server also proves it used the key whose public half the client knows; and a partially oblivious mode that adds public input. The RFC is Informational, a consensus of the IRTF's Crypto Forum Research Group and not an Internet standard, so real code takes an established library.
From the lesson OPAQUE, Privacy Pass and threshold signatures
-
What do OPAQUE, Privacy Pass, threshold signatures and Oblivious HTTP each do?
OPAQUE (RFC 9807): a password login in which the server never receives the password, even at account creation, so a stolen table alone cannot start a dictionary attack. Privacy Pass: tokens blinded when issued, so the issuer cannot match one to its request, each accepted once. Threshold signatures such as FROST (RFC 9591): t of n holders sign under one public key in two rounds. Oblivious HTTP (RFC 9458): a relay sees the address but not the request, a gateway the request but not the address.
From the lesson OPAQUE, Privacy Pass and threshold signatures
-
How does Shamir sharing hide a key and rebuild it?
The key is the constant term of a random polynomial of degree k − 1 over a prime field, and holder i gets the polynomial's value at i. Any k values fix the polynomial, so k holders interpolate back to the key; with k − 1 values every possible key still fits exactly one polynomial, so those holders learn nothing. All 10 triples of 5 shares rebuilt the key and none of the 10 pairs did.
From the lesson OPAQUE, Privacy Pass and threshold signatures
-
Why is Shamir sharing better than cutting a key into pieces, and what does it still cost?
Four holders of a key cut into five pieces of six or seven bytes miss one piece of at most 7 bytes, 2^56 keys, while two holders of a Shamir split still face all 2^256. But to sign, one machine must collect k shares and rebuild the key, holding the whole key for that moment. A threshold signature avoids it: every holder works out a signature share using its own key share, and only the shares are combined.
From the lesson OPAQUE, Privacy Pass and threshold signatures
-
Why does Kerberos use a key distribution centre instead of pairwise keys?
If every pair among n parties needs its own key, the system holds n(n − 1)/2 keys: 45 for 10 parties, 4,950 for 100 and 499,500 for 1,000. With a KDC every party shares one long-term key with it, so the system holds n keys, and the KDC hands out a fresh session key whenever two parties want to talk.
From the lesson Kerberos tickets, authenticators and replay checks
-
What does a key distribution centre cost?
An online server that must be trusted, an attractive target, a bottleneck and a single point of failure, as the Handbook names them.
From the lesson Kerberos tickets, authenticators and replay checks
-
What is the weakness of Needham-Schroeder with shared keys, and how does Kerberos limit it?
The server returns a session key sealed for the first party, with a copy inside sealed for the second. The second party cannot tell whether the key is fresh, so if a session key is ever stolen an attacker can resend the old copy and pose as the first party. Kerberos limits this with a lifetime in the ticket, and uses timestamps where Needham-Schroeder uses nonces.
From the lesson Kerberos tickets, authenticators and replay checks
-
What do a Kerberos ticket and an authenticator each prove?
A ticket is encrypted under the key of the service it is meant for, so a client carries it without being able to read or change it; it records whom the KDC introduced. An authenticator is a name and a timestamp sealed under the session key, and a fresh one goes with every use of a ticket; it shows that the sender has the session key at this moment.
From the lesson Kerberos tickets, authenticators and replay checks
-
Which replay checks make a Kerberos authenticator trustworthy?
Three checks together: a cache of recent authenticators, a window around the clock, and an end time on every ticket. Without them a recorded request can simply be sent again, and the service cannot tell a replay from the real thing.
From the lesson Kerberos tickets, authenticators and replay checks
-
How does a syllabus table of hours and weights show where self-study pays?
GTU 3161606's content table has eleven rows totalling 48 teaching hours and 100 % of the theory weight. Public-key systems (7 hours, 15 %) and the opening unit (5 hours, 15 %) weigh the same, but the shorter unit earns 3.0 per cent of weight per hour against 2.1. Message authentication earns the most, 3.33; modes of operation and Kerberos the least, 1.25.
From the lesson University cryptography syllabi: a topic map
-
How do you answer an exam question about a retired algorithm?
In two parts: the algorithm as the question asks for it, then one sentence on what is current. For DES: a 64-bit block, 56 key bits inside a 64-bit key with parity bits, the initial and final permutations, 16 Feistel rounds with a 48-bit round key, the round function, decryption with reversed keys; then DES is retired because 2^56 keys can be searched, NIST withdrew it in 2005, and AES is the standard. Never let the last sentence replace the answer asked for.
From the lesson University cryptography syllabi: a topic map
-
What is current for DES, Triple DES, the classic modes, and RSA with Diffie-Hellman?
DES: NIST withdrew the standard in 2005; AES is the block cipher to use. Triple DES: three-key encryption is disallowed after 2023 and two-key encryption is disallowed (SP 800-131A Rev. 2). ECB, CBC, CFB, OFB and CTR are still permitted, but a new design uses an AEAD such as AES-GCM. RSA and Diffie-Hellman: choose 128-bit strength, which RSA-2048 does not reach, and plan for post-quantum algorithms.
From the lesson University cryptography syllabi: a topic map
-
What is current for MD5 and SHA-1, DSA and SSL?
MD5 must not be used for any cryptographic purpose. SHA-1 may not generate signatures except where NIST guidance allows, and NIST plans to retire it by 2030. FIPS 186-5 no longer allows DSA for signing, only for verifying old signatures. SSL 3.0 is prohibited by RFC 7568, TLS 1.0 and 1.1 are deprecated by RFC 8996, and TLS 1.3 is RFC 9846.
From the lesson University cryptography syllabi: a topic map
-
Which printed answers let you check the syllabus practicals with test cases?
RSA with p = 17 and q = 11: d = 23, and 88 gives 11. Playfair with MONARCHY: ar mu hs ea gives RM CM BP IM. Caesar with key 3: ABC gives DEF and Hello, Welcome gives Khoor, Zhofrph. Hill: pay gives RRL. Euclid: gcd(16, 12) = 4. Rail fence: Meetme gives MEMETE. Columnar with key 4312567: TTNAAPTMTSUOAODWCOIXKNLYPETZ.
From the lesson University cryptography syllabi: a topic map
-
Why does the Hill practical give RRL in one course and LNS in another?
RRL comes from writing each block of three letters as a row vector and multiplying it by the key. A course that writes blocks as columns gets LNS from the same matrix. Neither is wrong, so say which convention you use. The columnar answer has 28 letters for a 25-letter plaintext because it was made with the padding xyz.
From the lesson University cryptography syllabi: a topic map
-
What useful program replaces the practicals that ask for a virus program?
A defender's integrity monitor in a scratch folder. It records the size and SHA-256 of each file and the target of each symbolic link, and never follows a link. It reported the new link with the name it points to and a file growing from 13 to 23 bytes. A size-only monitor missed the link and an in-place one-byte edit that kept the size; only the digest noticed. Run lab programs on files and traffic that are your own.
From the lesson University cryptography syllabi: a topic map
-
What are the five steps of mapping any syllabus, and what did the AKTU example leave out?
Copy the units, note the versions, find the lessons, map the practicals with checks, and turn the weights into hours. The AKTU BCY401 map leaves out steganography, Fermat, Euler, Miller-Rabin and CRT (discrete mathematics), Blowfish and RC4 internals, MD5 internals, and email architecture, S/MIME and PGP key rings.
From the lesson University cryptography syllabi: a topic map