Setting up an encrypted Debian system

Thanks to

Even though the Debian installer can set up encrypted partitions, it is optimised for systems with a single data partition, unless you want to enter multiple passphrases when the system boots. The installer configures a LUKS volume using cryptsetup, but it provides no mechanism for the use of key files, only interactive passphrases.

I like partitioning my disks and use different filesystems for /tmp, /home, /var, and /usr/local for a number of reasons. I don’t like entering more passphrases than necessary. If you can identify with that, the following is for you.

Several people have pointed out to me that one can simply create a single encrypted “physical volume” with the Debian installer and place “logical volumes” for the various filesystems in there. You still need a separate /boot partition, in any case. Kapil Hari Paranjape has described the approach, as well as Simon McVittie.

This method is much cleaner and to be preferred. It’s quite likely that it also improves the speed since only a single kcryptd process takes care of all of the decryption and encryption needs.

Nevertheless, the following is still useful with that approach, although it’ll be less complicated.

Installing the system

The first step to setting up an encrypted Debian system is to perform a normal Debian system installation. When you are asked to partition your harddrive and create filesystems, set up all partitions as encrypted volumes (I suggest to go with the installer defaults and use dm-crypt and AES with the default settings, simply because I have no reason to doubt the installer dveeloper team’s choices). Make sure to erase the disks in the process — the installer has an option for that.

Set up the swap partition as an encrypted volume too, but don’t worry too much about the settings at this point; we will recreate the swap partition later.

Unless you want to boot off an external medium, such as a USB stick, you will need to create an unencrypted partition for /boot. I will return to this topic, which has security implications, further down.

The installer will ask you for passphrases for each of the volumes you create. I suggest you pick a secure passphrase for the root volume (/), but simple passphrases for all the other ones (such as “a”), since we will reconfigure them to use key files instead.

Using key files

A key file is like a passphrase stored in a file on disk; as opposed to “what you know”, it’s a “what you have” security asset. Thus, you need to store the file somewhere. When I boot up my system, I unlock the root partition with a passphrase entered interactively, which makes the root filesystem available. I store key files for all other volumes in /etc/keys. Obviously, I need to tell cryptsetup to use those.

The first step is to create a key file for each partition and to add it as a decryption key to the LUKS volume. You can do all of the following without unmounting the filesystems. See the following example for hda6, which will prompt for the simple passphrase we entered above to unlock the key ring when adding the key file:

umask 077
mkdir /etc/keys
dd if=/dev/urandom of=/etc/keys/hda6.luks bs=4k count=1
cryptsetup luksAddKey /dev/hda6 /etc/keys/hda6.luks
cryptsetup luksKillSlot /dev/hda6 0 --key-file /etc/keys/hda6.luks

The last command wipes the simple passphrase from the key ring and thus makes it unusable.

Now we need to tell cryptsetup to use the key file by editing /etc/crypttab and ensuring a line such as the following exists:

hda6_crypt /dev/hda6 /etc/keys/hda6.luks luks

This tells cryptsetup to create the cryptographic volume hda6_crypt from the base device /dev/hda6, using the key file we created above, and letting it know that it’s dealing with a LUKS volume.

Repeat this for every partition except your root and swap partitions.

Encrypting the swap partition

If you are using an encrypted Debian system, you likely have some security requirements to meet. If that’s the case, you must also use an encrypted swap partition.

The swap partition can be encrypted in two ways:

  • it can be recreated on every boot, using a random passphrase, or
  • it can be created like the other encrypted volumes with a persistent passphrase

If you want to use suspend-to-disk, you cannot use the first approach as it would overwrite your memory footprint stored in the swap partition. Furthermore, you cannot use a key file like the other partitions, since the root filesystem is not (and must not) be mounted by the time the resume process starts and needs to read the decrypted swap partition.

The way I solved this is by telling cryptsetup to compute the passphrase of the swap partition from the decryption key of the volume holding the root filesystem; the cryptsetup package implements this with /lib/cryptsetup/scripts/decrypt_derived. Thus, to set up the swap partition, I do the following, assuming hda2 is the partition holding the encrypted swap and the root filesystem is in hda5_crypt:

swapoff /dev/mapper/hda2_crypt
cryptsetup luksClose hda2_crypt
dd if=/dev/urandom of=/dev/hda2
/lib/cryptsetup/scripts/decrypt_derived hda5_crypt \
  | cryptsetup luksFormat /dev/hda2 --key-file -
/lib/cryptsetup/scripts/decrypt_derived hda5_crypt \
  | cryptsetup luksOpen /dev/hda2 hda2_crypt --key-file -
mkswap /dev/mapper/hda2_crypt

To tell the system about this swap partition, we need to add it to /etc/crypttab and /etc/fstab; make sure, those files contain lines like the following:

  hda2_crypt /dev/hda2 hda5_crypt luks,keyscript=/lib/cryptsetup/scripts/decrypt_derived

  /dev/mapper/hda2_crypt swap swap sw 0 0

With this in place, as soon as you configure the system for suspend-to-disk, the swap partition will be automatically set up alongside the root filesystem very early during the boot sequence. To figure out which swap partition to make available at that point, cryptsetup checks the following:

  • a line like RESUME=/dev/mapper/hda2_crypt in /etc/initramfs-tools/conf.d/resume
  • a resume device setting in /etc/uswsusp.conf (see uswsusp.conf(5))
  • an entry in /etc/suspend.conf
  • a resume=/dev/mapper/hda2_crypt in the kernel command line

You can inspect /usr/share/initramfs-tools/hooks/cryptroot if you want to know more about this.

Using UUIDs

Even though the above is all you have to do, you might want to consider replacing the device paths in /etc/crypttab with persistent ones. One motivation might be the ability to boot off your drive via a USB adapter, which might cause it to appear as /dev/sda instead of /dev/hda.

udev is installed by default on Debian systems and it makes persistent links to partitions available under /dev/disk/by-uuid, using the UUID of the content structure (e.g. the LUKS header). It uses /lib/udev/vol_id to determine those link names.

If you replace the entries in /etc/crypttab, make sure to update the initramfs (update-initramfs -u -k all) and consider to use the same approach for the /boot filesystem in /etc/fstab; you’ll note that all other filesystems use persistent device paths thanks to the dm-crypt layer.

If you ever end up booting off the disk through a USB adapter, you might face the problem where the usb_storage subsystem takes too long to activate, so that the cryptsetup script does not find the devices in time. You can either solve this by adding the rootdelay=x parameter or break=mount to the kernel command line. The first will cause the scripts to wait x seconds before trying to configure and mount the root filesystem; the second would give you a shell that you can exit as soon as the kernel spouted its device initialisation messages at you.

f you got this far, you might even want to take it further and replace hda5_crypt with cr_root or the like to abstract those silly partition numbers away even further. This is easier than it sounds, but does require several steps. Do not do this if you’re not comfortable reviving your system in case it fails to come back up!

  1. replace the old names with the new names in /etc/crypttab for all volumes except the root volume. If you are using a derived passphrase for the swap partition, make sure to put the new name for the root volume into the third column of the swap partition’s configuration line.
  2. modify /etc/fstab accordingly, leave the root filesystem’s device path alone.
  3. call update-initramfs -u
  4. modify your bootloader to ask the kernel to boot off the new root volume.
  5. replace the root volume’s old name with the new one in /etc/fstab.
  6. reboot, and add break=mount to the kernel command line.
  7. at the busybox prompt, edit (vi) /conf/conf.d/cryptroot and change the first field of the root volume’s line to the new name.
  8. exit the shell and watch the boot process complete.
  9. finally, replace the root volume’s old name with the new one in /etc/crypttab.

If the system fails to boot up again, you can use the backup initial ramdisk, which update-initramfs left in /boot.

Security implications

Apart from the usual security implications related to cryptosystems, passphrases, mathematics, user stupidity, and so on, the approach I outlined will leave you with a pretty well-secured system. Obviously, you should make sure to lock your screen whenever you leave the system unattended or the entire encryption is basically useless.

There are two attack vectors on your system, both involving physical access to the machine:

Other than that, you should be careful when travelling to totalitarian countries, like the Excited States of America, China, and probably the UK. First off, encryption arouses suspicion, and second, border agents might ask you to decrypt the partitions for them to copy or scan, and refusal to do so might get your turned away at the border. When travelling to those countries, make sure to hide your data properly.

Speed implications

Obviously, having your entire system encrypted (including swap) will slow it down. I don’t have any quantitative information on that, but after several years of using full-disk encryption on my laptop (an X40, which isn’t very powerful), I can say that it remains usable, if you don’t rely on disk-intensive operations, such as compiling kernels and the like.

Alternative approaches

Several alternative approaches exist, all involving an additional device:

  • if you don’t like to type in the passphrase for the root filesystem, you could store it on a USB key (or the like); cryptsetup provides /lib/cryptsetup/scripts/passdev, which can be used to deal with such a situation. You can find more information in cryptsetup‘s README.Debian file.
  • if you don’t like the unencrypted /boot partition, you could boot the system off a USB key, which you can keep separate from the system except for when booting and upgrading the kernel. All you need to do for that is install the bootloader and kernel onto the device and configure it to use the proper encryption volume on the harddisk as root filesystem.
  • cryptsetup also comes with support for PKCS#15 smartcards (opensc and openct).

I have chosen neither of these approaches, because the extra security does not make up for the inconvenience, and the danger of an unbootable system in case of loss of forgetting of the additional device.