Real full disk encryption using GRUB on Debian GNU/Linux for BIOS

Outdated content

Published on 2017-06-23. Modified on 2021-08-30.

In this tutorial we're gonna take a look at setting up full disk encryption on a BIOS MBR based system using GRUB on Debian GNU/Linux - the KISS way.

NOTE 2021-08-30: I haven't had time to validate that the approach below works with Debian Bullseye.

cryptsetup currently defaults to v2 of the LUKS header. There has been great work at getting GRUB version 2.06 to support LUKS2, but there still is a bug that prevents this from working. Make sure you specify --type luks1 when creating the encrypted partition. See bug 55093 and the Encrypted boot section at the Arch Linux wiki for details.

When we use GRUB as the boot loader we can setup a full disk LUKS encryption system without any use of a separated unencrypted boot partition.

Normally a separate boot partition needs to remain unencrypted as the bootloader needs to be able to boot the kernel before invoking LUKS, but because GRUB can load encryption modules such as crypto.mod, luks.mod, and cryptodisk.mod we can use GRUB in various settings and still gain a real full disk encryption model without the need for an unencrypted boot partition. This setup is not possible using other boot loaders such as systemd-boot or syslinux, because neither of those boot loaders support loading encryption modules (at least as of writing).

Because the Debian installer hasn't been updated with support for GRUB encryption modules, it really gets in the way when you try to run without an unencrypted boot partition. You simply cannot create an encrypted main partition without creating an unencrypted partition for boot at the same time. The Debian installer will complain and not allow you to continue the installation without setting up the unencrypted boot partition.

One way to get around this is to allow it to create a small unencrypted boot partition, then afterwards disable it and not use it. This actually increases the security of your system a bit as it will look like you're running with an unencrypted boot partition. If an attacker is going to tamper with your computer he or she would most likely install a malicious kernel with a keylogger in your un-encrypted boot partition. In this setup your system would boot without ever using the malicious kernel and if you remember to run something like a sha256sum on the original kernel in the unencrypted boot partition, you can actually detect the tampering without being affected. The unencrypted boot partition could serve as a "honeypot".

The benefits of running with a setup like this rather than a real unencrypted boot partition is that we can mitigate numerous attacks that can occur before and during the boot process, such as an attacker installing a modified kernel that is able to harvest your password phrase. This doesn't mean that the system isn't vulnerable to tampering with the BIOS or the bootloader itself, however it does provide yet another level of security that makes it a bit more difficult to gain access to the encrypted information.

It is very difficult to prevent tampering with the BIOS and/or other hardware components if you leave your computer out-of-sight, however you can dump your MBR and take a look at it with a hexedecimal editor and compare it to an old secure dump.

Other more secure options exist such as using UEFI with custom signature keys and Secure Boot instead of MBR, or booting from another medium, but this tutorial is about a legacy BIOS setup.

To keep things as simple as possible we're not going to use LVM (Logical Volume Management). LVM is a system for partitioning and managing logical volumes, or filesystems, but it has nothing to do with encryption in itself. LVM is a much more advanced and flexible system than the traditional method of partitioning a disk. LVM is used for easy resizing and moving partitions. With LVM you can create as many Logical Volumes as you need and you can also use LVM to take snapshots of your filesystem. However, unless you actually need any of these features, adding the extra layer of complexity doesn't provide any benefits.

Our setup will consist of three disk partitions, one for the un-encrypted boot partition that the Debian installer insists on, which we're never going to use, another one for swap, and the third one for our normal filesystem. The partition scheme will look like this:

sdX1 (unused original boot partition)
sdX2 (LUKS encrypted swap)
sdX3 (LUKS with EXT4, XFS, Btrfs or something else)

Both swap and the normal partition will be fully encrypted with LUKS.

In this example we'll use EXT4 as the filesystem, but you can easily change it into XFS or Btrfs or something else.

One minor downside to this setup with GRUB is that you have to enter your encryption password twice. Once for GRUB and another time during the system boot-up when the Linux initrd image is loaded. However, this can be avoided by adding a keyfile. When the system is booted the keyfile resides in the ramfs, unencrypted, but at this point, so does the LUKS master key, so if an attacker can get a hold of your keyfile in this situation, he might as well get your master key. In such a situation you will need to do a lot more to secure your system, something which is well beyond the scope of this tutorial.

Let's get started.

  1. Boot the Debian GNU/Linux install medium and choose your language, country and keyboard setup.

  2. Setup your network and choose your hostname.

  3. Setup your root password.

  4. Setup a normal user account.

  5. Now it's time to partition the harddisk.

    • Choose "manual" as the partition method.
    • Delete whatever partitions that's already setup on the disk. You do that by choosing the partition you need to delete and then choose "Delete the partition". You continue doing this untill all the partitions has been deleted.
    • When all the partitions has been deleted, choose the "pri/log" - "FREE SPACE".
    • Choose "Create a new partition" and make it 200 MB.
    • Choose "Primary".
    • Choose "Beginning"
    • Change the "Mount point" from "/" to "/boot".
    • Choose "Done setting up the partition".
    • Choose "pri/log" - "FREE SPACE".
    • Choose "Create a new partition".
    • This is going to be used as your encrypted swap partition so make it a size that suits your needs. It's normally recommended that the swap space is maximum twice the amount of RAM.
    • Choose "Primary".
    • Choose "Beginning".
    • IMPORTANT: Change "Use as: " to "do not use the partition".
    • Choose "Done setting up the partition".
    • Choose "pri/log" - "FREE SPACE".
    • Choose "Create a new partition".
    • Choose the size that is being displayed.
    • Choose "Primary".
    • Change "Use as: Ext4.." to "physical volume for encryption".
    • Change the "Bootable flag" from "off" to "on".
    • The most secure option regarding the "Erase data" flag is "yes", but you should note that it takes a very long time on a large disk.
    • Choose "Done setting up the partition".
    • Choose "Configure encrypted volumes".
    • Choose "Yes" to the question about writing changes to disk and configure encrypted volumes.
    • Choose "Create encrypted volumes".
    • Choose "/dev/sdX3" and press "Continue".
    • Choose "Finish".
    • Write your encryption passphrase.
    • Under the "Encrypted volume, which in my case is called (sda3_crypt), choose the disk. In my case it says #1 - ext4.
    • Change the "Mount point" from "none" to "/" (the root file system). Change the file system if you want to use something other than EXT4.
    • Choose "Done setting up the partition".
    • Choose "Finish partitioning and write chnages to disk".

    The installer will now complain about a missing swap partition. Just ignore that for now and choose "No". Next choose "Yes" to the question about writing changes to disks.

    The installer will then setup the disk and install the base system.

  6. Configure the package manager and choose your mirror country.

  7. Decide if you wan't to participate in the package usage survey.

  8. Choose the software to install and continue.

  9. Choose "Yes" to install GRUB on the master boot record and choose the correct device, again in my case it's "/dev/sda".

  10. Choose "Continue" to reboot into the newly installed system.

  11. Once rebooted, use your passphrase to unlock your disk.

    Now we need to deal with the unencrypted /boot partition. First we'll copy all the files in /boot unto a temporary directory, then we'll disable the /boot partition and get GRUB running with its encryption modules in order to be able to decrypt a boot directory instead of the original boot partition.

    You need to login as root. Or if you have installed an X window system then start a terminal and become root by using the su command.

  12. Create the temporary directory and copy files from /boot into it:

    # mkdir /root/tmp
    # cp -r /boot/* /root/tmp/
  13. Unmount the boot partition:

    # umount /boot
  14. Edit fstab and comment out the boot partition (or delete it):

    I prefer to leave the boot partition in fstab and just comment it out.

    # vi /etc/fstab

    In my case it looks like this:

    # UUID=6d8...    /boot   ext4    defaults    0   2

    In the above I have shortened the UUID for brevity.

  15. Copy the files from the temporary directory into the now empty /boot directory.

    First, verify that /boot is no longer mounted:

    # ls /boot

    No files should reside there now.

    Then copy the files back:

    # cp -r /root/tmp/* /boot/
  16. Now we need to setup GRUB to decrypt the /boot directory.

    First you need to figure out what the Debian installer has called your encrypted partition. Take a look in /dev/mapper:

    # ls /dev/mapper/
    control
    sda3_crypt

    In my case it's "sda3_crypt".

    Then edit the GRUB file:

    # vi /etc/default/grub

    And change the line:

    GRUB_CMDLINE_LINUX=""

    To:

    GRUB_CMDLINE_LINUX="cryptdevice=/dev/sda3:sda3_crypt"

    If you're using a SSD disk you need to add "allow-discards" in order to enable TRIM support:

    GRUB_CMDLINE_LINUX="cryptdevice=/dev/sda3:sda3_crypt:allow-discards"

    Make sure that you have used both the correct encryption name and the correct harddisk partition!

    Next, create the following line:

    GRUB_ENABLE_CRYPTODISK=yes

    Save the file and reinstall GRUB:

    # grub-install --target=i386-pc /dev/sda

    Don't be tempted to change the "i386" part of the target if you're using 64bit, you still need to write "i386" as the target. Also make sure you choose the correct device.

    Update the GRUB config:

    # grub-mkconfig -o /boot/grub/grub.cfg

    Then reboot the machine:

    # reboot

    During boot you'll notice that you have to type in your passphrase twice. This is not a mistake. Just ignore it for the moment.

  17. Fix the swap partition.

    Edit /etc/crypttab and insert the following line at the bottom:

    swap /dev/sda2 /dev/urandom swap,cipher=aes-cbc-essiv:sha256,size=256

    Make sure that your device fits. In my case it's /dev/sda2.

  18. Reboot the system again and after login verify that the encryptet swap partition is mapped correctly and set it up:

    # ls -l /dev/mapper/
    swap -> ../dm1
  19. Enable the swap:

    # swapon /dev/mapper/swap

    You can verify a last time with:

    # free
  20. Update fstab:

    # vi /etc/fstab
    /dev/mapper/swap swap swap defaults 0 0
  21. Create the keyfile.

    If you don't mind typing the encryption passphrase twice, you can skip this step and the next.

    # dd bs=512 count=4 if=/dev/urandom of=/crypto_keyfile.bin
    # cryptsetup luksAddKey /dev/sda3 /crypto_keyfile.bin
    # chmod 000 /crypto_keyfile.bin

    Again make sure you're using the correct device. In my case it's /dev/sda3 (the encrypted partition used as the root partition /).

  22. Setup crypttab to use the keyfile.

    Edit /etc/crypttab and change the line where your encrypted partition is listed.

    In my case I need to change:

    sda3_crypt UUID=6d8... none luks

    To:

    sda3_crypt UUID=6d8... /crypto_keyfile.bin luks,keyscript=/bin/cat

    The crypttab cannot deal with the keyfile directly. So in the above the cat executable will be copied into the ramdisk and during boot cat will send the contents of the keyfile to cryptsetup.

    Now we just need to make sure that the keyfile is available before the drive is decrypted by copying it into the ramdisk too. We need to make a custom hook for crypttab.

    Create the file /etc/initramfs-tools/hooks/crypto_keyfile and insert the following into it:

    #!/bin/sh
    cp /crypto_keyfile.bin "${DESTDIR}"

    Make the hook executable:

    # chmod +x /etc/initramfs-tools/hooks/crypto_keyfile

    Recreate the ramdisk:

    # update-initramfs -u

    Then reboot:

    # reboot

That's it!

Remember that you can always mount the original boot partition on /mnt and compare the kernel with the copy you made in /root/tmp. The easiest way though is to keep a secure sha256sum of the original kernel. You can have a script automatically mount your boot partition after startup and then do the checking for you.