When I decided to go with full disk encryption on my machines, I had a pretty
hard time figuring out exactly what to do. Not only were there tools and
commands to learn, but there was quite a bit of design involved in the
process. In this post, I will describe the setup I chose, and the scripts I
use to make things a bit more convenient.

Partition Design

partition

size

label

file system

mount point

notes

sda1

200MiB

boot

ext4

/boot

sda2

20GiB

luks/ext4

/

sda3

218GiB

luks/ext4

/home

sda4

6GiB

Extended Partition

sda5

4096MiB

recovery

ext4

/

Minimal Ubuntu for recovery

sda6

1900MiB

luks/swap

Creating the partition layout

After deciding on a partition scheme, the next step was to create the
partitions and format them. I created a 14.04 USB installer and booted the
machine in the "Try Ubuntu" mode.

This part is easy. I used gparted to create the partition layout above. For
the three encrypted partitions (marked luks/… above) I left them
"unformatted".

Formatting the encrypted partitions

Instructions for the next step came mostly from the Arch
wiki. The process involves
first formatting the encrypted partitions with a Linux Unified Key Setup
(LUKS) header. The luks header contains the AES master key as well as key
information for up to eight passphrases (note, in this context a passphrase
may be a file of arbitrary data) allowing access to that master key.

Initially, I chose to lock down the root and home partitions using a keyfile
passphrase, and later added a password as a passphrase, so I will go through
that process.

First, we need to create a keyfile for each partition. I used /dev/random to
source random bytes (rather than /dev/urandom which is faster but
pseudorandom). Knowing that /dev/random sources user interface event arrival
times for randomness I made sure to do lots of typing while I was reading off
a key. I chose to use a keysize of 512bytes. I initially accomplished this
with

$ cat /dev/random > root.key

while watching in another terminal with ls -l until the file was over 512
bytes. Then I used

$ truncate -s 512 root.key

to reduce the size to 512. After doing this a few times I created a small
script to provide saner feedback on how much data had been read from
/dev/random

And that's it. Reboot now and ubuntu will ask you for a password to expose the
root partition before mounting it. You may notice a warning about /home not
being mounted and given options to wait, skip, or do something else. Just give
it a few more seconds. I guess the timeout built in for mounting /home isn't
long enough to also deal with decrypting it.

USB Master Key

The process of entering the password every boot is troublesome and, to be
honest, my ability to recall secure passwords is not to be trusted. In order
to address this shortcoming, I decided to create a USB stick whose sole
purpose was to act like a password. I do not consider this insecure because,
should I lose the USB key, I can revoke the encryption passphrase from the
LUKS header and make it no longer usable on my system.

I considered several options for how to go about creating the USB key. I
considered a separate boot initramfs with grub installed on the key to
actually boot from the key. I also considered storing the
keyfile on a filesystem and
searching removable filesystems at boot, or trying to identify the disk by
partition label or UUID. Ultimately, I decided instead to use an unformatted
partition of the USB key to store the keyfile.

The following can be performed on target system, however I suggest creating a
backup of the boot/initramfs-…-generic file. If you mess anything up you can
drop to grub (press shift 5 times at boot) and alter the grub boot command to
use the backup initramfs to get back into a useable system.

Then I partitioned the USB key with an unformatted partition of 1MiB and the
rest as LUKS/ext4. The second partition is somewhat irrelevant for this
discussion except to show that the USB key is still useful for storage.

Now copy the keyfile to the unformatted space, and add the key to an unused
slot of the LUKS header for the root partition

The keyscript is a script which dm-crypt runs to get the passphrase. It
expects the passphrase on stdout. I used the script from the stack overflow
link above but took the initial parts of the script from the blog linked above
(which makes the script work with plymouth).

The script attempts to read from the raw device provided in ${CRYPTTAB_KEY}
(which is the third column in crypttab). If the device file does not exist
after 5 seconds, it drops to asking for a password.