How to use LUKS with a detached header

Linux Unified Key Setup (LUKS) is the de-facto standard block device encryption format used on Linux-based systems. We already discussed some of the features provided by it in a previous tutorial about using a file as a LUKS device key. When using LUKS, encryption metadata is stored on the header which is created at the beginning of the encrypted device (a copy of the header is created at end of the device for redundancy, when using LUKS2).If desired, it is possible to specify that the header should be detached from the device: in this tutorial we see how.

In this tutorial you will learn:

  • What is the LUKS header and what information are stored in it
  • How to create and restore a LUKS header backup
  • How to use LUKS with a detached header
How to use LUKS with a detached header
How to use LUKS with a detached header

Software requirements and conventions used

Software Requirements and Linux Command Line Conventions
Category Requirements, Conventions or Software Version Used
System Distribution-independent
Software cryptsetup
Other Root privileges
Conventions # – requires given linux-commands to be executed with root privileges either directly as a root user or by use of sudo command
$ – requires given linux-commands to be executed as a regular non-privileged user

What is the LUKS header?

As we already said, when we setup a block device to be encrypted using the LUKS format, an header containing metadata is stored, by default, at the beginning of the encrypted partition or raw block device. What information are stored in the LUKS header? Inspecting its content is very simple. Supposing our encrypted block device is /dev/sdb, to get information about the LUKS header, we would run the following command:

$ sudo cryptsetup luksDump /dev/sdb

Here is an example of the output we would obtain:

LUKS header information for /dev/sdb

Version:        1
Cipher name:    aes
Cipher mode:    xts-plain64
Hash spec:      sha512
Payload offset: 4096
MK bits:        512
MK digest:      a5 2b 28 28 65 1b 72 47 b6 5e 13 03 53 d1 21 58 16 16 01 0e
MK salt:        2d 69 3a 58 a0 05 43 d4 c6 b3 12 fb 93 21 a1 0a
                3d 35 78 59 a6 48 48 e3 8c 8c 4a 27 93 ec a1 d6
MK iterations:  63750
UUID:           ecbc1d41-d1b6-4fc1-b2f0-7688c93cdc45

Key Slot 0: ENABLED
        Iterations:             2582695
        Salt:                   ab f9 18 8b 35 f9 f0 d6 fe a2 82 0a 08 1d 18 d9
                                b4 de 02 d8 71 8a a6 00 54 04 65 c5 75 66 91 8b
        Key material offset:    8
        AF stripes:             4000
Key Slot 1: DISABLED
Key Slot 2: DISABLED
Key Slot 3: DISABLED
Key Slot 4: DISABLED
Key Slot 5: DISABLED
Key Slot 6: DISABLED
Key Slot 7: DISABLED



By taking a look at the output of the command, we can see some important information are displayed, like the LUKS version in use (1 in this case, although the most recent available version is 2), the cipher name and mode, the hash algorithm used for the password salt, the master key bits, digest, salt and hash iterations, and the device UUID. We can also see that only the first of the seven password slots available is used.

The LUKS header is a crucial part of the setup: if for some reason it is damaged, all the data on the disk its irremediably lost. That is why it is always a good idea to create a backup of it. Let’s see how.

Creating and restoring a LUKS header backup

Creating a backup of a LUKS header is a quite simple task. We do it by using the cryptsetup utility, with the luksHeaderBackup command. To create a backup of LUKS header of the /dev/sdb device we would run:

$ sudo cryptsetup luksHeaderBackup /dev/sdb --header-backup-file sdbheaderbackup.img

Let’s take a look at what we did above. We invoked cryptsetup with root privileges we obtained by using sudo. As we said, to create the backup, we used the luksHeaderBackup command and passed the path of the LUKS formatted device as argument to it. We than used the --header-backup-file option to specify where the header should be stored: in this case on the sdbheaderbackup.img file.

Restoring the created backup to the block device is just as simple: the only thing we need to change is the command. Instead of luksHeaderBackup we use luksHeaderRestore. Here is what we would run to restore the header backup to the block device:

$ sudo cryptsetup luksHeaderRestore /dev/sdb --header-backup-file sdbheaderbackup.img

One possible security issue that should be taken into account when creating a backup of the LUKS header is that by restoring it, it would be possible to unlock the block device by using the passwords originally existing in its slots, which we could possibly decided to change or remove from the disk after the backup was done.

Using a detached LUKS header

As we saw, the LUKS header is created at the beginning of the encrypted block device by default. When formatting the device with LUKS, however, we can choose to create a detached header, stored separately. Why we would want do it? One of the possible reasons is to achieve plausible deniability: since there is no proof that a block device is encrypted (no metadata is stored on it), one can plausible state it is not. Even if the disk would appear to be filled with random data, suggesting encryption is used, there would be no way to prove it is.

To create a detached header when formatting a device with LUKS, all we have to do is to use the --header option, and pass the path of the file or device where the header should be stored. Here is an example:

$ sudo cryptsetup luksFormat /dev/sdb --header luksheader.img



As you can imagine, the --header option would be also used each time we try to unlock the device, or when we need to perform other operations which modifies it, such as adding, removing or changing a password, or when using luksDump to read its content. To unlock a LUKS device with a detached header, for example, we would run:

$ sudo cryptsetup luksOpen /dev/sdb sdb-crypt --header=luksheader.img

Full disk encryption with detached LUKS header

A detached LUKS header setup is easy to obtain if we are encrypting raw block devices or partitions which are not an essential part of the system; but how could we achieve a full LVM on LUKS full disk encryption setup with a LUKS detached header?

In such a setup the only non-encrypted partition is the one mounted at /boot partition, which contains the grub files, the Linux kernel images, and the related initramfs archives. Such partition, for added security, is usually created on a separated usb device. The other parts of the system are created inside a single LUKS encrypted device as LVM logical volumes: this is done to have multiple partitions without having to encrypt them separately.

If we want to use a detached header for the LUKS device used in such a setup, we need to modify how the device is handled in the system crypttab. Suppose we have the following entry for it:

sdb_crypt /dev/sdb none luks



As we know, in the crypttab file the first column contains the device mapper name, the second the path of the encrypted device, the third the path of the eventual file used as the device key (none in this case), and the forth, the comma-separated list of options to use for the device. In this case only the luks option is used, to explicitly specify that LUKS mode should be used (vs plain dm-crypt).

What we need to do, is to modify the line and add the header option, to specify where the luks header is located. The header could be stored:

  1. On a separated raw device
  2. On a separated filesystem

In the first scenario, for example, the header of the /dev/sdb LUKS device is stored on the raw /dev/sdc (--header=/dev/sdc) block device. In such a case, all we have to do is to pass the path of the row device as the value of the header option. The line above would become:

sdb_crypt /dev/sdb none luks,header=/dev/sdc

The second scenario exists when we decide to store a detached header as a file on a filesystem. To achieve plausible deniability, for example, we could use a partition created on an external and removable usb device as /boot, and store the header of the LUKS-encrypted main block device on it. A specific notation should be used to specify such a location. Supposing the partition to be mounted ad /boot is /dev/sdc1, we would write:

sdb_crypt /dev/sdb none luks,header=/path/to/header.img:/dev/sdc1

The notation used above consists into specifying the absolute path of the header file on the filesystem separated by a colon : from the filesystem identifier, for example its UUID:

sdb_crypt /dev/sdb none luks,header=/path/to/header.img:UUID=<filesystem-uuid>

Since the modified crypttab file (/etc/crypttab) is part of the root filesystem, which is encrypted, it must be copied into the initramfs to be used on boot. How to perform such operation depends on what distribution we are using. On Fedora, for example, to regenerate the initramfs, we would use dracut:

$ sudo dracut --regenerate-all --force

Conclusions

In this tutorial we learned what is the role of the LUKS header, and how to use a detached header when encrypting a block device with LUKS. We also saw how to create and restore a backup of the header, and how to use a detached header in the context of a full disk encryption setup.



Comments and Discussions
Linux Forum