Automatically unlock an luks encrypted partiiton with an SDCard

… or a USB card.

I am booting my work laptop (NixOS on a Thinkpad) from a LUKS-encrypted volume. I also do have another “laptop” (used as a build/server) that is LUKS-encrypted. So far, I’ve been using a passphrase I type on boot. It’s more than fine for my laptop, but it means it’s a bit trickier for my other machine. I need to remove from its slot below my desk, type it and re-put it in the slot. This mean it’s a bit harder to do upgrade and reboot without any input from me.

For convenience, I want an SD card’s LUKS volume to unlock and mount when the machine boots, rather than me needing to unlock and mount it each time.

There is a bunch of articles about this, like this one. Or slightly related these ones. I am using NixOS however, and it is actually making things relatively straightforward. The closer article to what I was looking for is this one as well as the NixOS wiki entry on full disk encryption.

The idea is relatively simple : we are going to use a key file (hidden or not in a partition) to unlock a luks encrypted — with a fallback on passphrase (in case the medium is not there). There is 3 main steps :

Creating a keyfile and storing it

Creating a key file is very simple. If we are to use a file, we can just do the following:

$ dd if=/dev/urandom of=hdd.key bs=4096 count=1

I have two key to generate, one for aomi and one for naruhodo

$ dd if=/dev/random of=naruhodo.key.bin bs=1 count=4096
4096+0 records in
4096+0 records out
4096 bytes (4.1 kB, 4.0 KiB) copied, 0.00947718 s, 432 kB/s

$ dd if=/dev/random of=aomi.key.bin bs=1 count=4096
4096+0 records in
4096+0 records out
4096 bytes (4.1 kB, 4.0 KiB) copied, 0.00985101 s, 416 kB/s

What we are going to do here is, to hide the key inside a sdcard or a usb stick. The idea is to use the first or the last few blocks to hide the key.

# This writes the aomi key to the "head" of sda (a sdcard)
$ sudo dd if=sync/aomi.key.bin of=/dev/sda bs=1 count=4096
# This writes the naruhodo key to the "tail" of sdb (a usb card)
# The offset has to be computed from the usb key size
$ sudo dd if=sync/naruhodo.key.bin of=/dev/sdb bs=1 count=4096 seek=30992883712

Add the key to a slot

This is probably the easiest step of all, this is just about running the following.

$ cryptsetup luksAddKey $LUKS_DEVICE $KEY

The only trick to it is : you have to do this “offline”, a.k.a. when the partition in locked (and thus not mounted, …). Either you do this when you are installing the operating system (and it’s straightforward), or you need to boot your laptop/desktop with a livecd (that also then has access to the key).

NixOS configuration

This is where NixOS helps greatly, we have just a few things to write, and NixOS will make sure all is correctly setup (the initramfs, …).

# For aomi, without offset
boot.initrd.luks.devices = {
  root = {
    device = "/dev/disk/by-uuid/{UUID}";
    preLVM = true;
    allowDiscards = true;
    keyFile = "/dev/disk/by-id/{DISKID}";
    keyFileSize = 4096;
    fallbackToPassword = true;
  };
};
# For narudoho, with offset
boot.initrd.luks.devices = {
  root = {
    device = "/dev/disk/by-uuid/{UUID}";
    preLVM = true;
    allowDiscards = true;
    keyFile = "/dev/disk/by-id/{DISKID}";
    keyFileOffset = 30992883712;
    keyFileSize = 4096;
    fallbackToPassword = true;
  };
};

Now, we are a nixos-rebuild away from being able to boot a NixOS on a encrypted file system, without having to type the password if we have the correct medium inserted in the machine.

/Of course, this means that the “unlock” medium becomes precious and important not to loose. If you go on vacation for example, you should definitely remove any of those medium and hide them (or bring them with you)./