ADR-004: Crypto agility and post-quantum cryptography
ADR-004: Crypto agility and post-quantum cryptography
Section titled “ADR-004: Crypto agility and post-quantum cryptography”- Status: Proposed
- Date: 2026-05-30
- Deciders: Keepin’ Tracks engineering
- Supersedes: Crypto details in ADR-003 (personal authentication)
- Superseded by: —
Context
Section titled “Context”Personal authentication (ADR-003) initially used fixed SHA-256 token hashing and opaque session cookies. We need:
- Crypto agility — swap hash, encryption, and signing algorithms without breaking stored data
- Post-quantum readiness — protect long-lived PII and session integrity against future quantum attacks
- Plane isolation — shared primitives only; each API plane supplies its own
SESSION_SECRET
Transport-layer PQC is already provided by Cloudflare (TLS 1.3 with X25519MLKEM768 on customer-facing hostnames). This ADR covers application-layer cryptography.
Decision
Section titled “Decision”1. Plane-agnostic package
Section titled “1. Plane-agnostic package”Implement packages/crypto (@keepintracks/crypto):
- No imports from
apps/* - No plane-specific cookie names or table names
- Callers pass
rootSecretand context strings (e.g.personal:email:v1)
2. Versioned storage format
Section titled “2. Versioned storage format”All stored digests and ciphertexts include an algorithm id:
| Format | Example |
|---|---|
| Token hash | v1.sha256.<hex> (legacy bare hex = sha256-v1) |
| Field encryption | aes256gcm-v1:<payload> or hybrid-mlkem768-aesgcm-v1:<payload> |
| Session cookie | v1.hmac.<payload>.<sig> |
3. Phased algorithms
Section titled “3. Phased algorithms”| Phase | Capability | Algorithms |
|---|---|---|
| A | Agility foundation | SHA-256-v1 hashes, HKDF-SHA256, AES-256-GCM field encryption |
| B | PQC at-rest PII | ML-KEM-768 envelope encryption for users.email when PQC_KEM_ENABLED=true |
| C | Signed sessions | HMAC-SHA256 (session-v1.hmac); hybrid HMAC + ML-DSA-65 (session-v2.hybrid) when PQC_SIGN_ENABLED=true |
4. Workers runtime
Section titled “4. Workers runtime”- Prefer Web Crypto (
crypto.subtle) for classical algorithms - ML-KEM via
mlkem-wasmbehind aKemProviderinterface until native Web Crypto ships ML-KEM - Lazy-load WASM; fall back to
aes256gcm-v1if PQC disabled or WASM unavailable
5. Key management
Section titled “5. Key management”| Secret | Plane | Purpose |
|---|---|---|
SESSION_SECRET | personal-api only | HKDF root, HMAC session signing, classical field encryption |
PQC_KEM_ENABLED | var (not secret) | Gate ML-KEM email encryption |
PQC_SIGN_ENABLED | var (not secret) | Gate ML-DSA hybrid session cookies |
Production/staging fail closed if SESSION_SECRET is missing or shorter than 32 bytes.
ML-KEM keypair for at-rest encryption is lazily generated and cached in KV (crypto:mlkem:v1) per isolation plane.
6. TLS
Section titled “6. TLS”No application TLS code. Document reliance on Cloudflare PQC for browser ↔ edge.
Data inventory (Law 25 / PIPEDA)
Section titled “Data inventory (Law 25 / PIPEDA)”| Data | Protection | Retention |
|---|---|---|
users.email (plaintext column) | Deprecated during migration | Until backfill completes |
users.email_encrypted | AES-GCM or hybrid ML-KEM | Until account deletion |
Magic-link token_hash | Versioned SHA-256 | Until used or expired |
| Session cookie | HMAC-signed reference to D1 session | Session TTL |
Consequences
Section titled “Consequences”Positive
Section titled “Positive”- Algorithms can rotate via version prefixes without schema migrations per algorithm
- Business plane can reuse
packages/cryptowith separate secrets and HKDF contexts - Aligns with NIST hybrid transition guidance
Negative
Section titled “Negative”- WASM adds bundle size (monitor with
wrangler deploy --dry-run) - Dual-read email path adds complexity during migration
- ML-KEM keypair in KV requires backup/rotation procedures
Follow-ups
Section titled “Follow-ups”ML-DSA hybrid session signatures (Phase C2)— Implemented (session-v2.hybrid,PQC_SIGN_ENABLED)Email backfill job for existing plaintext rows—POST /dev/backfill-email-encryption,bun run backfill:emailsAccount export / deletion—GET /me/export,DELETE /meSession cleanup cron— Daily0 4 * * *viascheduledhandler- WebAuthn passkey COSE algorithm agility
- Business-plane adoption with
business:*HKDF contexts - Remove plaintext
users.emailcolumn after backfill verification