Chapter 19 — Identity and cryptography
Lesson map
Lesson 19 published. Map, example, EX055.
flowchart TD
N0["Learning outcomes"]
N1["19.1 Hashes"]
N2["Lab — Lab — verifying an artifact"]
N3["19.2 Lab result"]
N4["19.3 Signatures"]
N5["19.4 Keys and identities"]
N6["19.5 Encryption"]
N7["19.6 Key management"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6 --> N7
N7 --> EX["Worked example"]
EX --> Q["Exercise EX055"]
Logical drawing
flowchart LR
N0["Learning outcomes"]
N1["19.1 Hashes"]
N2["Lab — Lab — verifying an artifact"]
N3["19.2 Lab result"]
N4["19.3 Signatures"]
N5["19.4 Keys and identities"]
N6["19.5 Encryption"]
N7["19.6 Key management"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6 --> N7 --> Q["EX055"]
[Learning outcomes]
|
v
[19.1 Hashes]
|
v
[Lab — Lab — verifying an artifact]
|
v
[19.2 Lab result]
|
v
[19.3 Signatures]
|
v
[19.4 Keys and identities]
|
v
[19.5 Encryption]
|
v
[19.6 Key management]
|
v
[Worked example] --> [Exercise EX055]
Learning outcomes
You will (1) explain hashing, signing and encryption for software integrity; (2) verify artifacts against published digests; (3) compare digests safely; (4) manage keys and identities for build systems.
19.1 Hashes
A cryptographic hash such as SHA-256 maps any data to a fixed-length digest; any change gives a different digest. Publishing the digest lets anyone check an artifact.
Two properties make this useful. It is infeasible to find a different file with the same digest, so an attacker cannot craft a substitute that passes the check, and the digest is small enough to publish, store in a build record or paste into a lockfile. The digest says nothing about whether the file is good, only whether it is the same file the reference describes.
Lab — Lab — verifying an artifact
"""Verify a build artifact's SHA-256 against the published digest using a constant-time compare."""
import hashlib, hmac
artifact = b"ticket-web 3.2.0 build output (synthetic)"
published = hashlib.sha256(b"ticket-web 3.2.0 build output (synthetic)").hexdigest()
tampered = artifact + b" extra"
for name, blob in (("release", artifact), ("mirror copy", tampered)):
ok = hmac.compare_digest(hashlib.sha256(blob).hexdigest(), published)
print(f"{name:12} {'VERIFIED' if ok else 'DIGEST MISMATCH - do not deploy'}")
Run with python3 lab_hash.py. Verified output:
release VERIFIED
mirror copy DIGEST MISMATCH - do not deploy
19.2 Lab result
The release copy matches its published digest and is verified. The mirror copy, with extra bytes, gives a digest mismatch and is marked "do not deploy". The lab uses hmac.compare_digest, a constant-time comparison, a good habit when comparing secrets and a safe default for digests.
The tampered copy differs only by six bytes at the end, yet its digest bears no resemblance to the published one, which is why truncation in the mirror incident was detectable. An ordinary string comparison stops at the first differing character, and its timing can leak information when the compared value is secret.
19.3 Signatures
A digest proves the file matches a reference, but who published the reference? A digital signature binds the digest to an identity. Deployment checks both.
An attacker who can change both the artifact and the published digest on the same server defeats a digest check alone, which is the weakness the errors note at the end of this chapter warns about. The signature moves trust to a key or identity the attacker does not control. Deployment first verifies the signature on the build record, then compares the artifact's digest with the one in that record.
19.4 Keys and identities
Build signing uses short-lived credentials issued to the CI identity, not personal keys. Developers sign in with multi-factor authentication; OWASP Top 10:2021 A07 covers identification and authentication failures.
Personal keys travel with people: onto laptops, into backups and out of the company when someone leaves. A CI identity exists only inside the pipeline and receives credentials for minutes, so a leaked credential soon becomes useless. Multi-factor sign-in for developers protects the steps before CI, since a stolen password alone could otherwise push code that CI would build and sign faithfully.
19.5 Encryption
Encryption protects confidentiality, for example of backups and network traffic; it is not the same as integrity protection.
An encrypted file can still be replaced with a different encrypted file, or corrupted, without the reader noticing unless an integrity check is added. Modern authenticated encryption schemes combine both properties, but plain encryption does not. For artifacts, which are usually public, confidentiality matters little; integrity and authenticity are the goals, so signatures and digests do the work. Backups need both, since they hold rider data and must not be swapped for altered copies.
19.6 Key management
Keys are stored in a managed key service, rotated and access-logged.
A managed service keeps keys inside hardware or software that performs signing and decryption without exporting the key, so administrators use keys without being able to copy them. Rotation limits how long any single key is useful if it leaks unnoticed. Access logs show which identity used which key and when; Kwame reviews them monthly for use outside the CI jobs that should need them. Short-lived signing credentials still depend on longer-lived keys elsewhere, such as the key service's own root, so those are protected most carefully.
Rotation and revocation
Credentials are rotated on a schedule and revoked at once when staff leave or a leak is suspected.
Audit trail
Every signing event is logged with the CI job, commit and time.
Worked example
Kwame adds digest verification to the deploy script for ticket-web. In the first month it blocks one deployment, from an outdated cache holding an older build with the same version label. The label was reused by mistake; Coastline adds a rule that version labels can never be reused.
Synthetic case. Artifacts and digests are synthetic.
Errors and limits
A digest check is only as good as the source of the expected digest; protect that source.
Exercises
- EX055 — Lab result. What did the lab report for the two copies? Rubric: 3 = release VERIFIED; mirror MISMATCH do not deploy; 2 = partial; 1 = vague; 0 = none.
- EX056 — Signature purpose. What does a signature add to a digest? Rubric: 3 = binds to publisher identity; 2 = partial; 1 = vague; 0 = none.
- EX057 — Blocked deploy. What did the deploy check block? Rubric: 3 = outdated cache build with reused label; no reuse rule; 2 = partial; 1 = vague; 0 = none.
Synthesis
Hashes, signatures and managed identities let you trust what you deploy.
Continue studying — chapter 19 of 50
← Chapter 18 (draft) · Course chapter index · Chapter 20 (draft) →