LUKS
What It Is
LUKS (Linux Unified Key Setup) is the standard for disk encryption on Linux. It provides a consistent on-disk format for encrypted partitions, supporting multiple keyslots, key management, and metadata storage. LUKS sits on top of dm-crypt (the kernel's encryption layer) and adds the user-facing key management.
If dm-crypt is the engine that encrypts and decrypts data, LUKS is the ignition system that manages the keys to start it.
Why It Matters
Without LUKS, you'd need to manage encryption keys manually: decide on a
cipher, generate a key, figure out where to store the key metadata, handle
key rotation, support multiple unlock methods. LUKS standardizes all of this
into a well-tested format with tooling (cryptsetup).
LUKS also enables the keyslot model: one encrypted partition can be unlocked by multiple different credentials (password, key file, YubiKey, TPM), each stored in its own keyslot. All keyslots protect the same master key -- adding or removing a keyslot never re-encrypts the data.
How It Works
LUKS2 On-Disk Format
A LUKS2 partition starts with a header (typically 16 MB) followed by the encrypted data:
+------------------+------------------------------------------+
| LUKS2 Header | Encrypted Data (AES-256-XTS) |
| | |
| - JSON metadata | dm-crypt handles read/write here |
| - Keyslot area | |
| - Salt, cipher | |
+------------------+------------------------------------------+
JSON metadata: LUKS2 replaced LUKS1's binary header with JSON, making it more flexible and extensible. The metadata describes the cipher, key size, PBKDF parameters, and keyslot layout.
Keyslot area: Up to 32 keyslots (LUKS2; LUKS1 had 8). Each keyslot holds an independently encrypted copy of the master key. The master key is what actually encrypts the data. Keyslots are just different ways to recover it.
Master Key and Keyslots
The critical design: the data is encrypted with a randomly generated master key. This master key is never stored in plaintext. Instead, each keyslot encrypts a copy of the master key with a different credential:
Keyslot 0: master_key encrypted with PBKDF2(password)
Keyslot 1: master_key encrypted with key_file_contents
Keyslot 2: master_key encrypted with yubikey_hmac_response
To unlock the partition, you provide any one credential. cryptsetup tries
it against each keyslot until one succeeds, then uses the recovered master key
to set up dm-crypt.
This means:
- Changing a password doesn't re-encrypt the disk (just replaces a keyslot)
- Adding a recovery key doesn't affect existing keyslots
- Removing a compromised credential only removes its keyslot
Common Operations
# Create a LUKS2 partition
cryptsetup luksFormat /dev/vdb
# Open (unlock) the partition
cryptsetup luksOpen /dev/vdb persist
# The decrypted device appears as /dev/mapper/persist
mkfs.ext4 /dev/mapper/persist
mount /dev/mapper/persist /persist
# Add a keyslot (e.g., a key file for automated unlock)
cryptsetup luksAddKey /dev/vdb /path/to/keyfile
# Remove a keyslot
cryptsetup luksKillSlot /dev/vdb 1
# Close (lock) the partition
cryptsetup luksClose persist
LUKS1 vs LUKS2
| Feature | LUKS1 | LUKS2 |
|---|---|---|
| Header format | Binary | JSON |
| Max keyslots | 8 | 32 |
| PBKDF | PBKDF2 only | Argon2id (default), PBKDF2 |
| Integrity | None | Optional dm-integrity |
| Online reencryption | No | Yes |
| Token support | No | Yes (systemd-cryptenroll, FIDO2, TPM2) |
LUKS2 is the default since cryptsetup 2.1 (2019). FortrOS uses LUKS2.
How FortrOS Uses It
Encrypted /persist: Each node's /persist partition is LUKS2-encrypted. The master key is protected by:
- Keyslot 0: Org-derived key (HKDF from preboot_secret + ca_pubkey + generation_id). Used on every normal boot.
- Keyslots 1-N: Admin YubiKey keyslots for disaster recovery.
Rolling upgrades: When upgrading to a new generation, the LUKS key changes
(generation_id changes). prepare-upgrade adds a new keyslot for the new
generation's key. After successful boot, cleanup-upgrade removes the old
keyslot. See 10 Sustaining the Org.
Revocation: Deleting a generation_secret from the generation authority makes it impossible to derive the LUKS key for that generation. Machines with that generation can't unlock /persist. This is cryptographic enforcement of "cold boot prevents stolen devices."
First boot: cryptsetup luksFormat creates /persist with the initial
keyslot. Subsequent boots use cryptsetup luksOpen.
Failed unlock: If luksOpen fails (generation revoked, /persist corrupted), the preboot reformats from scratch. Identity and cache are lost, but the machine can re-enroll.
Alternatives
dm-crypt without LUKS: Raw dm-crypt with a plain key. No keyslot management, no metadata, no standard format. Suitable only for ephemeral encrypted volumes where key management isn't needed.
eCryptfs / fscrypt: File-level encryption (individual files/directories encrypted, not the whole partition). More granular but more complex. Android uses fscrypt for per-user encryption. FortrOS encrypts the whole /persist partition -- file-level granularity isn't needed.
BitLocker (Windows): Proprietary, Windows-only. Similar keyslot concept (TPM, PIN, recovery key) but closed-source format.
ZFS native encryption: Built into the ZFS filesystem. Encrypts datasets (logical filesystems). FortrOS doesn't use ZFS.
Links
- cryptsetup -- The LUKS reference implementation
- LUKS2 On-Disk Format Specification
- ArchWiki: dm-crypt/Encrypting an entire system
- systemd-cryptenroll -- Enroll FIDO2, TPM2, recovery keys into LUKS2