◇ OpenCyber Academy
Engineering · Chapter 19 · English

Chapter 19 — Identity and cryptography

Open, free learning for anyone who wants to protect people and technology. No account is required to read this text or its worked answers.

Chapter 19 — Identity and cryptography

Lesson map

Lesson 19 published. Map, example, EX018.

flowchart TD
  N0["Learning outcomes and connection"]
  N1["19.1 Primitives"]
  N2["19.2 Authenticating telemetry"]
  N3["19.3 Key management"]
  N4["19.4 Identity for people and devices"]
  N5["19.6 Practical activity: Lab 8"]
  N6["Chapter synthesis"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6
  N6 --> EX["Worked example"]
  EX --> Q["Exercise EX018"]

Logical drawing

flowchart LR
  N0["Learning outcomes and connection"]
  N1["19.1 Primitives"]
  N2["19.2 Authenticating telemetry"]
  N3["19.3 Key management"]
  N4["19.4 Identity for people and devices"]
  N5["19.6 Practical activity: Lab 8"]
  N6["Chapter synthesis"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6 --> Q["EX018"]
[Learning outcomes and connection]
    |
    v
[19.1 Primitives]
    |
    v
[19.2 Authenticating telemetry]
    |
    v
[19.3 Key management]
    |
    v
[19.4 Identity for people and devices]
    |
    v
[19.6 Practical activity: Lab 8]
    |
    v
[Chapter synthesis]
    |
    v
[Worked example] --> [Exercise EX018]

Learning outcomes and connection

After this chapter you can (1) explain symmetric and public-key cryptography, hashes and MACs, and choose among them; (2) design message authentication with replay protection for constrained telemetry; (3) plan key management — generation, distribution, storage, rotation, revocation — for a field fleet; and (4) design identity and authentication for people and devices. It builds on Chapters 4, 13 and 18 and prepares Chapters 27–28.

19.1 Primitives

Never design your own primitives or protocols when a standard one fits; TLS 1.3 (RFC 8446) is the default for IP links that can run it.

19.2 Authenticating telemetry

For a constrained link, a common design is: payload plus a monotonic counter (or timestamp), MAC over both, receiver checks the MAC in constant time, then checks that the counter exceeds the last accepted value. The counter defeats replay; a timestamp with a freshness window defeats delay attacks but needs synchronised clocks. Truncating HMAC-SHA256 to 128 bits is common for bandwidth, with a correspondingly reduced but still very large forgery margin. Persist the last counter or rotate keys on restart, or a restart reopens replay (EX018).

19.3 Key management

Keys are where cryptography meets operations. Decide: who generates keys and where (ideally in hardware, never by hand); how they reach devices (factory provisioning, secure enrolment); where they are stored (secure elements, not configuration files); how they rotate (scheduled and after suspected compromise); how they are revoked; and who can access them. One key per device-pair limits the blast radius: compromising one RTU should not let an attacker impersonate another. A single fleet-wide key is a common cause with $\beta \approx 1$ (Chapter 7).

19.4 Identity for people and devices

People need named accounts, strong authentication (phishing-resistant multi-factor where possible — see NIST SP 800-63B), roles mapped to tasks, and prompt removal on departure. Devices need identities too — certificates or provisioned keys — so that a gateway knows which RTU it is talking to. Shared or default credentials are the most common identity failure in OT.

In TMRP, operators use named accounts with strong authentication at the SCADA servers, and each RTU has its own key, so the gateway knows which station sent each message.

19.5 Worked example: TMRP message format (synthetic)

ADR-007 chose HMAC with counters. The frame in Lab 8 carries an 8-byte counter, 2-byte station ID, 2-byte level and a 16-byte truncated HMAC-SHA256: 28 bytes, of which 22 are overhead relative to a 6-byte unauthenticated payload. Per-station keys are generated in the gateway's secure element at enrolment and stored in the RTU's key store; the SCADA side holds them in a hardware security module. Keys rotate annually and immediately on suspected compromise; the counter is persisted in non-volatile memory at each increment of 1,000 with a forward skip on restart, so replay of old messages remains impossible.

19.6 Practical activity: Lab 8

# Lab 8 - authenticated telemetry with a counter: tamper and replay are rejected (synthetic key, offline)
import hmac, hashlib, struct
KEY = bytes.fromhex("00112233445566778899aabbccddeeff00112233445566778899aabbccddeeff")  # demo key only
def seal(ctr, station, level_cm):
    body = struct.pack(">QHH", ctr, station, level_cm)
    return body + hmac.new(KEY, body, hashlib.sha256).digest()[:16]
class Receiver:
    def __init__(self): self.last = {}
    def accept(self, msg):
        body, tag = msg[:12], msg[12:]
        if not hmac.compare_digest(tag, hmac.new(KEY, body, hashlib.sha256).digest()[:16]): return "reject: tag"
        ctr, st, lvl = struct.unpack(">QHH", body)
        if ctr <= self.last.get(st, -1): return "reject: replay"
        self.last[st] = ctr; return f"ok st={st} ctr={ctr} level={lvl}cm"
r = Receiver(); m1, m2 = seal(1, 3, 312), seal(2, 3, 309)
forged = m2[:10] + struct.pack(">H", 150) + m2[12:]
for name, m in [("m1", m1), ("m2", m2), ("replay m1", m1), ("forged", forged)]: print(f"{name:10}", r.accept(m))
print("frame bytes:", len(m1), "overhead vs 6-byte payload:", len(m1) - 6)

Expected output:

m1         ok st=3 ctr=1 level=312cm
m2         ok st=3 ctr=2 level=309cm
replay m1  reject: replay
forged     reject: tag
frame bytes: 28 overhead vs 6-byte payload: 22

The key in the lab is a published demonstration value; real keys must never appear in source code.

The first two messages from station three are accepted with increasing counters. Replaying the first message is refused because its counter is not greater than the last accepted value, and the forged message, with its level changed from 309 to 150 centimetres, fails the tag check. The final line confirms the frame size used in ADR-007: twenty-eight bytes, twenty-two of them overhead. The lab keeps state only in memory, which is why EX018 asks what happens after a restart.

19.7 Common errors and limits

TMRP's design answers each item: tags are compared in constant time, counters persist across restarts, keys are per station in secure hardware, and the message format gains a suite identifier for future algorithm changes. Each choice has a test.

Exercises — chapter 19

EX037 — Counter persistence. Objective: design restart-safe replay protection. Inputs: §19.5 (persist every 1,000 increments). Steps: explain why the RTU must skip forward on restart and by how much at least; state what the receiver must persist. Expected evidence: explanation. Rubric: 3 = skip ≥ 1,000 beyond last persisted value so no counter is reused, receiver persists last-accepted per station or rotates keys; 2 = one side only; 1 = vague; 0 = none.

EX038 — Blast radius. Objective: compare key designs. Inputs: 42 field stations; option A one fleet key; option B one key per station. Steps: compare the consequence of extracting a key from one stolen RTU, the rotation effort after that theft, and the storage required at SCADA. Expected evidence: table and recommendation. Rubric: 3 = A lets the thief forge any station and forces fleet-wide rotation; B confines forgery to one station with one rotation; storage trivial; recommendation B; 2 = one dimension missing; 1 = recommendation without reasoning; 0 = none.

Chapter synthesis

Choose standard primitives for the property you need: hashes for fingerprints, MACs or signatures for authenticity, authenticated encryption for confidentiality with integrity. Add freshness to defeat replay and keep it across restarts. Key management is the real system: per-device keys in hardware, rotation and revocation. Give people and devices distinct, strongly authenticated identities.

Continue studying — chapter 19 of 50

← Chapter 18 · Course chapter index · Chapter 20 →

Continue to the next authored lesson.

Worked answers

EX018. Invariant: for each station, last[st] never decreases and equals the highest accepted counter. Sequence 1, 2, 2, 1, 5 → accept, accept, reject (replay), reject (replay), accept; final last[3] == 5. After a receiver restart, last is empty, so previously seen messages are accepted again unless the receiver persists last or keys are rotated on restart.

EX037. If the RTU persists its counter every 1,000 increments and restarts, the last persisted value may be up to 999 behind the last used value. To avoid reusing a counter (which the receiver would reject, or which could enable replay after a receiver reset), the RTU skips forward by at least 1,000 beyond the persisted value. The receiver must persist the last accepted counter per station, or both sides rotate keys after restart.

EX038. A (fleet key): one stolen RTU lets the thief forge messages for all 42 stations; recovery needs re-keying of every station. B (per-station keys): forgery confined to the stolen station; one key revoked and replaced. SCADA storage of 42 keys is trivial in an HSM. Recommendation: B.