The attack

Laptops need full disc encryption. Indeed, my university has explicitly banned us keeping any information on our students’ grades on our laptops unless we use FDE. Not even comments on essays, apparently, as that counts as grade information.

There must, though, exist unencrypted code that tells the computer how to decrypt everything else. Otherwise you can’t turn your laptop on. If you’re only trying to protect your data from your laptop being permanently stolen, it’s fine for this to be in an unencrypted partition on the laptop’s HDD: when your laptop is stolen, the data you are trying to protect remains encrypted.

An evil maid attack involves the replacement of this unencrypted code with something malicious – perhaps it e-mails data from the encrypted partition to someone who wants it. Of course, if someone has access to your laptop without your knowledge, they can always work around any security scheme you might develop. They might add a hardware keylogger, for example. So why might we want to try to protect against the evil maid attack – haven’t we already lost if someone is able to modify the contents of the unencrypted partition of our hard drive?

Well, the thing about the evil maid attack is that it is very quick and easy to modify the contents of a laptop’s hard drive, as compared to other security-bypassing hardware modifications, which take much longer to perform without detection. Users expect to be able to easily replace their hard drives, so they are usually accessible with the removal of just a single screw. It could take less than five minutes to deploy the evil maid payload.

Laptops are often left unattended for the two or three minutes it would take to deliver an evil maid payload; they are less often left for long enough that deeper hardware modifications could be made. So it is worth taking steps to prevent evil maid attacks.

The best solution

UEFI Secure Boot. But

  • Debian does not support this yet; and
  • my laptop does not have the hardware support anyway.

My current solution

The standard solution is to put the unencrypted hard drive partition on a USB key, and keep that on one’s keychain. Then there is no unencrypted code on the laptop at all; you boot from the USB, which decrypts the root partition, and then you unmount the USB key.

Problem with this solution

The big problem with this is kernel and bootloader upgrades. You have to ensure your USB key is mounted before your package manager upgrades the kernel. This effectively rules out using unattended-upgrades to get security upgrades for the kernel. They must be applied manually. Further, you probably want a backup USB key with the kernel and bootloader on it. Now you have to upgrade both, using commands like apt-get --reinstall.

This is a real maintenance burden and is likely to delay your security upgrades. And the whole point of putting /boot on a USB key was to improve security!

Something better

Recent GRUB is able to decrypt partitions itself. So /boot can reside within your encrypted root partition. GRUB’s setup scripts are smart enough that you can switch over to this in just a few steps:

  1. Move contents of /boot from USB drive into root partition.
  2. Remove/comment /boot from /etc/fstab.
  3. Set GRUB_ENABLE_CRYPTODISK=y in /etc/default/grub.
  4. grub-install /dev/sda
  5. update-grub

It’s still true that there must be unencrypted code that knows how to decrypt the root partition. Where does that go? grub-install is the command that installs that code; where does it put it? The ArchLinux wiki has the answer. If you’re using EFI, it will go in the EFI system partition (ESP). Under BIOS, if your drive is formatted with an MBR, it goes in the “post-MBR gap” between the MBR and the first partition (on drive partitioned with very old tools, this post-MBR gap might be too small to accommodate the larger GRUB image that contains the decryption code; however, drives partitioned with recent tools that “support 1 MiB partition alignment” (including the Debian stretch installer) will be fine – to check fdisk -l and look at where your first partition starts). Under BIOS, if your drive is formatted with a GPT, you have to add a 1MiB BIOS boot partition, and the code goes there.

We’ve resolved the issue of package updates modifying /boot, which now resides in the encrypted root partition. However, this is not all of the picture. If we are using EFI, now we have unencrypted code in the EFI system partition which is subject to the evil maid attack. And if we respond by moving the EFI system partition onto a USB drive, the package update problem reoccurs: the EFI system partition will not always be mounted. If we are using BIOS, the evil maid reoccurs since it is not that much harder to modify the code in the post-MBR gap or the BIOS boot partition.

My proposed solution, pending UEFI Secure Boot, is to use BIOS boot with a MBR partition table, keep /boot in the encrypted root partition and grub-install to the USB drive. dpkg-reconfigure grub-pc and tell it to never grub-install to anything. Then set the laptop’s boot order to never try to boot from the HDD, only from USB. (There’s no real advantage of GPT with my simple partitioning setup but I think that would also work fine.)

How does this solve the various issues I’ve raised? Well, the amount of code on the USB drive is very small (less than 1MiB) so it is much less likely to require manual updates. Kernel updates will modify /boot; only bootloader could require me to manually run grub-install to modify the contents of the post-MBR gap, but these are very infrequent.

Of course, the BIOS could be cracked such that the laptop will boot from the HDD no matter what USB I have plugged in, or even only when some USB is plugged in, but that’s a hardware modification beyond the evil maid, against which we are not trying to protect.

As a nice bonus, the USB drive’s single FAT32 partition is now usable for sneakernet.