Chapter 19 — Identity and cryptography
Lesson map
Lesson 19 published. Map, example, EX037.
flowchart TD
N0["Learning outcomes and connection"]
N1["19.1 Identity"]
N2["19.2 Hashes, MACs and signatures"]
N3["19.3 Hash chains and anchors"]
N4["19.5 Key lifecycle"]
N5["Chapter synthesis"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5
N5 --> EX["Worked example"]
EX --> Q["Exercise EX037"]
Logical drawing
flowchart LR
N0["Learning outcomes and connection"]
N1["19.1 Identity"]
N2["19.2 Hashes, MACs and signatures"]
N3["19.3 Hash chains and anchors"]
N4["19.5 Key lifecycle"]
N5["Chapter synthesis"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> Q["EX037"]
[Learning outcomes and connection]
|
v
[19.1 Identity]
|
v
[19.2 Hashes, MACs and signatures]
|
v
[19.3 Hash chains and anchors]
|
v
[19.5 Key lifecycle]
|
v
[Chapter synthesis]
|
v
[Worked example] --> [Exercise EX037]
Learning outcomes and connection
After this chapter you can (1) distinguish authentication, authorisation and accountability in response systems; (2) explain what hashes, MACs and digital signatures do and do not prove; (3) build a tamper-evident evidence manifest with a hash chain and an independently held anchor; and (4) plan the key lifecycle and role separation that the cryptography depends on. It builds on Chapters 15 and 18 and prepares Chapters 28, 30 and 34.
19.1 Identity
Authentication establishes who is acting; authorisation decides what that identity may do; accountability links each action to an identity afterwards. Shared accounts break accountability regardless of cryptography. Service identities need the same rigour as people: one identity per function, short-lived credentials, and scopes that match the function.
Lab 19 records collector-2 as the producer of every manifest entry, which is accountability only if that identity is used by one collector and no person. The worked example ends on the same point: administrators who share one account able to read the anchor key cannot be told apart afterwards. Each of them could have rewritten and re-anchored the chain.
19.2 Hashes, MACs and signatures
A cryptographic hash (SHA-256, FIPS 180-4) gives a fixed-size fingerprint; anyone can compute it, so a hash proves only that two copies match — not who produced them. A MAC such as HMAC (FIPS 198-1, RFC 2104) requires a secret key: whoever holds the key could have produced it, so it proves integrity relative to key holders. A digital signature (Diffie and Hellman, 1976; Rivest, Shamir and Adleman, 1978) can be verified by anyone with the public key and produced only by the private-key holder. None of them proves the content was true when signed — only that it has not changed since.
19.3 Hash chains and anchors
Linking each manifest entry to the hash of the previous one makes edits detectable: changing entry $i$ changes every later hash. But an attacker with write access can recompute the whole chain. The defence is an anchor — the latest head hash and entry count, authenticated with a key the attacker does not hold, or published to an independent party. Tamper-evident logging research (Schneier and Kelsey, 1999; Crosby and Wallach, 2009) develops these ideas; trusted timestamping (RFC 3161) binds a hash to a time asserted by a third party.
19.4 Worked example (synthetic): the HVSS evidence manifest
"""Lab 19 (synthetic): hash-chained, HMAC-anchored evidence manifest; tamper detection."""
import hashlib, hmac, json
KEY = b"synthetic-anchor-key-not-for-production"
def entry_hash(prev, item):
return hashlib.sha256((prev + json.dumps(item, sort_keys=True)).encode()).hexdigest()
def build(items):
chain, prev = [], "0" * 64
for it in items:
prev = entry_hash(prev, it); chain.append({"item": it, "h": prev})
anchor = hmac.new(KEY, f"{len(chain)}:{prev}".encode(), hashlib.sha256).hexdigest()
return chain, anchor
def verify(chain, anchor):
prev = "0" * 64
for i, e in enumerate(chain):
prev2 = entry_hash(prev, e["item"])
if prev2 != e["h"]: return f"break at entry {i}"
prev = prev2
a = hmac.new(KEY, f"{len(chain)}:{prev}".encode(), hashlib.sha256).hexdigest()
return "ok" if hmac.compare_digest(a, anchor) else "anchor mismatch (truncation or rewrite)"
items = [{"file": f"host{i}.evtx", "sha256": hashlib.sha256(f"blob{i}".encode()).hexdigest()[:16], "by": "collector-2"} for i in range(5)]
chain, anchor = build(items)
print("intact:", verify(chain, anchor))
t = json.loads(json.dumps(chain)); t[2]["item"]["sha256"] = "0" * 16
print("edited item 2:", verify(t, anchor))
print("truncated to 4:", verify(chain[:4], anchor))
r, _ = build(items[:4]); print("rewritten without key-held anchor:", verify(r, anchor))
Expected output:
intact: ok
edited item 2: break at entry 2
truncated to 4: anchor mismatch (truncation or rewrite)
rewritten without key-held anchor: anchor mismatch (truncation or rewrite)
Editing an item breaks the chain at that entry. Truncation leaves a valid-looking chain but fails the anchor, because the anchor binds the count. A full rewrite also fails — but only because the attacker lacks the anchor key. What the signature supports and what it does not: it supports "this manifest has not changed since the anchor was computed by a key holder". It does not support "collector-2 collected these files correctly", "the files are what the label says" or "no other file existed". If administrators share one account that can read the anchor key, any of them could rewrite the chain and re-anchor: cryptography moves the trust to key custody and role separation, it does not remove it.
19.5 Key lifecycle
Generation (in a hardware security module or managed key service where possible), storage with access limited to the anchoring service, rotation with overlap so old anchors remain verifiable, revocation procedures, and logging of every key use. Document which keys protect which claims.
For the Lab 19 manifest, the published key synthetic-anchor-key-not-for-production breaks every one of these rules, which is why it is marked as never to be used. A production anchor key would sit in a managed key service that only the anchoring service can call, and its use would be logged. After rotation, the old key must stay available for verifying anchors computed before the change.
19.6 Errors and limits
- Treating a hash as proof of origin.
- Hash chains without independent anchors.
- Signing keys accessible to the people whose actions are logged.
- Claiming signatures prove truth of content.
Lab 19 shows the limit that lies behind each of these errors. The SHA-256 values for host0.evtx to host4.evtx show only that copies match, not who made them. The chain alone did not catch truncation to four entries; only the HMAC anchor, which binds the count, did. Even an intact anchor says nothing about whether collector-2 gathered the right files.
Exercises — chapter 19
EX037 — Attack the chain. Objective: understand the anchor's role. Inputs: Lab 19. Steps: write code that appends a forged entry and recomputes the chain; show which check catches it with and without knowledge of KEY. Expected evidence: code and outputs. Rubric: 3 = shows anchor mismatch without key and silent success with key, with the conclusion about key custody; 2 = one case; 1 = attempt; 0 = none.
EX038 — Claims and roles. Objective: separate what crypto supports. Inputs: the HVSS evidence store with signed manifests and a shared administrator account. Steps: list three claims the signatures support, three they do not, and two role changes needed. Expected evidence: lists. Rubric: 3 = precise and role changes address key custody and named administration; 2 = partial; 1 = vague; 0 = none.
Chapter synthesis
Identity gives accountability; hashes give matching; MACs and signatures give integrity relative to key holders; anchors make chains tamper-evident. Every cryptographic claim rests on key custody and role separation, which must be designed as carefully as the algorithms.
Continue studying — chapter 19 of 50
← Chapter 18 · Course chapter index · Chapter 20 →
Continue to the next authored lesson.