This post is a guide to setup disk encryption on Ubuntu 20.04 using LUKS2, while still being able to dual boot to Windows 10. Unlike most guides out there, I intend to keep the setup as simple as possible:
- One partition for boot, and another for everything else (no separate data partition)
- Boot partition is unencrypted
- No swap
- No LVM
I will not convince you why you should encrypt your hard disk – plenty of resources out there already.
Though I try to keep explanations simple, I presume you are already a little familiar with Linux to begin with; this is not a guide to be following if this is your first time installing Linux.
I am using Kubuntu here, but there should not be much difference in the setup procedure across different Ubuntu variants.
Rationale for Setup
You can skip ahead to “Prologue” if you do not bother to know.
I have used file based encryption via eCryptfs on my home folder for a few months. A bit of setup was needed since I did not encrypt during installation, but it was tolerably simple and it had so far worked really well. I opted to switch to disk based encryption mainly because Ubuntu team does not intend to support file based encryption moving forward. Disk based encryption is also more performant when dealing with many files (see performance comparison on phoronix.com).
Now although it sounds good to switch in theory, the setup is a big pain, especially for a GUI lover like me. Ubuntu and Pop OS offers disk based encryption out of the box, but the moment you need to customise your disk setup (so as not to wipe your Windows installation), the convenience is thrown out the window. I went through Full_Disk_Encryption_Howto_2019 from Ubuntu Community Wiki and Encrypting disks on Ubuntu 19.04 from Isuru Perera and found it too much work.
So I came up with my own guide.
I have only 110GB of space allocated for my linux setup, so dividing up between data partition and the OS is a tough call. I do not keep a lot of data inside my laptop anyway.
Encrypting my boot partition and putting decryption keys to root partition inside makes no sense to me. Even the default Ubuntu setup does not do this. Having said that, GRUB very recently supported LUKS2, in case you want to attempt to encrypt anyway.
I have 16GB of RAM and the concept of swap is foreign to me.
LVM is good if you want to grow your partition space across multiple hard disks, even while your OS is running. I am stuck with the single disk slot in my thinkpad, so this is a little unecessary.
Disclaimer: many things can go wrong when you customize your setup and fiddle with the terminal as root user. It is recommended to keep a backup of valuable data and do a few trail runs first.
My disk setup as is below.
I have formatted my devices as follows (your device names may vary; do not just copy what you see!).
- For my root parition I use a 110Gb EXT4 partition (/dev/nvme0n1p5)
- For my boot partition I use a
300Mb 500Mb EXT4 partition (/dev/nvme0n1p6)
Update 9/5/2020: 300Mb boot partition is too small – should be 500Mb. Turns out Ubuntu stores a few versions of the initrd in the boot partition and I bumped to “Error 24 : Write error : cannot write compressed block” when updating. You could resolve this by removing older kernels (refer here), but it is not pleasant to bump to this issue. apt does offer to cleanup old kernels for you, but you need to explicitly do so after updating:
I have also a 260Mb EFI partition (/dev/nvme0n1p1), which is mandatory for me because my laptop uses UEFI – you may not have this. Everything else belongs to Windows.
Be sure you jot down the device name of your designated root partition (/dev/nvme0n1p5 in this example). You will use it a lot later.
Partition managers are simple to use, so I skip the steps for setting up the partitions here.
Important: partition manager allows you to encrypt your partition as an option when you format. Do not enable this. As of this writing it defaults to LUKS1; we want LUKS2.
Now we setup encryption on the root partition.
$ sudo -i # proceed the entire guide as root user
# cryptsetup luksFormat /dev/nvme0n1p5
WARNING: Device /dev/nvme0n1p5 already contains a 'ext4' superblock signature.
This will overwrite data on /dev/nvme0n1p5 irrevocably.
Are you sure? (Type uppercase yes): YES
Enter passphrase for /dev/nvme0n1p5:
This will replace our ext4 partition with an encrypted LUKS partition. To verify that we are indeed using LUKS2, check the version (I have omitted the output for brevity):
# cryptsetup luksDump /dev/nvme0n1p5
LUKS header information
Next, we open the encrypted partition as rootfs so that Ubuntu can be installed inside:
# cryptsetup open /dev/nvme0n1p5 rootfs
Enter passphrase for /dev/nvme0n1p5:
This will create a new device /dev/mapper/rootfs where we can read and write freely, while the encryption and decryption is performed underneath. It is currently unformatted space, so we need to format as ext4:
# mkfs.ext4 /dev/mapper/rootfs
mke2fs 1.45.5 (07-Jan-2020)
Creating filesystem with 501760 4k blocks and 125440 inodes
Filesystem UUID: 31dcba0e-ec56-4321-9578-0abcd162de2f
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912
Allocating group tables: done
Writing inode tables: done
Creating journal (8192 blocks): done
Writing superblocks and filesystem accounting information: done
Now we can install Ubuntu into /dev/mapper/rootfs.
Supposedly you can also format to ext4 in the graphical installer, but last I tried it seemed to think it needs to create a partition table, and I cannot get Ubuntu to boot properly afterwards.
I will skip ahead a few steps to the disk setup. Here you may notice that there is no guided option where you can have encryption and keep your dual boot setup. You will need to do manual disk setup:
Select “Manual” for disk setup
In the “Prepare Partitions” page, let us start with the boot partition /dev/nvme0n1p6:
- Use as: ext4 journaling file system
- Format the partition: ✓
- Mount point: /boot
Setup boot partition with parameters as shown
Now it gets a little confusing when it comes to the encrypted partition. For some reason, the Ubuntu installer displays it like it is a separate device from my hard disk. So select the partition under /dev/mapper/rootfs, which is also called /dev/mapper/rootfs, and set as follows:
- Use as: ext4 journaling file system
- Format the partition: ✓
- Mount point: /
Setup root partition with parameters as shown
After setting both, you will see something like this when you select /dev/nvme0n1 and /dev/mapper/rootfs:
Lastly, if you have an EFI partition (/dev/nvme0n1p1 in my case), there is where you want to install the boot loader:
The steps after this is straightforward, so I will skip ahead to the part where the installation completes. Here click “Continue Testing” instead of restarting.
If you restart your Ubuntu installation now, your kernel would not be able to mount your root partition because it is encrypted. To circumvent this, you need to tell your kernel that the hard disk is encrypted. This is where crypttab comes in.
crypttab is like fstab in that it tells your kernel which hard disks to boot during startup. The key difference is that it is only for encrypted drives, and it loads before fstab.
Before we can setup crypttab for our fresh installation, we need to first understand that we are currently in the testing image. Any config changes we do in /etc/ therefore affects not our fresh installation (installed in /target/), but the testing image.
To change our terminal environment to the fresh install, execute:
# for n in proc sys dev etc/resolv.conf; do mount --rbind /$n /target/$n; done # change mount points to target
# chroot /target # change root directory to target
# mount -a # mount all devices in fstab
Now, to inform the kernel to identify your LUKS encrypted root partition /dev/nvme0n1p5 as rootfs, execute the following:
# echo "rootfs UUID=`blkid -s UUID -o value /dev/nvme0n1p5` none luks" >> /etc/crypttab
Verify that your UUID has been added to crypttab:
# cat /etc/crypttab
rootfs UUID=aacc905d-beef-baba-a477-88aa12345fb2 none luks
Now you may be wondering: how is the kernel going to know what you set if the config is set in /etc/crypttab when it is in an encrypted disk?
Well, the kernel does not read it from there. You need to execute:
# update-initramfs -u -k all
update-initramfs: Generating /boot/initrd.img-5.3.0-46-generic
As you can see, it updates a file in /boot/, which is unencrypted.
Now restart and boot up your Ubuntu installation and you will be asked to key in a password to decrypt your root partition:
A fairly common issue you can expect is that Windows 10 time will be out of sync. You can fix it temporarily in Windows 10 and toggling setting the time automatically, but a permanent fix is to execute this in Ubuntu:
timedatectl set-local-rtc 1 --adjust-system-clock
It is important to note that your encryption password is different from your login password; changing one does not change the other. Having said that, it is convenient to keep them both passwords the same and disable login at startup – unless you want to key in your password twice during startup.
Though it is easy to change your login password from your window manager, you need to use the command line to change your LUKS2 password (this process does not re-encrypt your partition, so do not hesitate to change the passphrase on a whim):
# cryptsetup luksChangeKey /dev/nvme0n1p5
Enter passphrase to be changed:
Enter new passphrase:
The wording “Enter passphrase to be changed” is very deliberate – LUKS can be configured to allow multiple passphrases to be configured for the same device.
I now end this post with a screenshot of my desktop. Cheers!
Crap I formatted /boot/efi and now Windows 10 cannot boot! What do I do?
It is possible to restore the boot record to a new /boot/efi partition, but you will need a bootable USB stick with Windows 10 inside. To do this you’ll need a windows machine and a USB drive with about 8GB of space.
- Create bootable USB drive using the Windows 10 Media Creation Tool (download option will not show up in a Linux machine).
- Boot from the USB drive
- Select Repair Your Computer.
- Select Troubleshoot.
- Select Advanced Options.
- Choose Command Prompt from the menu:
- Now use diskpart to assign a drive letter to new /boot/efi partition:
diskpart # Start diskpart
sel disk 0 # Select first physical disk
list vol # List all volumes. Search for your EFI paritition
sel vol <EFI_VOL_NO> # Select EFI partition
assign letter=<EFI_LETTER>: # Assign an unused drive letter
- Now you can recreate the boot record with <EFI_LETTER>:
bcdboot c:\Windows /l en-us /s <EFI_LETTER>: All
Now you will be able to boot Windows 10 again.