id-RFC-017 — Identity-bound full-disk encryption for Kodix: TPM-sealed LUKS, measured-boot + presence-gated unlock (BitLocker+Hello / FileVault parity)
| Field | Value |
|---|---|
| Status | Ratified (2026-06-25 — owner answered all §9 questions, accepting the recommendations). The decision to build FDETPM was already ratified via id-RFC-016 Q4 (owner, 2026-06-08); the §9 design choices (presence factor, AB-safe PCR policy, recovery custody) are now resolved → implementation may begin at slice S1. |
| Author(s) | Rodrigo (with Claude as scribe) |
| Target modules | infra/linux/kodix (bootinitramfs, image build, AB live-update #081#082), `infralinuxkolide (greeter handoff, #048), servicesfoundation/id (emergency-kit recovery, id-RFC-014a`), new initramfs unseal hook |
| Related | id-RFC-016 (esp. Q4/N3 — this RFC is the named follow-up — and §5.3 cache custody / §5.5 device-join policy at-rest protection), id-RFC-014a (emergency-kit recovery — the recovery-key custody home), kolide#048 (native greeter — the post-unlock login target), kodix#081 (full-live-system umbrella, zero-physical-reboot), kodix#082 (userspace AB image live-update — the PCR-brittleness coupling), `specsauthpasskeys.kmd (the identity factor), policiesidentity-data-retention.kmd, policiesself-hosted-first.kmd, policiesstack-principles.kmd §2` |
| Origin | id-RFC-016 Q4 (owner, 2026-06-08): "FDE/TPM binding — *YES, as a follow-up RFC* seal the LUKS key in the TPM + gate disk-unlock on the passkey/presence so data-at-rest is tied to identity (BitLocker+Hello / FileVault parity)."* Also closes the open custody question raised while implementing id-RFC-016 S2 (the offline cache §5.3 root-of-trust needs at-rest integrity, not just root 0700). |
1. Summary
Make Kodix's data-at-rest bound to identity + platform: the root (and any data) volume is LUKS2 full-disk-encrypted, and its master key is sealed in the TPM2, released at boot only when (a) the measured-boot state matches a sealing policy (tamper-evident firmwarebootloadersecure-boot chain) and (b) a presence/identity factor is satisfied — TPM PIN or the Koder ID passkey ceremony. This is BitLocker + Windows Hello / FileVault parity, against your own self-hosted IdP, and it is the named follow-up to id-RFC-016 Q4.
It does two things at once:
- Identity-bound FDE (the literal Q4 ask): data on the disk is unreadable
unless this platform boots its expected software and a present user passes the factor — pulling the disk or evil-maiding the boot chain yields ciphertext.
- Closes the
id-RFC-016§5.3 custody hole (the implementation finding):the offline-login cache (
/var/lib/koder-id-cache— cached passkey pubkeys, sign-counters, Argon2id hashes) and the §5.5 device-join policy / allow- list are the local root-of-trust for offline login.root 0700protects them from a running-OS non-root reader but not from an offline-disk attacker (pull the disk, mount, rewrite the allow-list to add yourself, or read the cached material). FDE keyed to the TPM is the root-cause fix (D12): at-rest confidentiality and integrity for the whole offline trust store, not a per-record bolt-on.
The hard part — and why this is its own RFC — is doing FDE without breaking the A/B live-update (kodix#081/#082): naïve measured-boot sealing re-locks the disk every kernel update. §5.5 is the load-bearing design.
2. Problem / motivation
id-RFC-016makes Kodix a Koder-ID-joined OS with offline login(§5.3): a previously-seen user logs in with no network by verifying a passkey assertion against a locally-cached public key + checking the sign-counter monotonicity, or an Argon2id password hash. The seam that detects a tampered store (
KidStoreStatus{ABSENT,VALID,INVALID}— "tampered ≠ absent", fail-closed) was implemented in S2. But detection is not prevention: an attacker who controls the bytes (offline disk) can craft a store the app reads asVALID, or simply read the cached material. The §5.5 device-join allow-list ("who may log into this machine") has the same exposure — an offline attacker rewrites it to authorize their own Koder ID.root 0700+ theINVALIDseam are the right runtime defenses, but theat-rest threat (stolen powered-off laptop / pulled disk) is a crypto problem, and the correct crypto answer is FDE.
id-RFC-016deliberately deferred this (N3 / Q4) to keep that RFC's scope onlogin; the owner ratified doing it as a follow-up. This RFC is that follow-up: it specifies how the disk is encrypted and how the key is custodied so it inherits the passwordless, offline-capable, never-brick properties of
id-RFC-016.- Why TPM-sealed and not a passphrase: a passphrase the user retypes at boot
contradicts the passkey-first / passwordless UX
id-RFC-016establishes (Q2Q3) and is itself phishableshoulder-surfable. Sealing in the TPM, gated on measured boot + presence, matches the identity-bound model and the Windows/Mac bar this Stack is consciously meeting and exceeding.
3. Goals / non-goals
Goals
- G1 — Root (and optional data) volume is LUKS2 FDE; master key
sealed in the TPM2 (no plaintext key on disk, no user-typed passphrase on the happy path).
- G2 — Measured-boot gating: the TPM releases the key only when the
boot-chain PCR state matches the sealing policy (tamper-evident: firmware, secure-boot state, signed kernel).
- G3 — Presence/identity factor at unlock — TPM PIN or the Koder ID
passkey ceremony — so a powered-off stolen machine does not auto-decrypt (BitLocker TPM+PIN parity, not bare TPM-only).
- G4 — Close the
id-RFC-016§5.3/§5.5 custody hole: the offline cache+ device-join policy inherit at-rest confidentiality + integrity from FDE; the offline-disk readtamperdowngrade attack is cryptographically prevented.
- G5 — Never brick (recovery): a recovery key unseals if the TPM/PCR
state legitimately changes (firmware update, hardware swap, TPM clear) or the TPM fails; custodied via the
id-RFC-014aemergency kit. Mirrorsid-RFC-016§5.7 "never brick the box". - G6 — Survive A/B live-update (
kodix#081/#082): a kernel/UKI swap onthe inactive slot must not require re-sealing or a recovery-key prompt on the next boot. The sealing policy authorizes any Koder-signed kernel.
- G7 — Reuse-first: LUKS2 + the TPM2 stack (
systemd-cryptenroll/systemd-pcrlock/ TPM2 authorized policy) are mature, audited plumbing — we configure them, we don't reinvent a crypto layer (reuse-first.kmd §5).
Non-goals (this RFC)
- N1 — Per-user / per-file home-directory encryption (ecryptfs/fscrypt,
systemd-homed). Adjacent and complementary; a separate document. FDE here is the whole-volume at-rest layer. - N2 — Fleet key-escrow / remote attestation / MDM-driven recovery custody
(future; this RFC is the per-device contract an MDM would later orchestrate — symmetric with
id-RFC-016N2). - N3 — Non-TPM hardware as a first-class path. Machines without a usable
TPM2 fall back to passphrase LUKS (documented, §5.7), but the designed happy path assumes a TPM2 (every Kodix target ships one).
- N4 — Encrypting the ESP / boot partition itself (must stay readable by
firmware); integrity of the boot chain is handled by measured boot + secure-boot signing, not encryption.
4. Background
- LUKS2: the Linux FDE standard. A volume has a master key; keyslots each
unseal the master key from a different secret (passphrase, TPM-sealed blob, recovery key). Multiple keyslots coexist — this is how "TPM happy path + recovery key" is expressed natively.
- TPM2 sealing: a secret can be sealed to the TPM under a policy —
most importantly a PCR policy (release only if a set of Platform Configuration Registers hold expected measurements) and/or authValue (a PIN).
systemd-cryptenroll --tpm2-deviceenrolls a TPM-backed LUKS keyslot;--tpm2-with-pin=yesadds the presence factor;--tpm2-pcrs=selects PCRs. - PCRs that matter:
0(firmware),2(option ROMs),4(bootloader /boot path),
7(secure-boot state + keys),11(UKI / kernel measurements, via systemd-stub).7is stable across kernel updates if secure-boot keys don't change;411change on every kernelUKI swap — the A/B problem. - Measured boot vs secure boot: secure boot refuses to run an unsigned
kernel; measured boot records what ran into PCRs so the TPM can gate secrets on it. We use both: secure-boot signing (Koder's key) authorizes the kernel; measured boot seals the disk key to that fact.
systemd-pcrlock/ TPM2 authorized policy: instead of sealing to aliteral PCR-11 value (brittle), seal to a signed policy — the TPM releases the key for any PCR state signed by a trusted policy key. This is the mechanism that lets a Koder-signed A/B kernel update unseal without re-enrolment (G6).
id-RFC-016cache store (the thing we're protecting):/var/lib/koder-id-cache/(record per provisioned Koder ID) +/var/lib/koder-id/{policy,credentials}(device-join allow-list + registered passkeys). Implemented in S2 with theABSENT/VALID/INVALIDdowngrade- protection seam; FDE is the at-rest layer underneath it.- Prior art: BitLocker (TPM, or TPM+PIN for presence; recovery key in a
Microsoft account / printout); FileVault (key in the Secure Enclave, gated on the login password; recovery key / iCloud). This RFC matches TPM+PIN/passkey and exceeds them by custodying recovery in the self-hosted
id-RFC-014aemergency kit.
5. Design
5.1 Components
┌─ install / image build (kodix) ──── creates the LUKS2 volume, enrolls the
│ TPM2 keyslot (sealing policy) + a recovery
│ keyslot; records the recovery key into the
│ id-RFC-014a emergency kit
├─ initramfs unseal hook (NEW) ─────── asks the TPM2 to release the master key
│ ├─ measured-boot gate: TPM checks the PCR / signed policy (G2/G6)
│ ├─ presence factor: TPM PIN prompt, or defer to the greeter passkey (§6)
│ └─ on success: LUKS opens → pivot to real root → greetd/kolide (id-RFC-016)
├─ sealing policy (signed) ─────────── TPM2 authorized policy keyed to Koder's
│ secure-boot/policy key → any Koder-signed
│ kernel unseals (survives A/B update, G6)
├─ recovery path (id-RFC-014a) ─────── recovery keyslot; emergency-kit custody;
│ re-seal flow after legit PCR change (G5)
└─ at-rest custody (G4) ────────────── /var/lib/koder-id-cache + /var/lib/koder-id
now live on the FDE volume → confidential
+ integrity-protected at restThe only new code is the initramfs unseal hook + the install-time enrolment and re-seal flows; the crypto is LUKS2 + TPM2 (systemd-cryptenroll/pcrlock).
5.2 Enrolment (install-time / image build)
- Create the LUKS2 volume for
/(and an optional separate/varor datavolume so the §5.3 cache is always covered even on a future split layout).
- Enroll a TPM2 keyslot sealing the master key under the chosen policy
(§5.5) + the presence factor (§5.6):
systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs=<stable set> --tpm2-with-pin=<§6 decision> <dev>. - Enroll a recovery keyslot (high-entropy recovery key); *ecord the
recovery key into the
id-RFC-014aemergency kit*(the existing self-hosted recovery-custody home) — never printed-only, never escrowed in the clear. - Keep the local-admin break-glass (
id-RFC-016 §5.7) able to drive therecovery keyslot, so the never-brick guarantee holds end-to-end.
5.3 Unlock flow (boot)
- Firmware → secure-boot-verified bootloader → UKI; PCRs accrue measurements.
- initramfs unseal hook asks the TPM2 to release the master key under the
sealing policy. PCRs match (expected platform + a Koder-signed kernel) → key released. PCRs mismatch (tampered boot chain / unsigned kernel) → refused → fall to the recovery path (§5.6), never silent-fail-open.
- Presence factor (§5.6): TPM PIN entered in the initramfs, or (option B)
the unseal is deferred and the greeter passkey ceremony gates it.
- LUKS opens; pivot to the real root;
greetdstartskolide-shell --greeter— and
id-RFC-016login proceeds normally (now over an encrypted disk).
5.4 At-rest custody for the offline trust store (closes id-RFC-016 §5.3/§5.5)
Once / (or the /var carrying it) is FDE:
- Confidentiality: the cached passkey pubkeys, sign-counters, and
Argon2id hashes are unreadable from a powered-off / pulled disk. (They were never reversible secrets, but pubkey + counter disclosure aids targeted attacks; the allow-list disclosure is a privacy/recon leak.)
- Integrity: an offline attacker cannot rewrite the §5.5 device-join
allow-list to authorize their Koder ID, nor forge a
VALID-parsing cache record, because they cannot produce ciphertext that decrypts to a chosen plaintext without the TPM-sealed key. This is the structural answer the S2ABSENT/VALID/INVALIDseam detects but cannot prevent. root 0700stays as defense-in-depth for the running system (anon-root local process still can't read the store); FDE adds the at-rest layer the running-system permission can't provide. Two layers, two threats.
This is the custody decision recorded during
id-RFC-016S2 (the/k-arch"path-b"): integrity-at-rest via FDE/TPM +root 0700, not per-record org-signing of every cache entry. Org-signed allow-lists remain a fleet-phase addition (§5.5 of id-RFC-016, N2 here) — for a personal device the TPM is the local anchor and per-record signing would be redundant ceremony (Rule 13: match the threat, don't over-build). Server-side custody (Koder Vault / KMS,id-RFC-014) is the wrong primitive for an offline-device root-of-trust — the device must verify with no network; the TPM is the only local anchor.
5.5 AB live-update survival (the load-bearing design — kodix#081#082)
kodix#082 ships kerneluserspace updates to the *nactive AB slot with zero physical reboot. A naïve seal to PCR 4/11 (which measure the specific kernel/UKI) would make the disk un-unsealable after every update* forcing a recovery-key prompt each time — unacceptable.
Design: seal to a signed policy, not a literal PCR value.
- Seal the TPM keyslot to stable PCRs (
0,2,7— firmware + optionROMs + secure-boot state/keys) plus a TPM2 authorized policy /
systemd-pcrlockthat authorizes the kernel-measurement PCRs (11) for any kernel signed by Koder's secure-boot key. - Effect: an A/B update that installs a Koder-signed kernel satisfies the
signed policy → unseals on the next boot without re-enrolment. An unsigned / tampered kernel does not match → refused (the security property is preserved).
kodix#082's update flow gains a step: when the secure-boot signing key or theauthorized-policy itself changes (rare), re-seal (drive the recovery keyslot once, re-enroll the TPM keyslot). Routine kernel updates need nothing.
This couples this RFC to kodix#081/#082; the signed-policy approach is the reason FDE and live-update coexist instead of fighting.
5.6 Recovery (never brick — id-RFC-014a)
- A recovery keyslot (§5.2) unseals the volume when the TPM refuses
(firmware update changed PCR 07, hardware swap, TPM clearedfailed, lost PIN).
- Custody: the recovery key lives in the
id-RFC-014aemergency kit —the Stack's existing self-hosted recovery-custody mechanism — not a vendor cloud (the
self-hosted-firstparity point vs BitLocker's MS-account escrow). - Re-seal flow: after a legitimate PCR change, the system (or the owner via
break-glass) re-enrolls the TPM keyslot to the new measurements, so the happy path resumes; the recovery key is rotated if it was used.
- Local-admin break-glass (
id-RFC-016 §5.7) can always drive recovery →the machine is never bricked even if Koder ID and the TPM are unavailable.
5.7 Non-TPM fallback (N3)
On a machine with no usable TPM2, enrolment falls back to a passphrase LUKS2 keyslot (no identity binding, user types it at boot) + the recovery key. This is a documented downgrade, surfaced at install ("this machine has no TPM — disk encryption will require a passphrase"), not a silent loss of FDE.
6. Alternatives considered (the /k-arch deliberation)
- A — Passphrase-only LUKS (no TPM). Rejected as the design (kept as the N3
fallback): contradicts the passwordless
id-RFC-016UX, phishable/shoulder- surfable, no platform binding. A valid fallback, not the target. - B — TPM-sealed, PCR-only, no presence factor (bare TPM auto-unlock).
Rejected: a powered-off stolen laptop boots and auto-unseals to the greeter — the disk key is in RAM and the data volume is mounted before any human factor. This is BitLocker TPM-only mode, which Microsoft itself flags as weaker; an evil-maid / DMA / cold-boot adversary is in scope. Convenient, but trades away exactly the at-rest protection we're here for.
- * — TPM-sealed + measured-boot + presence factor (TPM PIN or greeter
passkey) + signed-policy for A/B (this RFC). Chosen. Most complete + correct long-term (
stack-principles §2): platform-bound, identity-bound, A/B-compatible, never-brick. Higher up-front effort (initramfs hook, signed policy, re-seal flow) — accepted. Two sub-options for the presence factor, deferred to Q1: C1 TPM PIN in initramfs (BitLocker TPM+PIN parity, simplest, factor-before-decrypt); C2 defer unseal to the greeter passkey*(true passkey-gated FDE, best UX-identity alignment, but requires the authenticator be reachable from a minimal early-userspace — harder). - D — Per-filehome encryption only (
systemd-homedfscrypt), no FDE.Rejected as the answer (kept as complementary N1): does not protect the system-level
id-RFC-016cache + device-join policy (they're not in a user home), so the §5.3/§5.5 custody hole stays open. FDE is the layer that closes it; per-user encryption can be added on top later.
Trade-off recorded: C accepts real implementation cost (initramfs unseal hook + the signed-policy machinery to survive AB updates + the re-seal recovery flow) to avoid (B) "v1 that auto-unlocks a stolen laptop" and (A) "type a passphrase, abandoning passwordless". The structurally better form is achievable, so it wins (Rule 13 / D12 root-cause: the real requirement is data-at-rest bound to identity+platform, and bare-TPM or passphrase each drop one half of that).
7. Security considerations
- Evil-maid / boot tamper: measured boot (PCR 027 + secure-boot signing)
makes a tampered boot chain fail to unseal → refused, not fail-open.
- Stolen powered-off device: the presence factor (Q1) is what stops bare
auto-unlock; without it, FDE degrades toward (B). This is the single most important §9 decision.
- Cold-boot / DMA: the key is in RAM only after unseal; presence-before-
decrypt (C1) shrinks the window vs auto-unlock (B). Out-of-scope hardening (memory encryption) is a hardware concern.
- PCR brittleness vs security: the signed-policy (§5.5) is a deliberate
relaxation (any Koder-signed kernel unseals) — it trades "seal to this exact kernel" for "seal to our signing authority", which is the correct trust boundary for a self-updating OS. The signing key's custody (Koder secure-boot key) becomes load-bearing and must be protected accordingly.
- Recovery-key custody: in the
id-RFC-014aemergency kit, self-hosted —no third-party escrow. Compromise of the emergency kit =compromise of FDE, so it inherits
id-RFC-014a's protections. - Custody-hole closure (G4): the §5.3 offline cache + §5.5 allow-list gain
at-rest confidentiality+integrity; combined with the S2
INVALIDruntime seam, the downgrade attack is closed both at-rest (can't forge ciphertext) and at runtime (tamper ≠ absent, fail-closed). - TPM firmware trust: we trust the platform TPM2; a backdoored TPM is outside
this threat model (as it is for BitLocker/FileVault).
- Retention: any auth-data the unseal path logs follows
policies/identity-data-retention.kmd; the disk key is never logged.
8. Implementation slices (phased — Rule 15 cat-A)
- S1 — LUKS2 + TPM seal at image build (
kodiximage pipeline): create theencrypted volume, enroll the TPM2 keyslot (stable PCRs) + recovery keyslot; record the recovery key into the
id-RFC-014aemergency kit. Headless- testable in a VM with a software TPM (swtpm). - S2 — initramfs unseal hook (§5.3): minimal early-userspace unit that
unseals + opens LUKS + pivots; refuse-and-fall-to-recovery on PCR mismatch.
- S3 — presence factor (§5.6 / Q1): C1 TPM-PIN first (simplest, BitLocker
parity); C2 greeter-passkey as a follow-on if Q1 picks it.
- S4 — signed-policy for A/B survival (§5.5, couples
kodix#082):authorize any Koder-signed kernel; prove an A/B kernel update unseals with no recovery prompt; add the re-seal step for signing-key rotation.
- S5 — recovery + emergency-kit integration (§5.6 /
id-RFC-014a): recoverykeyslot drive, re-seal flow after legit PCR change, local-admin break-glass.
- S6 — custody-hole regression (§5.4 / G4): an offline-disk attack
regression — mount the powered-off image, attempt to (a) read the cache and (b) rewrite the device-join allow-list; assert both fail against the encrypted volume (and that a decrypted-then-tampered store still trips the S2
INVALIDseam). Registers under the per-file regression registry.
9. Open questions (owner)
All §9 questions RESOLVED (owner, 2026-06-25) — the owner accepted the recommendations as written ("vai nas recomendações"). Status promoted Draft → Ratified; implementation may begin at slice S1.
- Q1 — Presence factor: TPM-PIN (C1) vs greeter-passkey (C2) vs PCR-only (B)?
— RESOLVED (owner, 2026-06-25): C1 (TPM-PIN) for the first cut, with C2 (passkey-gated unseal) as a follow-on slice once the early-userspace authenticator path is proven. PCR-only (B) rejected (auto-unlocks a stolen device). BitLocker TPM+PIN parity, factor-before-decrypt — the load-bearing security decision. Drives S3 (§5.6 / §6 alt C1→C2).
- Q2 — A/B sealing policy mechanism: — *ESOLVED (owner, 2026-06-25):
systemd-pcrlockif the Kodix systemd is new enough, else a hand-rolled TPM2 authorized policy keyed to Koder's secure-boot key. Either way: seal to the signing authority, not a literal kernel PCR (§5.5). Drives S4*(the A/B-survival slice, coupleskodix#082). - Q3 — Recovery-key custody: — RESOLVED (owner, 2026-06-25): the
id-RFC-014aemergency kit as the system of record, + a one-time printed recovery code at install for the cold-start window (before the emergency kit exists). Drives S5 (§5.6). - Q4 — Encryption scope: — *ESOLVED (owner, 2026-06-25): separate
encrypted
/var(data) volume long-term (cleaner A/B + custody story; the §5.3 cache is independently keyable and the system image stays measured/ reproducible); root-FDE acceptable for the first cut. Drives S1*s layout decision. - Q5 — Non-TPM hardware: — *ESOLVED (owner, 2026-06-25): passphrase-LUKS
fallback (§5.7) with a loud install-time warning*— don't brick a TPM-less box, don't pretend it has FDE-parity. Stays N3 (not the designed happy path).
- Q6 — Numbering: — RESOLVED (owner, 2026-06-25): keep
id-RFC-017—it's "Koder ID identity-bound FDE", the direct
id-RFC-016Q4 follow-up, and cross-referencesid-RFC-016-014aheavily; `kodix#081#082` are the implementation coupling, referenced from here (not a re-home).
10. References
id-RFC-016— Kodix as a Koder-ID-joined OS (Q4/N3 = this follow-up; §5.3offline cache + §5.5 device-join policy = the custody store FDE protects; §5.7 never-brick).
id-RFC-014a— emergency-kit recovery (recovery-key custody home).kolide#048— native greeter over greetd (the post-unlock login target).kodix#081(full-live-system umbrella, zero-physical-reboot),kodix#082(userspace A/B image live-update — the PCR-brittleness coupling, §5.5).
specs/auth/passkeys.kmd(the C2 identity factor);policies/self-hosted-first.kmd(recovery custody vs vendor escrow);
policies/identity-data-retention.kmd;policies/stack-principles.kmd §2(Quality > Speed — the C-over-B trade-off);policies/reuse-first.kmd §5(LUKS2/TPM2 reused, not reinvented).- Tooling:
systemd-cryptenroll,systemd-pcrlock, LUKS2, TPM2 (PCRs, sealing,authorized policy),
swtpm(headless VM testing). - Prior art: BitLocker (TPM / TPM+PIN; MS-account recovery escrow) and
FileVault (Secure Enclave, login-gated; iCloud recovery) — the at-rest bar this RFC matches and the self-hosted recovery it improves on.
Changelog
- 2026-06-25 — Draft v0.1. The named follow-up to
id-RFC-016Q4 (ownerratified building FDE/TPM on 2026-06-08). Also closes the offline-cache §5.3 / device-join §5.5 at-rest custody hole found while implementing
id-RFC-016S2 (the/k-arch"path-b": integrity-at-rest via FDE/TPM +root 0700, org- signed allow-lists deferred to the fleet phase). Design = alt C (TPM-sealed + measured-boot + presence factor + signed-policy for A/B survival). StatusDraftpending owner answers to §9 (Q1 presence factor is load-bearing). - 2026-06-25 — *ll §9 questions resolved (owner, "vai nas recomendações")
→ status promoted Draft → Ratified. Q1 = C1 (TPM-PIN) first, C2 (passkey) follow-on, B rejected; Q2 =
systemd-pcrlock(else authorized-policy); Q3 = emergency-kit (id-RFC-014a) + one-time printed code; Q4 = separate encrypted/varlong-term, root-FDE acceptable first cut; Q5 = passphrase fallback + loud warning; Q6 = keepid-RFC-017. Implementation may begin at slice S1*