Enabling Full Disk Encryption on Legacy MBR BIOS with LVM on LUKS and GRUB Bootloader

Enabling Full Disk Encryption on Legacy MBR BIOS with LVM on LUKS and GRUB Bootloader

This was obviously somewhat of an edge case, but I’m sure it will apply to many other users out there, and I hope it finds them well. This was one particular case where the Arch Wiki was a little shady and left me figuring out a lot of stuff on my own — as is the case for any Arch user — which is one of the reasons we punish ourselves by using it in the first place. That being said, this method should work with minimal tweaks for just about any OS, because the main things being modified here are the underlying disk formats, partitions, kernel, and bootloader. Everything else is left untouched.

That means if you are restoring an Ubuntu system, then [theoretically] this should probably work for you. That also being said, I was able to do this same thing with all of my files in place on my Ubuntu daily driver about a year ago (without making a backup, like an idiot), and after lots of troubleshooting, I was able to get everything up and working right before work the next morning. I like living on the edge, but I will never try that again, and in that particular case, I was simply one lucky bastard.

There are a few tools out there that should allow you to enable full disk encryption in-place without backing up and restoring files, such as luksipc (LUKS In-Place Conversion Tool) and cryptsetup-reencrypt (which I might have used if I had more patience to read the documentation), but let’s be honest — in-place encryption methods are for both veterans and morons, so we will go about this by means of best practices and do a full backup of our OS before restoring it to its former glory — albeit this time with the added bonus of full disk encryption, as well as the ability to easily resize volumes by means of running LVM along with this setup.

Here’s what we’ll be doing:

  1. Attach an external hard drive to backup our data
  2. Securely wipe the existing data from the main hard drive
  3. Format the disk so that it will boot with legacy BIOS
  4. Create an encrypted LUKS volume with a secure passphrase
  5. Create a volume group, and setup the logical volumes
  6. Mount the new filesystem in the live distro
  7. Copy all of our original data back to the new filesystem from the external HDD
  8. Add mkinitcpio hooks
  9. chroot into the new filesystem
  10. Re-install the Linux kernel and bootloader
  11. Add new kernel parameters, and regenerate the GRUB config
  12. Exit chroot, unmount the new filesystem, say a little prayer, reboot, jerk out the live USB, and watch the magic happen

Here’s what you will need:

  • Your computer
  • Another computer or tablet or phone to read the instructions (or a printer if you are over the age of 50)
  • 2 USB ports (or 1 USB port and a CD-ROM drive if you are old school)
  • A Linux Live USB (or CD) — creating one of these is out of the scope of this tutorial, and if you don’t know how to create one or can’t Google it, then I’m sorry to say that this whole tutorial is outside your scope.
    • I would recommend the Arch ISO, because yes, I’m a douchebag — btw I use Arch — but also because that’s what was used in this tutorial. It should work for pretty much any other Linux OS with a couple of tweaks where necessary, but as-is, YMMV.
  • An external drive that exceeds the capacity of your current OS (because you’ll be backing your OS up to it, and data loss is a bitch).
    • If for some silly reason, you have a FireWire 800 [or eSATA] hard drive, feel free to bend the rule on requirement #2 — all we need is a place to backup and a place to run a live distro.
  • Internet connection
    • You don’t have to be wired. You can simply run wifi-menu to connect to wireless. You need this for the last part to reinstall the kernel and bootloader.

A few things I have learned during these type of exercises

Some of these things I already knew. Some of them I had to learn the hard way. Some of them turned out to be completely useless to this particular exercise, but is still good knowledge to have in your back pocket.

  • GRUB does not work with LUKS version 2 (at least at the time of me writing this).

LUKS version 2 is DEFAULT, so you explicitly have to state --type luks1 in your cryptsetup command in order to make GRUB play nice. This was vaguely referenced in the Arch Wiki, but LUKS2 was basically what ended up killing everything I had been trying, and LUKS1 finally provided the golden ticket to allow everything to come together.

  • In order to boot from BIOS, you need a DOS partition, not GPT, and the boot flag must be set on the boot partition.

After initially partitioning my drive as GPT, I found a nifty workaround that would allow legacy BIOS machines to read and boot from GPT partitions — but it obviously doesn’t work for LUKS, or it doesn’t work for GRUB (or something) — so it’s not relevant to this tutorial, but I found it to be useful information, nonetheless.

The command below will overwrite the second MBR partition slot and add a bootable partition there of type 0 (i.e. unused), covering only the first sector of the device. It will not interfere with the GPT or with the first MBR partition entry which normally contains a protective MBR partition.

printf '\200\0\0\0\0\0\0\0\0\0\0\0\001\0\0\0' | dd of=/dev/sdX bs=1 seek=462

^ That allowed my GPT-partitioned drive to try and boot, and I saw the word “GRUB”, but then it crapped out and threw me into a boot loop.

  • If you want to boot from BIOS, you have to actually boot from BIOS in the first place.

^ I found this out long ago, but you can’t very easily create a system that boots from BIOS if you are running a live disk that booted from UEFI, and vice-versa. Just useful information, but not relevant to this tutorial.

Learn from my mistakes…

I will go ahead and start out by saying that this process was not without trial and lots and lots of error before I finally got it to work. I felt like a dumbass many, many times. In the end, after I finally got things working, I did have to do a little troubleshooting with a tad of manual cleanup that took me maybe 10-15 minutes. I think where I went wrong was using pacstrap on /mnt and downloading a few packages to work with in the chroot jail before copying my original data over, which caused some pacman confusion. Eventually, I had to resolve quite a few duplicates, which was fairly trivial with a little Bash automation, and finally I had to do the dreaded pacman -Syu --overwrite='*', which basically re-installed all of my packages, but in the end nothing was lost.

Needless to say, I learned some things, and I am going to recommend the way that I should have gone about this process instead of the way I actually did it, so that you will avoid the very slight pitfalls that I experienced. I have since run the exact process outlined in this tutorial on a spare laptop, and I can indeed confirm that it works as expected (without the package manager pitfalls that I ran into toward the end). Now let’s get to it.

Let’s start out by attaching an external drive and backing up all of our shit:

Go ahead and sudo -s, because you’re going to want to be root for this mess. Run lsblk -f to get the name of the backup device you just attached. For this example, we’ll say it just so happened to be /dev/sdc.

Now let’s go ahead and back everything up with rsync:

mkdir /mnt/backup
mount /dev/sdc /mnt/backup
rsync -aAXv --exclude={"/boot/*","/dev/*","/proc/*","/sys/*","/tmp/*","/run/*","/mnt/*","/media/*","/lost+found"} / /mnt/backup
umount /mnt/backup

Securely erase all of the things

After you have backed up all your porn, go ahead and reboot into the Live USB. Let’s securely-erase all of that stuff so you can start being a real creep by encrypting it. We will be assuming here that /dev/sda is your main hard drive that you want to encrypt. If you are running from a single drive, then most-likely /dev/sdb will be your Linux Live USB, and /dev/sdc will be your external backup drive. Don’t get the letter wrong. That’s a good way to make a grown man cry.

cryptsetup open --type plain -d /dev/urandom /dev/sda to_be_wiped
dd if=/dev/zero of=/dev/mapper/to_be_wiped status=progress
cryptsetup close to_be_wiped

Set up your partitions

Run cfdisk and for the love of God, make sure you choose dos as the partition type, and make both partitions primary. The first will be your root partition (/dev/sda1) which will take up all the space, minus 1G, which we’ll reserve for /boot (/dev/sda2). It doesn’t have to be as big as 1G, but I like to be prepared for the very distant future.

/dev/sda1 (primary)
/dev/sda2 (primary - bootable flag)

Write it all to disk and quit cfdisk.

Create the volume group, and set up logical volumes

Don’t forget --type luks1 if you want this thing to actually work when all is said and done. The rule of thumb for swap space is RAMx2. I was running 16G in this particular instance, so I reserved 32G for swap space. Probably overkill, but it’s LVM — if necessary, we can always change it later. I also set aside 32G for my root volume, because why not. Everything else goes to /home.

cryptsetup luksFormat --type luks1 /dev/sda1
cryptsetup open /dev/sda1 cryptlvm
pvcreate /dev/mapper/cryptlvm
vgcreate volume_group /dev/mapper/cryptlvm
lvcreate -L 32G volume_group -n swap (RAMx2 for swap)
lvcreate -L 32G volume_group -n root (32G for root)
lvcreate -l 100%FREE volume_group -n home (all the rest for /home)

Create filesystems on each logical volume

mkfs.ext4 /dev/volume_group/root
mkfs.ext4 /dev/volume_group/home
mkfs.ext4 /dev/sda2
mkswap /dev/volume_group/swap

Mount your filesystems and backup drive

mkdir -p /mnt /mnt/home /mnt/boot /mnt/backup
mount /dev/volume_group/root /mnt
mount /dev/volume_group/home /mnt/home
mount /dev/sda2 /mnt/boot
mount /dev/sdc1 /mnt/backup
swapon /dev/volume_group/swap

Copy all your warez back over to their new location

We’re going to backup fstab in case there’s any network shares or something in there you’d like to migrate over to the new one later.

rsync -aAvh --no-i-r --info=progress /mnt/backup/* /mnt/
cd /mnt/backup/etc
mv fstab fstab.bak

Edit mkinitcpio.conf to make the HOOKS line look like the one below:

HOOKS=(base udev autodetect keyboard keymap consolefont modconf block encrypt lvm2 filesystems fsck)

Unmount the backup device:

umount /mnt/backup

Get ready to friggin’ chroot

Beware that if you decide to get fancy and try to run pacman -Sy linux grub, you will have to run mkinitcpio -p linux before installing and generating the GRUB config in the next step. Just follow the dang directions. This is the part where you will need the Internet connection. Run wifi-menu before chrooting, and you’ll be straight.

genfstab -U /mnt > /mnt/etc/fstab
mkdir -p /mnt/sys /mnt/dev /mnt/run /mnt/tmp
chroot /mnt /bin/bash
pacman -Sy linux
pacman -Sy grub

Now that you’re in the chroot jail, edit /etc/default/grub and make the GRUB_CMDLINE_LINUX_DEFAULT= line look like the one below.

Important Note: you also need to uncomment #GRUB_DISABLE_LINUX_UUID=true.

GRUB_CMDLINE_LINUX_DEFAULT="cryptdevice=/dev/sda1:cryptlvm root=/dev/volume_group/root loglevel=3 quiet"

Install GRUB, and rebuild the bootloader config

grub-install /dev/sda
grub-mkconfig -o /boot/grub/grub.cfg

Exit out of the chroot jail, and cleanup after yourself

umount /mnt/boot
umount /mnt/home
umount /mnt

Now jerk out that Live USB with a quickness, say a little prayer, and GRUB should boot up. You should then be prompted to enter your secure passphrase before booting into the OS. At that point, run startx, open a terminal, and do a pacman -Syu to make sure you’re in good shape.

That feeling when you realize you did everything right and see familiarity again…

Leave a Reply