AGENTS/tasks/2026-06-19-keyid-1-fingerprint.md
keyID)Date: 2026-06-19
Plan: AGENTS/plans/2_20/encryption-key-rotation.md — "Target design (phase 2)"
Status: ✅ Done
Depends on: — (foundation; everything else builds on this)
Size: S
Derive a stable, collision-resistant key id from the key material itself, so the id↔key binding is intrinsic (cannot be repointed at different material) and a removed key fails loudly instead of silently mis-decrypting. This is the content-addressing primitive the whole keyset model rests on.
util/keyid.go (new):
func keyID(material string) string — material is the base64 key as it
appears in the file. Implementation: base64-decode → sha256 of the raw key
bytes → first 8 bytes → base64.RawURLEncoding. Empty/invalid material ⇒
"" (no id; means "encryption disabled / passthrough").HMAC-SHA256(key, label)[:N]) and
why plain truncated SHA-256 is fine for validated 16/24/32-byte keys.pkg/jwt/signer.go:computeKID (same idea for the JWT public
key) — keep them conceptually aligned, do not share code (different inputs).util/keyid_test.go)"".+///=/: — important: the id is later used as a
ciphertext prefix split on :).: must never appear in an id (the envelope splits on the first :).
base64.RawURLEncoding guarantees [A-Za-z0-9_-] only.