TL;DR

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# Header backup (the volume does not need to be open)
cryptsetup luksHeaderBackup /dev/sdb --header-backup-file /root/sdb-luks-header.img

# Slots in use
cryptsetup luksDump /dev/sdb

# Keys
cryptsetup luksAddKey /dev/sdb                      # another passphrase (asks for an existing one)
cryptsetup luksAddKey /dev/sdb /root/keyfile.bin    # a keyfile in a new slot
cryptsetup luksChangeKey /dev/sdb                   # swap one passphrase for another, same slot
cryptsetup luksRemoveKey /dev/sdb                   # remove the passphrase you type
cryptsetup luksKillSlot /dev/sdb 2                  # remove slot 2 without knowing its passphrase (asks for another)

# Restore the header
cryptsetup luksHeaderRestore /dev/sdb --header-backup-file /root/sdb-luks-header.img

After any key change, back up the header again and destroy the previous backup. Restoring an old backup reactivates every passphrase it held at the time, including the ones you removed.

Why the header is everything

LUKS does not encrypt your data with your passphrase: it encrypts it with a random master key, and that master key sits encrypted inside the header, one copy per slot, each protected by a passphrase or keyfile. The header takes the first 16 MiB of the device on LUKS2 (2 MiB on LUKS1).

If those megabytes get damaged (a wrong dd, a mkfs on the raw disk, dead sectors right there), the master key is gone and the data becomes unrecoverable noise, even if you know the passphrase. A header backup, stored somewhere else, is the only insurance. The file is the size of the header and contains no data, only the encrypted master key.

Backing up and restoring

1
2
cryptsetup luksHeaderBackup /dev/sdb --header-backup-file /root/sdb-luks-header.img
cryptsetup luksDump /root/sdb-luks-header.img         # the backup can be inspected like a device

Keep it off the machine, encrypted (a gpg -c is enough), with a name that says which disk it belongs to. Restoring:

1
cryptsetup luksHeaderRestore /dev/sdb --header-backup-file /root/sdb-luks-header.img

It only repairs the header. If the accident went past the first 16 MiB, whatever was there stays lost.

Slots and keys

LUKS2 has 32 slots (0–31); LUKS1, 8. All of them unlock the same master key, so it does not matter which one you come in through:

1
2
cryptsetup luksDump /dev/sdb | sed -n '/^Keyslots:/,/^Tokens:/p'
cryptsetup open --test-passphrase -v /dev/sdb         # "Key slot 0 unlocked": which slot your passphrase uses

Keyfile to open without typing (typical for a data disk that comes up with the system):

1
2
3
dd if=/dev/urandom bs=32 count=1 of=/root/keyfile.bin
chmod 0400 /root/keyfile.bin
cryptsetup luksAddKey /dev/sdb /root/keyfile.bin

And in /etc/crypttab:

1
data  UUID=<luks-uuid>  /root/keyfile.bin  luks

Test without rebooting: systemctl daemon-reload && systemctl start systemd-cryptsetup@data.service. A keyfile under /root only makes sense if / is encrypted too or the disk belongs to a machine you trust physically.

Removing keys:

  • luksRemoveKey asks for the passphrase you want gone.
  • luksKillSlot <n> removes a specific slot and asks for another valid passphrase; useful when nobody remembers the slot’s own.
  • luksChangeKey swaps one passphrase for another in the same slot.

Traps

  • The header backup keeps the old keys. You removed a former colleague’s passphrase and the earlier backup is still on a USB stick: that stick opens the disk. Re-back up after every change and destroy the previous ones (shred -u).
  • luksErase is not secure erasure if a header backup exists. It destroys every slot on the disk, but a luksHeaderRestore brings them back. For a final wipe, destroy the backups too.
  • Do not kill the last slot. cryptsetup warns the device will become unusable; if you accept, that is it.
  • A backup on the same disk is not a backup. Nor on the same server if losing the server is what you fear.
  • Detached header (--header /path/header.img when formatting and opening) moves the header off the disk entirely; then the “backup” is the header itself and losing it equals losing the data.
  • LUKS1 vs LUKS2: the commands are the same; cryptsetup convert --type luks2 migrates a LUKS1 (with a backup first, of course).

Reference: man 8 cryptsetup, sections luksHeaderBackup, luksHeaderRestore, and luksKillSlot.