Encrypted Root


In a personal computer scenario, encrypting the whole system is not much more complicated than just encrypting the /home partition, and I see no reason not to do so.

On Linux, I determined dm-crypt, which is part of the kernel, to be the best option. It works as an overlay. It provides a decrypted block device sitting on top of another block device, encrypted. The whole deal tries to be transparent for users of those block devices (eg: filesystems).

Dm-crypt needs a choice of cryptographic algorithms and a key to work. They can be provided by hand but there's also LUKS, which is a special block device format that embeds keys and metadata itself. However, it is designed in a way so that partitions that use it are easy to destroy and to achieve so it spreads the keys through the disk in a way that if even a part goes missing, the whole key is not recoverable. That has its uses but certainly also makes LUKS partitions much more vulnerable to data loss.

When not using LUKS, there's the problem that a method is needed for securely storing the keys. One way to do it is to have a small LUKS partition which contains the keys for the actual root. This small partition can even be stored in a file and used through a loopback device. This trivializes backing the keyring up. I'll be describing this method.

Firstly we'll prepare a LUKS loopback partition in a file, then create some keys storing them in it. For this example aes-cbc-essiv:sha256 has been used, as it's cryptsetup's default when creating plain partitions. It could have been anything else; aes-xts-plain64 is a popular choice. (update: aes-xts-plain64 is now the default for LUKS and a good choice)

Create a LUKS loopback to store keys

#16MB can fit a lot of keys.dd if=/dev/urandom of=keys.luks bs=1M count=16
losetup /dev/loop0 keys.luks
cryptsetup luksFormat /dev/loop0
cryptsetup luksOpen /dev/loop0 keyring
#LUKS default is decent, but let's verify just in case (aes-cbc-essiv:sha256)
cryptsetup status keyring
mkfs.ext3 -m0 /dev/mapper/keyring
mkdir /mnt/whatever
mount /dev/mapper/keyring /mnt/whatever/

Create the keys for the real partition

dd if=/dev/random of=gentoo_root.key bs=1 count=32
cryptsetup -v -c aes-cbc-essiv:sha256 -d gentoo_root.key create name device
cryptsetup luksClose keyring
mkfs.xfs -L gentoo_root /dev/mapper/gentoo_root
mount /dev/mapper/gentoo_root /mnt/gentoo/

Next is preparing a kernel that is capable of booting such an encrypted root partition. The solution I went with is to use an initramfs to do the required setup. I'm using Gentoo genkernel's initrd feature as a base, so I'll only cover the part that sets up the encrypted root.

Kernel checklist (as builtin or modules included in the initrd)

  • General setup/Initial RAM filesystem and RAM disk (initramfs/initrd) support
  • harddisk bus drivers to access /
  • Multiple devices driver support (RAID and LVM) -> crypt target
  • cryptoapi/CBC,SHA256,SHA384,SHA512,BLOWFISH,TWOFISH,SERPENT,AES (the ones we use! SHA256, CBC, AES)
  • drivers/block devices/loop
  • drivers/block devices/initrd support (on by default)
  • filesystems/pseudo/Virtual memory file system support (on by default)
  • Support for the filesystem the root is in (as always) and the keyring's filesystem.

CPIO swiss army knife

  • cpio -idv <file
  • find .|cpio -ov >file

Genkernel trickery

  • genkernel --linuxrc=/usr/src/linuxrc --luks initramfs
  • the --linuxrc param must be an absolute path.
  • The default linuxrc script is: /usr/share/genkernel/defaults/linuxrc

Somewhere in the linuxrc

  • Adapt this to suit your specific needs.
#Roc: fugly as hell but working setup of encrypted /
good_msg 'Setting up encrypted root (Roc)...'
mkdir vfat
mount /dev/sda1 vfat -o ro
losetup /dev/loop0 vfat/keyring.luks
cryptsetup luksOpen /dev/loop0 keyring
mkdir keyring
mount /dev/mapper/keyring keyring -o ro
cryptsetup -d keyring/gentoo_root.aes-cbc-essiv\:sha256.key -s 256 -c aes-cbc-essiv:sha256 --tries 256 create gentoo_root /dev/sda8
umount keyring
rmdir keyring
cryptsetup luksClose keyring
losetup -d /dev/loop0
umount vfat
rmdir vfat

Encrypted Swap

RAM is generally trusted to temporarily store sensitive data. It's a problem when the system decides to page some memory into a swap partition, as that's permanent storage. Even worse, it could be read pretty easily by an attacker with physical access.

A way to deal with that is to have the swap block device be encrypted. As swapped information doesn't need to survive across reboots a random new key can be used for swap at each boot.

We'll be using mkswap to create a new swap at every boot, so it'd be dangerous if device order or partition order or something changed. In order to avoid that, there's many options. We'll detail some.

Option 1: LVM

  • partition type 8e for LVM

We create some basic LVM setup like this

pvcreate <dev>
vgcreate swapvg <dev>
lvcreate -n swapdev -l 100%vg swapvg

And these scripts for setting it up at /etc/local.d

cryptsetup -d /dev/urandom create swap0 /dev/mapper/swapvg-swapdev
mkswap /dev/mapper/swap0
swapon /dev/mapper/swap0
swapoff /dev/mapper/swap0
cryptsetup remove swap0

Option 2: swapfile

We create a swap file like this

dd if=/dev/urandom of=/boot/swapfile bs=1M count=<size_in_mb>

And these scripts for setting it up at /etc/local.d


losetup /dev/loop0 /boot/swapfile
if [ "$?" -eq "0" ]; then
 cryptsetup -d /dev/urandom create swap0 /dev/loop0
 if [ "$?" -eq "0" ]; then
 mkswap -f /dev/mapper/swap0
 swapon /dev/mapper/swap0
 exit 0
 echo "(encrypted swapfile) Oops. Missing kernel support for the relevant crypto stuff."
 exit 1
 echo "(encrypted swapfile) Oops. /dev/loop0 is already in use."
 exit 1
exit 1


swapoff /dev/mapper/swap0
cryptsetup remove swap0
losetup -d /d

Notes on Windows and TrueCrypt

On Windows, one of the popular options is TrueCrypt.

  • Sometimes we'll need to mount a TrueCrypt system drive on Linux:
truecrypt --mount -m system <dev> <mountpoint>