Encryption, Keys & TPM2
InterGenOS protects your machine on two axes that compose into one boot path: encryption at rest (your data is an unreadable blob to anyone without your passphrase) and a signed boot chain (every component the system boots is signed and verifiable). This page covers both — full-disk encryption with LUKS2, the experimental TPM2 and FIDO2 unlock methods, the per-machine signing key, and the boot chain, whose Secure Boot enforcement is optional and off by default on the current fleet.
The boot path is the most privileged code on any machine, and the data on the disk is yours. These features exist to give you a machine you understand, can modify, and can trust.
At a glance
- Full-disk encryption is opt-in, not default. The Forge installer asks; you choose. We recommend it for any portable device.
- The format is LUKS2 with a passphrase, AES-256 in XTS mode, and the
argon2idkey-derivation function. - TPM2-sealed unlock and FIDO2-token unlock are wired as EXPERIMENTAL v1.0 sub-options. They compose with the passphrase rather than replacing it — the passphrase slot is always retained as the unconditional fallback.
- Your passphrase is never written to disk outside the LUKS header slot, never logged, never sent anywhere. There is no recovery-key escrow and no master key. If you forget it, your data is gone by design.
- The boot chain is fully signed. Secure Boot enforcement is optional and off by default on the current fleet; the signatures are present and ready to enforce where you enable it.
- Every kernel you install after the original ISO is rebuilt into a Unified Kernel Image (UKI) and signed with your machine’s own Machine Owner Key (MOK). The release signing key never touches your machine.
Full-disk encryption with LUKS2
InterGenOS uses LUKS2 (Linux Unified Key Setup, version 2) as the on-disk encryption format. The tooling is cryptsetup, the cipher default is AES-256-XTS, and the key-derivation function is argon2id — memory-hard and resistant to GPU/ASIC brute-force.
A LUKS2 volume has three parts:
- A header at the start of the encrypted partition, holding the encryption metadata: the cipher choice, the master-key wrapping, and up to eight key slots.
- Key slots, each independently holding a wrapping of the master key by one passphrase (or by a TPM-sealed key, or by a FIDO2-derived key). Several unlock methods can be active at once; deleting one slot does not affect the others.
- The encrypted payload — your root filesystem.
The master key never leaves the LUKS header. Your passphrase unwraps a key slot, which yields the master key, which decrypts the payload. The passphrase itself is held only in volatile memory during the unlock and the buffer is zeroed when it finishes. There is no on-disk copy of your passphrase.
The Forge install flow
When you run Forge (TUI or GUI), the partitioning stage offers an Encrypt the root filesystem with LUKS2 checkbox. If you tick it:
- Forge prompts for a passphrase with a confirmation field. Both frontends enforce a non-empty value and a confirm-field match. Guidance is a soft warning, not a block: 8 characters is the floor below which the warning fires, and 12 characters with at least two character classes is the recommended baseline. You can accept a passphrase that fires the warning after confirming.
- Forge formats the target partition with LUKS2 using
cryptsetup luksFormat. Forge forces the argon2id KDF parameters (1 GB memory cost, 4 iterations, 4 threads) per RFC 9106’s recommendations for memory-hard KDFs, rather than relying on the hostcryptsetupdefaults. The cipher itself — AES-256 in XTS mode — is cryptsetup’s own default, which Forge leaves in place rather than overriding. They are calibrated to defeat GPU-accelerated brute-force without risking out-of-memory on 4 GB systems. - Forge writes
/etc/crypttabso the boot-time initramfs knows what to unlock. The entry is namedcryptrootand references the partition byUUID=. - Forge writes
/etc/fstabwith the unlocked device-mapper node (/dev/mapper/cryptroot) as the root mount source. - The kernel post-install hook bundles the FDE initramfs into the UKI, so the unlock prompt lives inside the same signed envelope as the kernel (see Composition with Secure Boot).
The passphrase you type is held only in memory while the install runs. It is piped to cryptsetup via stdin (never on the command line, never in argv), zeroized after use, and cleared on both the success and failure path. No copy is written to disk except in the LUKS header slot itself.
EXPERIMENTAL — TPM2-sealed unlock
If you tick Unlock with TPM2 (EXPERIMENTAL), Forge seals a fresh 32-byte random key against the current measured-boot state, adds that key as an additional LUKS slot, and writes the sealed-blob triplet (primary.ctx, secret.pub, secret.priv) to the ESP under /intergen/tpm2/. The seal is bound to a PCR0 + PCR7 policy: PCR0 tracks the firmware (BIOS/UEFI code), and PCR7 tracks Secure Boot policy state (the db/dbx/KEK/MOK enrollment status). On normal boots the system unlocks automatically without prompting.
The TPM2 sub-checkbox is greyed out with a tooltip if your hardware does not expose a TPM (/dev/tpmrm0 absent) or if the live ISO is missing the static TPM2 tools.
This is flagged EXPERIMENTAL because the failure modes are subtle. A firmware update changes PCR0; a kernel update that touches your shim/MOK state can change PCR7; a Secure Boot reconfiguration changes PCR7. Any of these invalidates the seal, and the boot falls through to the next configured method and ultimately to the passphrase prompt. The sealed blob on the ESP is not a secret — without the specific TPM that performed the seal, and the same PCR state, it is useless and cannot be unsealed on any other machine. The passphrase slot remains untouched.
EXPERIMENTAL — FIDO2-token unlock
If you tick Unlock with FIDO2 token (EXPERIMENTAL), Forge enrolls a credential on a FIDO2 security token (YubiKey, Solo, Nitrokey, etc.) plugged in during the install. Enrollment runs in two interactive steps:
- Generate credential:
fido2-cred -Mcreates a new credential on the token. You will be prompted to touch the token when it blinks. - Derive unlock key: a fresh 32-byte random nonce is generated and
fido2-assert -G --hmac-secretis invoked with that nonce as salt. The token returns an HMAC output bound to the credential and the nonce, which is added as an additional LUKS slot. You will be prompted to touch the token a second time.
Forge writes the cred_id and stored_nonce to the ESP under /intergen/fido2/. Neither file is a secret: without the physical token, the credential ID and salt are useless. The relying-party ID is intergenos. At boot, the same fido2-assert call against the same nonce yields the same HMAC bytes, which unlock the slot.
This is flagged EXPERIMENTAL for the same family of reasons as the TPM2 path: a lost token, a token-firmware update that rotates credential storage, or a token swap all invalidate the slot. The passphrase slot stays in the LUKS header for fallback.
The boot-time unlock chain
When an encrypted InterGenOS system boots, the firmware verifies the UKI signature, the kernel hands off to the FDE init, and the unlock chain runs in order:
- TPM2 unlock (if enrolled and
/dev/tpmrm0is present):tpm2_load+tpm2_unsealagainst the PCR0+PCR7 policy, piped tocryptsetup. On any failure, fall through. - FIDO2 unlock (if enrolled and the tools are available): wait up to 30 seconds for the token to enumerate, run
fido2-assert -G --hmac-secretagainst the stored nonce, pipe the HMAC tocryptsetup. On any failure, fall through. - Passphrase prompt — always the final fallback. Three attempts, then a recovery shell.
If neither TPM2 nor FIDO2 was enrolled, the chain skips straight to the passphrase prompt and the path is identical to a passphrase-only install. The prompt is plain text:
InterGenOS — encrypted root unlock
Enter passphrase for /dev/disk/by-uuid/<uuid>:
Three wrong attempts drops you into a recovery shell with cryptsetup available, where you can retry the unlock manually, inspect /etc/crypttab, or reboot.
The FDE initramfs is tiny: a static cryptsetup, a static busybox, the dm_crypt and ext4 kernel modules, and the storage drivers needed to see your disk. When TPM2 or FIDO2 unlock is enrolled it also carries the relevant static tools and kernel modules. It does no logging to disk, no telemetry, and no network — its only job is to attempt the unlock chain, mount the root filesystem, and hand off to systemd.
Debugging the unlock chain
The init script emits journal-grep-friendly prefixes when running EXPERIMENTAL methods. After boot, correlate each attempt by searching the journal:
| Prefix | What it means |
|---|---|
[fde-init][EXPERIMENTAL TPM2] | TPM2 unlock attempt — skipping (no /dev/tpmrm0, no tools, or no sealed blob), attempting unlock via sealed key (PCR0+PCR7), tpm2_load failed, a tpm2_unseal/cryptsetup PCR-drift failure, or unlock succeeded. |
[fde-init][EXPERIMENTAL FIDO2] | FIDO2 unlock attempt — skipping, attempting unlock — plug your security token + touch when it blinks, no FIDO2 token detected within 30s, a specific pipeline diagnostic, or unlock succeeded. |
[fde-init] (no suffix) | Passphrase prompt path, the recovery-shell drop, and root-mount errors. |
These messages go to the console during early boot and are captured by systemd-journald afterward, available via journalctl -b | grep fde-init.
Secure Boot
The boot path is the most privileged code on the machine: if an attacker can substitute a kernel before the OS finishes starting, every other defense is moot. InterGenOS signs the entire boot chain to close that class of attack; enabling Secure Boot (optional, and off by default on the current fleet) makes the firmware enforce those signatures.
The boot chain is:
Firmware (UEFI)
| trusts Microsoft 3rd-party CA
v
Microsoft-signed shim
| trusts the InterGenOS vendor cert (loaded as MOK)
v
InterGenOS GRUB
| enforces signature verification on UKIs
v
InterGenOS UKI (vmlinuz + initramfs + cmdline, one Authenticode binary)
|
v
InterGenOS userspace
A Unified Kernel Image (UKI) is a single signed file that bundles the kernel, the initramfs, and the kernel command-line. Signing the UKI envelope signs all three at once; nothing inside can be swapped without breaking the signature.
The live ISO and install media use UKIs signed by the release key on an offline signing workstation. That release key never leaves our hardware and physically does not exist on your machine. Once you install to disk, every kernel you install or upgrade is rebuilt into a UKI on your machine and signed with your machine’s MOK.
InterGenOS treats unsigned modules the same way it treats unsigned kernels: a signed kernel that loads unsigned out-of-tree modules at runtime is no better than an unsigned kernel. The trade-off for this strictness is a one-time MOK enrollment step for out-of-tree modules; the benefit, once Secure Boot is enabled, is that nothing unsigned runs during boot.
The Machine Owner Key (MOK)
A Machine Owner Key is a per-machine signing key, generated on your own machine, that the firmware trusts because you enrolled it via MokManager at first boot. It exists for two reasons:
- Your machine signs the kernels you install. When you install a new kernel with
pkm install linux-kernel-X.Y.Z, InterGenOS rebuilds the UKI and signs it with your MOK. The release key never sees the kernels you install. - You can trust your own third-party drivers. Out-of-tree modules (for example, proprietary GPU drivers via DKMS) can be signed by your MOK and load on a Secure Boot system without disabling enforcement.
The MOK is yours. It lives at /var/lib/intergen/mok/ on the installed system. If you reinstall, Forge generates a fresh MOK; if you migrate to a new machine, you generate a new MOK there.
What Forge does at install
The bootloader stage runs without asking further questions:
- Generates a per-machine MOK keypair (RSA-2048) as
mok.key(private key),mok.crt(PEM X.509 cert, used bysbsign), andmok.der(DER X.509 cert, the binary form MokManager wants for enrollment). - Generates a random 12-character enrollment password and stores it for the first-boot step.
- Stages the MOK for enrollment so MokManager picks it up on next reboot.
- Installs
ukifyandsbsigntoolso the kernel post-install hook can build and sign UKIs. - Installs an initial UKI built from the installed kernel and signed with the fresh MOK.
- Configures a recovery boot entry that loads the bare vmlinuz as a fallback if a UKI ever fails to sign or boot.
Forge shows the enrollment password on the install-complete screen and writes it to /var/log/intergen-install.log. Write it down before you reboot. You need it once, during MokManager enrollment.
First-boot MOK enrollment
On the first boot after install, the firmware notices a pending enrollment request and runs MokManager — a small blue-text-on-black utility — before continuing the boot. It walks you through three screens:
- “Perform MOK management” — press any key to start.
- “Enroll MOK” — review the certificate (subject
CN=InterGenOS Machine Owner Key) and confirm. - “Enter password” — type the enrollment password Forge gave you. It is single-use.
After enrollment, MokManager exits and the system boots normally. From that point, the firmware trusts your MOK and UKIs signed with it load without prompts.
If you skip enrollment, the system still boots using the release-signed UKI that shipped with the installer image — but the next kernel install or upgrade produces a MOK-signed UKI the firmware will not trust, and you will fall through to the recovery boot entry until you enroll.
Kernel install and upgrade
When you install or upgrade a kernel via pkm, the linux-kernel package’s post_install hook runs on your machine with no key material from the release infrastructure:
- Reads the kernel, the standard initramfs (and the FDE initramfs if your system is LUKS-encrypted), and the canonical command-line.
- Runs
ukify buildto bundle them into a single UKI. - Runs
sbsign --key /var/lib/intergen/mok/mok.key --cert /var/lib/intergen/mok/mok.crtto sign it. (sbsignreads PEM certs; the.derform is for MokManager enrollment only.) - Writes the signed UKI to the ESP under
/boot/efi/EFI/Linux/, namedintergenos-<kernel-version>.efi. - Updates the GRUB menu so the new kernel is the default boot entry.
If the UKI build or signing step fails (corrupt key file, full ESP, missing tooling), the hook falls back to the GRUB-loads-vmlinuz path: the kernel and initramfs are written out separately and GRUB loads them directly with the same signature-verification semantics, since GRUB is itself signed and enforces check_signatures=enforce. The kernel install is never rolled back on UKI failure, so you never end up with a half-installed kernel.
ESP sizing
Every kernel you install becomes a UKI in /boot/efi, so the ESP needs headroom for several generations. A typical UKI is 80-150 MB depending on the initramfs payload. Forge creates a fixed 1 GiB ESP during partitioning, leaving room for several kernel generations. If the ESP fills up, kernel install fails with a clear message; clean up with pkm remove linux-kernel-<old-version>.
Composition with Secure Boot
The encrypted-root and signed-boot stories are designed to compose. They do not interact at runtime except through the FDE initramfs being part of the signed UKI.
On a non-encrypted install, the UKI’s bundled initramfs is minimal — typically only CPU microcode — because storage and filesystem drivers are built into the kernel. On an encrypted install, the UKI’s bundled initramfs is the FDE initramfs: the same init that prompts you for the passphrase is part of the same signed envelope as the kernel.
The practical consequences:
- An attacker cannot substitute a fake unlock prompt that captures your passphrase, because the prompt code is inside the signed UKI. Tamper with it and Secure Boot refuses to load it.
- A kernel upgrade rebuilds the UKI with the new kernel and the same FDE initramfs, signed with your MOK. The unlock experience is identical across kernel upgrades.
- If TPM2-sealed unlock is enabled, the same UKI envelope holds the bits that talk to your TPM. The unlock path stays inside the signed envelope; the TPM is not a way to skip Secure Boot verification.
What is and is not protected
Encrypted at rest: the entire root filesystem, including /home, /var, /etc, /root, swap if placed on the encrypted volume, and anything written to disk once the system is running and unlocked.
Not encrypted:
- The ESP (the small
/boot/efipartition). The firmware reads it before any OS runs, so it cannot be encrypted. Its integrity is protected by Secure Boot signature verification on the UKI, not by encryption. - The LUKS header, which is on disk and visible. It reveals that the partition is LUKS-encrypted and which cipher is in use, but nothing about the payload.
- A running system. Once unlocked, the master key lives in kernel memory and the filesystem is readable to any process with the right permissions. Encryption-at-rest does not replace process isolation, user permissions, or AppArmor confinement.
If your threat model includes someone with physical access while the machine is running, full-disk encryption is not the control you want — use screen lock or a powered-off machine.
Recovery
“I forgot my passphrase”
Your data is gone. There is no master key, no recovery-key escrow, and no back door — a recovery channel we could use is a channel an attacker could use. Boot a live ISO and reinstall. Back up early and often.
Add or remove a passphrase
LUKS2 supports up to eight key slots. From a running system, as root:
cryptsetup luksAddKey /dev/disk/by-uuid/<uuid>
cryptsetup luksRemoveKey /dev/disk/by-uuid/<uuid>
luksAddKey prompts for an existing passphrase (to unwrap the master key) and then the new one. luksRemoveKey prompts for the passphrase belonging to the slot you want to remove; the other slots are untouched.
Back up the LUKS header
If the header is corrupted, the payload becomes unrecoverable even with the correct passphrase, because the encryption metadata lives in the header. Back it up to a separate medium:
cryptsetup luksHeaderBackup /dev/disk/by-uuid/<uuid> \
--header-backup-file /path/to/external/header.bin
Store it offline. Anyone with the backup file and your passphrase can decrypt your disk; treat it accordingly. Restore with cryptsetup luksHeaderRestore and the same --header-backup-file argument.
“I need to regenerate the MOK”
The MOK material lives under /var/lib/intergen/mok/. On a default install Secure Boot is off and there is no enrollment password to lose. If you run with Secure Boot enabled and need a fresh MOK, reinstalling with Forge regenerates one; the next kernel install or upgrade rebuilds the UKIs with it, and the bare-vmlinuz fallback in GRUB keeps the system bootable in the meantime. (There is no separate recovery wrapper command — UKI signing is handled entirely by the kernel package’s post-install hook.)
“Secure Boot is refusing my new kernel”
This usually means the MOK was not enrolled (or was un-enrolled) but the post-install hook signed a UKI with it. Boot the recovery entry, then either re-enroll the MOK or regenerate it via the password-reset path above.
“I want to run an unsigned kernel”
Don’t. Every kernel that boots is signed — this is non-negotiable. Build your kernel, sign it with your MOK using sbsign, and install it through the same pkm flow. To test bare unsigned kernels, use a VM with Secure Boot off, not a production install.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Passphrase prompt rejects every attempt | Wrong passphrase, or keyboard layout differs at boot | The FDE initramfs uses US-QWERTY by default; type the QWERTY equivalents of layout-sensitive characters. |
| Boot drops to the FDE recovery shell with “no LUKS volume specified” | /etc/crypttab was not written, or the encryption stage did not complete | Inspect /etc/crypttab from the recovery shell; if empty, boot a live ISO and reinstall. |
| Boot drops to the recovery shell with “LUKS volume not found after 30s” | Disk did not enumerate in time (failing drive, USB storage, slow RAID init) | Run ls /dev/disk/by-uuid/; if the volume appears, retry cryptsetup open manually. |
| TPM2-sealed unlock falls through to passphrase | PCR0 or PCR7 changed (firmware update, Secure Boot reconfiguration, shim/MOK update) | Enter the passphrase to boot. Re-enrolling TPM2 against the new PCR state restores automatic unlock. Check the [EXPERIMENTAL TPM2] journal lines for the specific outcome. |
| FIDO2 unlock does not detect the token | Token plugged in too late, or dead battery | Plug the token in before boot; the initramfs waits up to 30 seconds. Check the [EXPERIMENTAL FIDO2] journal lines. |
| Boot stops at MokManager every time | MOK enrollment never completed | Complete enrollment per First-boot MOK enrollment above. |
| New kernel installs but won’t boot, falls through to recovery | UKI signed with a MOK the firmware doesn’t trust | Re-enroll the MOK, or re-run the kernel post-install hook after enrollment. |
| GRUB shows only the recovery entry | UKI signing has been failing silently | Inspect /var/log/intergen-kernel-postinstall.log; ESP-full and a missing MOK key file are the common causes. |
ukify is missing on the installed system | Forge skipped the UKI tooling install | pkm install ukify sbsigntool and re-run the kernel post-install hook. |
| Secure Boot toggle is greyed out in firmware | Some OEM firmware makes Secure Boot read-only outside Setup Mode | See your vendor docs for entering Setup Mode. The standard MOK enrollment path is sufficient for normal operation. |
Further reading
- Forge installer guide — the install walkthrough that references the encryption opt-in and MOK enrollment in context.
- FAQ — common security questions.