// guide

Encryption & LUKS

Password-protected boot files on the ESP, and one password for the whole boot.

The two layers

VISORENC protects the boot files sitting on the (always unencrypted) ESP: kernels, UKIs, and initrds are stored as encrypted, authenticated containers and decrypted in memory after you type a password in the menu. LUKS protects your root filesystem; Visor never parses LUKS itself — it hands your initramfs what it needs to unlock the disk. The two compose, and one password can drive both.

One-command setup

sudo visor encrypt /boot/vmlinuz-linux /boot/initramfs-linux.img --title "Encrypted Arch"

This single command:

  1. prompts for one password and encrypts both files with it,
  2. copies the containers to \EFI\visor\,
  3. generates a finished boot entry using your current kernel cmdline (from /proc/cmdline),
  4. detects a LUKS root (cryptdevice= / rd.luks.* on the cmdline) and adds luks = 1 with the right luks_preset (mkinitcpio or dracut, detected from your installed initramfs tooling),
  5. offers to append the entry to boot.conf for you, and
  6. prints the exact cryptsetup luksAddKey command to enroll that same password on your LUKS device.

Flags: --title TEXT (menu name), --no-luks, --no-config (print the entry only), --out PATH / --esp PATH, --name FILE, --iterations N, --initrd (the single input is an initrd).

What boot looks like

power on ─▶ Visor menu ─▶ one password prompt
             │
             ├─ decrypts kernel + initrd containers in RAM (authenticated first)
             ├─ injects the password as a keyfile into the decrypted initrd (cpio append)
             ├─ adds cryptkey=rootfs:… / rd.luks.key=… to the cmdline
             ▼
           kernel boots ─▶ initramfs unlocks LUKS root from the keyfile ─▶ desktop

One password, one prompt. The prerequisite: that password must also be a valid LUKS passphrase — enroll it once with sudo cryptsetup luksAddKey <device> (the keyfile Visor injects contains the exact password bytes, no trailing newline, so a normal passphrase slot matches).

At the prompt, F2 toggles showing what you typed — useful to confirm your keyboard layout before submitting. If luks_confirm=1, the password is asked for twice and a mismatch reprompts instead of booting with a typo. If luks_verbose=1, quiet and splash are stripped from the cmdline so the initramfs retry prompt stays visible when the passphrase is rejected.

Entry keys

KeyMeaning
encrypted = 1Both kernel and initrd are VISORENC containers.
kernel_encrypted = 1 / initrd_encrypted = 1Only one of the two is encrypted.
luks = 1Inject the entered password as a temporary keyfile into the in-memory initrd.
luks_presetmkinitcpio/arch → adds cryptkey=rootfs:<path> · dracut/systemd → adds rd.luks.key=<path>.
luks_key_pathKeyfile path created inside the initramfs. Default /crypto_keyfile.bin.
luks_cmdlineManual kernel options for the keyfile; overrides the preset.
luks_confirm1 = ask for the passphrase twice at the prompt; a mismatch reprompts instead of booting with a typo.
luks_verbose1 = remove quiet and splash from this entry's cmdline so the initramfs retry prompt is visible when a passphrase is rejected.

A single menu prompt covers encrypted, initrd_encrypted, and luks together — the same captured password decrypts the containers and becomes the keyfile.

Mapper-name consistency

If you are writing LUKS entries by hand, the mapper device name in your kernel cmdline must match what /etc/fstab and /etc/crypttab expect. Use rd.luks.name=<UUID>=<name> (not rd.luks.uuid= alone) so the name matches root=/dev/mapper/<name> and every fstab mount. See the full mapper-name consistency checklist in the configuration reference.

The VISORENC container format (v2)

FieldSizeNotes
Magic8VISORENC
Version42
Iterations4PBKDF2-HMAC-SHA256 work factor (default 600,000; max 5,000,000)
Plain length8Original file size
Salt16Random per file
Nonce12Random per file
HMAC tag32HMAC-SHA256 over header + ciphertext
CiphertextnChaCha20 stream

Key derivation: PBKDF2-HMAC-SHA256 → 64 bytes (32 for ChaCha20, 32 for the HMAC). The tag is verified before decryption, so a modified container is refused, not booted. Passwords are ASCII, up to 510 characters (the menu's input limit). Decrypted buffers and captured passwords are wiped from memory after use.

Threat model, honestly