Chapter 10 — Cryptography and trust services: quality and troubleshooting
Lesson map
Lesson 10 published. Map, example, EX046.
flowchart TD
N0["Learning outcomes"]
N1["10.1 A staff portal finding"]
N2["10.2 Verifying the fix"]
N3["Lab — Salted PBKDF2 versus fast hash"]
N4["10.3 Quality through review"]
N5["Synthesis"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5
N5 --> EX["Worked example"]
EX --> Q["Exercise EX046"]
Logical drawing
flowchart LR
N0["Learning outcomes"]
N1["10.1 A staff portal finding"]
N2["10.2 Verifying the fix"]
N3["Lab — Salted PBKDF2 versus fast hash"]
N4["10.3 Quality through review"]
N5["Synthesis"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> Q["EX046"]
[Learning outcomes]
|
v
[10.1 A staff portal finding]
|
v
[10.2 Verifying the fix]
|
v
[Lab — Salted PBKDF2 versus fast hash]
|
v
[10.3 Quality through review]
|
v
[Synthesis]
|
v
[Worked example] --> [Exercise EX046]
Learning outcomes
You will (1) troubleshoot a password storage weakness in a staff portal; (2) verify a fix using a key-derivation function; (3) improve workflow quality with review and retrospectives.
10.1 A staff portal finding
Bayside's small staff rota portal, built by the agency, stores staff passwords. During a review Dana sees in the configuration export that passwords are stored as unsalted SHA-256 hashes. Fast hashes let an attacker who steals the database test enormous numbers of guesses quickly, and without salt, identical passwords produce identical hashes. Password storage needs a slow, salted function. Python's hashlib.pbkdf2_hmac implements PBKDF2, and stronger memory-hard choices include scrypt from RFC 7914 and Argon2id from RFC 9106. Dana's recommendation is to use a maintained library implementing one of these, not to design a custom scheme.
10.2 Verifying the fix
The agency proposes PBKDF2-HMAC-SHA-256 with a random 16-byte salt per user and a high iteration count set by policy, migrating each user at next login. Dana verifies the approach in a lab with synthetic users: two staff with the same password get different stored values; the correct password verifies and a wrong one fails; and the time per guess is far higher than for a single SHA-256. The lab below shows these results. She records that the lab confirms behaviour of the method, while the agency's production code still needs its own review.
Lab — Salted PBKDF2 versus fast hash
# Salted PBKDF2-HMAC-SHA-256 vs one SHA-256, synthetic staff. Teaching only; use a maintained library in production.
import hashlib, hmac, secrets, time
ITER = 600_000 # lab value; production iteration count comes from policy
def store(pw):
s = secrets.token_bytes(16); return s, hashlib.pbkdf2_hmac("sha256", pw, s, ITER)
def check(pw, rec): return hmac.compare_digest(hashlib.pbkdf2_hmac("sha256", pw, rec[0], ITER), rec[1])
a, b = store(b"Rota-Clinic-3"), store(b"Rota-Clinic-3")
print("same password, different stored values:", a[1] != b[1])
print("correct password:", check(b"Rota-Clinic-3", a), "| wrong password:", check(b"Rota-Clinic-4", a))
t0 = time.perf_counter(); [hashlib.sha256(b"Rota-Clinic-3").digest() for _ in range(10000)]; fast = (time.perf_counter() - t0) / 10000
t0 = time.perf_counter(); check(b"x", a); slow = time.perf_counter() - t0
print(f"per-guess cost ratio PBKDF2/SHA-256: {'over 10,000x' if slow / fast > 10000 else 'under 10,000x'}")
Run with python3 lab_pbkdf2.py. Verified output:
same password, different stored values: True
correct password: True | wrong password: False
per-guess cost ratio PBKDF2/SHA-256: over 10,000x
10.3 Quality through review
Mistakes slip into every workflow, so Copperleaf builds quality checks in. Every report is reviewed by a second analyst before it goes to the client. After each monthly cycle, the team spends fifteen minutes on a retrospective: what went well, what went wrong and one change for next month. When Dana's retest of the chain fix nearly missed the second server, the retrospective led to a rule that load-balanced endpoints are tested once per backend. Small, steady improvements like this raise the quality of the whole service more than occasional heroic efforts.
Worked example
Dana documents the unsalted SHA-256 finding, runs the PBKDF2 lab to confirm the agency's approach and adds a per-backend testing rule after a retrospective.
Synthetic case. The rota portal, users and iteration count are synthetic; RFC 7914 and RFC 9106 are real.
Errors and limits
Lab timing varies by machine; it shows relative cost, not attacker speed. Upgrade at login leaves inactive accounts on old hashes.
Exercises
- EX046 — Unsalted weakness. Name two problems with unsalted SHA-256 password storage. Rubric: 3 = fast to guess and identical passwords share hashes;; 2 = one;; 1 = vague;; 0 = none.
- EX047 — Lab equal passwords. What did the PBKDF2 lab show for two staff with the same password? Rubric: 3 = stored values differed because salts differed;; 2 = differed;; 1 = same;; 0 = none.
- EX048 — Lab cost ratio. According to the lab, how did PBKDF2 cost compare with one SHA-256? Rubric: 3 = over 10,000 times slower per guess, as printed;; 2 = slower;; 1 = faster;; 0 = none.
- EX049 — Production caveat. What does the lab not prove about the agency's fix? Rubric: 3 = that production code implements it correctly; needs review;; 2 = code review;; 1 = proves all;; 0 = none.
- EX050 — Retrospective rule. Which rule came from the retrospective? Rubric: 3 = test load-balanced endpoints once per backend;; 2 = rule;; 1 = vague;; 0 = none.
Synthesis
Quality comes from verifying fixes with sound methods and from steady review and retrospectives.
Continue studying — chapter 10 of 12
← Chapter 09 (draft) · Course chapter index · Chapter 11 (draft) →