UPDATE: due to a wordpress bug, the pictures for this article are all missing from the server. i am quite angry about this but im going to leave the post as-is because the text is still relevant and useful.
While it is true that many Linux distributions provide the ability to setup system encryption, they “fake it” by using a set of scripts and kernel modules that are loaded using an initrd on an unencrypted partition. This works well because most Linux distros already utilize an initrd, and by simply including routines to mount an encrypted partition instead of a normal ext3 partition, they can keep root encrypted.
However, many Linux users have been asking for the ability to encrypt the entire system following a similar model to Truecrypt for Windows, which leaves only a small bootloader unencrypted at the start of the disk. This is now possible with extensions to the next generation GRUB2 bootloader, which has been patched to support not only AES, Twofish, Serpent and CAST5 encryption, but a number of hashing routines such as SHA1, SHA256, SHA512, and RIPEMD160. There is also support for the LUKS on-disk encryption format.
Note that there will still be an unencrypted bootloader, and an attacker could compromise it just like they could have compromised the unencrypted kernel on the /boot partition. To be clear, this does not in any way make your system less vulnerable to offline attack, if an attacker were to replace your bootloader with their own, or redirect the boot process to boot their own code, your system can still be compromised.
While this is more complicated and involved than most of the projects I work on, if you have experience working with Linux systems you should be able to replicate what i have done. This is not truly a tutorial or a howto, more a documentation of what i did so that others can perhaps benefit from what i spent hours working through and figuring out. If however you expect to simply follow these instructions line by line, it may not work, as you can easily get lost or miss a command, or need to improvise to keep things working. There are probably smarter or more simple ways to do certain steps, but this is what i did.
I very strongly advise you do to this in VMware first before deploying on a standalone system. Take backup snapshots of the system at various stages (vmware can do this), so that if you do something wrong or miss a step you can roll back the changes and keep going. This is exactly what i did and it saved me a significant amount of time.
Before we go on it should be noted this is a VERY manual process, especially after it is all setup, you will not be able to allow the normal grub scripts to update the grub.cfg file (in fact update-grub will no longer be installed), i am working on a solution to this, perhaps modifying the update-grub script and leaving it in place. You will also need to manually type the location of the grub.cfg file in the grub bootloader since it will be sitting on an encrypted partition. This too should become unnecessary once certain features are added to the code in the future, it should be possible for grub to find the luks partition, ask for the password and look for a configuration file all on its own. Since that is not the case yet, we will be doing it manually, and I will explain these things later on when the time comes.
My goal here is to encourage the distro maintainers and the developers of GRUB2 to merge the code involved here into usable packages that can be installed or automated by the distributions themselves, that would make most of this work unnecessary. However that is not the case right now, and this is truly the bleeding edge (this code is not even in the trunk of GRUB2 yet), so manual work is needed.
First off, I will start with an already encrypted Ubuntu system, created by using the Ubuntu alternate install cd. I did not use the guided encryption option, instead i setup a single boot partition and a single encrypted root partition, because the guided option creates an LVM setup on top of the encrypted partition, and I would like to at least TRY to keep things from getting too complicated. It should however work the same as long as you add the right module for LVM to the grub2 image later on. For some help manually installing an encrypted setup in this manner, look at the previous article about dual boot encryption, i setup that system very similar without using LVM.
This setup with the separate boot partition will be helpful, because we will need that space later on and we will be deleting the boot partition anyway, since the goal is to encrypt the entire system :) By default there is 32.5kb available at the start of the disk before the first partition (the boot partition in this case), and this does not appear to be enough to contain the GRUB2 core image with the cryptography modules included, so we simply make sure the encrypted partition, the only one we will care about when this is all finished, starts much later on the disk than 32.5kb.
Once you have a working encrypted Ubuntu system, lets install Ubuntu’s version of GRUB2:
This will also remove the original grub. We won’t be keeping this version of GRUB2, but we would like to make sure that GRUB2 will at least work on the system before going to the trouble of compiling and manually creating a GRUB2 core image with encryption support.
The installer will ask you if you want to chainload from the old bootloader (it is technically still installed to the boot sector), we do not. We need to know if GRUB2 can work on the system by itself, so tell it no:
Now that the GRUB2 package is installed in the filesystem we need to actually install it to the hard drive and to the /boot/grub directory, which will now have a number of GRUB2 specific files in it:
When grub2 was installed the system should have created a grub.cfg file, however if it didn’t or just to make sure, run
sudo update-grub now and reboot.
If the system still boots correctly using their GRUB2 package we will continue, if not, it is unlikely that GRUB2 will work on your system, or you missed a step. If you get a terminal grub prompt, you may have forgotten to run update-grub and are now missing a grub.cfg file, or an unknown problem could be preventing grub from reading your /boot partition where the grub.cfg file resides. If however it gives you an unknown error or refuses to do anything, it might just not work at all for some reason.
It did in fact work for me, i now have an encrypted Ubuntu system booting using the GRUB2 bootloader. Before we remove this copy of grub2 we need to save the grub-setup binary it installed (because it is absolutely necessary for the moment if we wish to install our new luks enabled grub2 image later on). So before continuing, run
sudo cp /usr/sbin/grub-setup /grub-setup.
Then I will proceed to uninstall grub2:
We also need to save the grub.cfg file and remove all of the support files grub left behind to ensure they don’t conflict with our new version we will compile soon:
Now that grub is wiped out, we need to copy the kernel and other files in the /boot partition to a safe place on the filesystem:
And now unmount and delete the boot partition. NOTE: This will only remove the partition entry, if you want to get rid of the data on the boot partition, dd over it sourcing from /dev/zero or /dev/urandom first like this
sudo dd if=/dev/urandom of=/dev/sda1. Make sure the partition you enter there is correct.
And remove reference to it from /etc/fstab, run
sudo nano /etc/fstab and remove the line the cursor is on and the UUID line right below it, it should say sda1:
And now rename the location we put the boot files to /boot:
Now we should have a single filesystem with the kernel, the initrd, and the grub directory (empty right now) included instead of being separate. From this point on the system WILL NOT boot as-is, so do not restart the system or you will need to start over, or chroot into the system from a livecd to continue.
Now we compile the LUKS-enabled GRUB2 source. To be clear i did not write the code that enables all this to work, so don’t give me credit for that. The work was done by developers working on the GRUB2 project. If you would like to be involved, or check out the latest source, or simply thank them for their work, subscribe to the grub-devel mailing list or visit the #grub irc room on irc.freenode.net.
We need to install some packages to compile the source code, so we run
sudo apt-get install build-essential bison, then we change directory to our new source tree and run
./configure to prepare the Makefile:
If it doesn’t complete without error, something is missing or setup incorrectly.
Now we compile the source code by running
make, and it should also complete without error:
Now we run
sudo make install to install the files to the system folders:
Now we will want to run
grub-install, which will install the modules and support files to /boot/grub for use later on:
It will complain that it doesn’t know the mapping for the encrypted root partition, this is fine, all we want it to do is copy the right files into /boot/grub/, and we will generate our own GRUB2 image and install it to the bootsector later on. For now we just need to make sure that the modules and a config file are present in our encrypted system in the right places. You will also want to run
sudo cp /grub.cfg /boot/grub/grub.cfg now to put our config file back.
We should now be able to run various commands to work with GRUB2 images and files. We will want to generate a new core image with the cryptography modules included:
That command was:
sudo grub-mkimage -o /boot/grub/core.img configfile sha1 fs_uuid biosdisk pc linux ext2 help minicmd crypto aes luks sha256 devmapper. This will create a grub core image that includes the files that are essential for grub to be able to read the encrypted filesystem and prompt you for your password. If you get this command wrong, you may not be able to boot the system, and will have to chroot into the encrypted partition to try again. If you used the guided encryption setup in the ubuntu installer you will need to add the lvm module to that line above, and perhaps some others. I have not tested this yet.
To be sure we created the core image correctly, run
ls -lh /boot/grub/core*. You should get a ~60kb core.img file. If you don’t or if it is ~20kb, you should run the grub-mkimage command above again or make sure you get the syntax right.
Now that we have a core image created with the right modules, we can install it directly to the drive. However, because of what appears to either be a bug in the trunk code, or a modification made by the Ubuntu developers needed to work with lvm and encrypted setups, the grub-setup program that comes with the trunk code does not like the partition setup and can’t decide which device is represented by /dev/mapper/ubuntu-root (this was the error earlier about the mapping). The solution for the moment appears to be to use the grub-setup script that came with the Ubuntu grub2 package (the one we saved earlier) to do the actual installation to the drive:
Make sure you execute that command correctly from the folder it resides in (i have it in /home/steve/ubuntu-grub-binaries, we copied it to / earlier), because if you don’t you won’t actually have a luks-enabled bootloader and will have to rollback your vmware snapshot or start over.
However if it does write correctly without error, we can now proceed to modify the grub.cfg file to reflect the new locations of the kernel and initrd. So modify /boot/grub/grub.cfg to reflect the configuration i have here:
You will notice we are simply using vmlinuz and initrd.img instead of the specific versions Ubuntu had setup before, this is because these are symlinks to the real files inside the /boot/ folder, and we know they are going to work correctly for the moment. If the kernel is upgraded these might not point to the correct kernel anymore, and if the older kernel is removed they might not work at all unless you fix them. If you intend to use full kernel versions in the grub.cfg file you will need to reference them by full path, which would be /boot/vmlinuz-2.6.24-23-generic. They are relative to the full root now instead of the separate /boot partition, this is why you need to include /boot/ in the lines.
This is a hackish solution, very manual, but it works for the moment. Until a solution can be found to get update-grub to write the grub.cfg file correctly we will stick with manually editing it.
Your /dev/mapper item should be similar but perhaps slightly different, as long as it reflects the same device you get when you check the
mount command, you are fine. You will notice that the hard drive device numbers have changed, they are no longer (hd0,1) but now (lk0), because GRUB2 will be reading the kernel and initrd directly from a luks device :)
Once you have those changes made, you can reboot the system, and it should come up with a blank GRUB2 terminal screen. You should be able to run the following command:
This should prompt you for a password like this:
And then it should load the grub.cfg file from the encrypted partition:
If you hit the default item, it should boot the kernel and initrd, load the pretty Ubuntu boot screen and eventually ask you for your password again. This is necessary because we are dealing with 2 distinct systems, GRUB2 merely needs to know the password to load the kernel and initrd into memory and read the grub.cfg file, it does not actually mount any filesystems such as root, that is done by the kernel. It would probably be possible for GRUB2 to pass our encryption password to the kernel so that the 2nd password prompt is not necessary, but it is only a minor inconvenience for the moment.
In the future it should be possible for Ubuntu to integrate all of this, such that the install CD could have a check box to encrypt everything and install a custom copy of the core image to the drive. In that case, the only thing left unencrypted would be the first 512 bytes of the drive, and perhaps a 20-40kb bootloader.