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:
- Move contents of
/boot
from USB drive into root partition. - Remove/comment
/boot
from/etc/fstab
. - Set
GRUB_ENABLE_CRYPTODISK=y
in/etc/default/grub
. grub-install /dev/sda
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.