Chapter 16 — Cryptography and trust services: methods II
Lesson map
Lesson 16 published. Map, example, EX046.
flowchart TD
N0["Learning outcomes"]
N1["16.1 Memory-hard hashing"]
N2["Lab — scrypt with a test vector"]
N3["16.2 Reading the scrypt run"]
N4["16.3 Planning migration"]
N5["Synthesis"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5
N5 --> EX["Worked example"]
EX --> Q["Exercise EX046"]
Logical drawing
flowchart LR
N0["Learning outcomes"]
N1["16.1 Memory-hard hashing"]
N2["Lab — scrypt with a test vector"]
N3["16.2 Reading the scrypt run"]
N4["16.3 Planning migration"]
N5["Synthesis"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> Q["EX046"]
[Learning outcomes]
|
v
[16.1 Memory-hard hashing]
|
v
[Lab — scrypt with a test vector]
|
v
[16.2 Reading the scrypt run]
|
v
[16.3 Planning migration]
|
v
[Synthesis]
|
v
[Worked example] --> [Exercise EX046]
Learning outcomes
You will (1) store passwords with memory-hard hashing; (2) verify an implementation call against a published test vector; (3) plan migration from weak password storage.
16.1 Memory-hard hashing
The permit portal's citizen accounts need safe password storage. Rosa learns that fast hashes let attackers test billions of guesses per second after stealing a database, while memory-hard functions make each guess costly in memory as well as time, slowing specialised hardware. Argon2id from RFC 9106 is the preferred choice; scrypt from RFC 7914 is an established alternative available in Python's hashlib. Production code uses a vetted password-hashing library with tuned parameters; the lab uses hashlib.scrypt to show the idea.
Lab — scrypt with a test vector
"""Check hashlib.scrypt against an RFC 7914 test vector, then store a synthetic password."""
import hashlib, hmac
WANT = ("fdbabe1c9d3472007856e7190d01e9fe7c6ad7cbc8237830e77376634b3731622eaf30d92e22a3886ff109279d9830dac727afb94a83ee6d8360cbdfa2cc0640")
def main():
got = hashlib.scrypt(b"password", salt=b"NaCl", n=1024, r=8, p=16, dklen=64).hex()
print("RFC 7914 vector matches:", got == WANT)
salt = bytes.fromhex("5e" * 16) # fixed demo salt for repeatable output
stored = hashlib.scrypt(b"Permit-Desk-2026!", salt=salt, n=2**14, r=8, p=1, dklen=32)
ok = hmac.compare_digest(stored, hashlib.scrypt(b"Permit-Desk-2026!", salt=salt, n=2**14, r=8, p=1, dklen=32))
print("stored:", stored.hex()[:24], "... verify:", ok)
if __name__ == "__main__":
main()
Run with python3 lab_scrypt.py. Verified output:
RFC 7914 vector matches: True
stored: ddb1b7d5e7566125ab501de6 ... verify: True
16.2 Reading the scrypt run
The lab first checks hashlib.scrypt against a published test vector from RFC 7914 with password "password", salt "NaCl", N 1024, r 8 and p 16; the 64-byte output matches. Matching the vector confirms the function is called with the right parameter meanings. It then stores a synthetic staff password with a salt and N of 2^14, and verification with compare_digest returns True. The fixed salt only makes the output repeatable; real salts are random per user. Rosa records the parameters next to the stored hash so they can be raised later.
16.3 Planning migration
The portal currently stores passwords with salted SHA-256, which is too fast. Rosa plans a migration: when a citizen logs in successfully, the portal verifies against the old hash and immediately stores a new memory-hard hash; accounts that never log in are wrapped by hashing the old hash with the new function, so no weak hashes remain at rest. After a set period, unused accounts are asked to reset. The plan avoids forcing millions of password resets at once. She estimates server load for the new hash at peak login times before scheduling the change.
Worked example
Rosa confirms hashlib.scrypt against RFC 7914, stores a synthetic password and plans migration from salted SHA-256 by rehash-on-login plus wrapping.
Synthetic case. The portal and passwords are invented; RFC 7914 and RFC 9106 are real.
Errors and limits
Memory-hard parameters must be tuned to server capacity. Wrapping old hashes must be done carefully to avoid lockouts.
Exercises
- EX046 — Why memory-hard. Why are memory-hard functions better for passwords than fast hashes? Rubric: 3 = each guess costs memory and time, slowing specialised hardware;; 2 = slower;; 1 = same;; 0 = none.
- EX047 — Vector purpose. What does matching the RFC 7914 vector confirm? Rubric: 3 = the function is called with correct parameter meanings;; 2 = correct use;; 1 = security;; 0 = none.
- EX048 — Migration method. How are accounts that never log in protected during migration? Rubric: 3 = old hash wrapped with the new memory-hard function;; 2 = wrapping;; 1 = ignored;; 0 = none.
Synthesis
Memory-hard hashing, verified against test vectors and introduced through careful migration, protects citizen passwords.
Continue studying — chapter 16 of 30
← Chapter 15 (draft) · Course chapter index · Chapter 17 (draft) →