Hibernate support on Ubuntu 20.04 with encrypted swap and encrypted root filesystem
So I installed Ubuntu 20.04 on my laptop with encrypted root filesystem with bcache support since I have a NVME SSD along with the usual hard disk in it. While setting up encrypted root filesystem the installer will not allow you to have unencrypted swap – and the default encrypted swap setup is to use a random encryption key that is changed at every boot – so that makes hibernation impossible. After a few shenanigans with the rescue system and systemd I managed to hibernate working with a fixed encryption key swap.
First thing is you have to set up fixed key encryption for the swap – so when using the installer to create an encrypted root filesystem – do not create a partition for swap, the installer will automatically create a swap in
/swapfile after installation. But when partitioning your disks leave out space equivalent to the size of your RAM in your SSD for creating our fixed key encrypted swap post installation.
After installation, disable existing swap using
sudo swapoff -a. Delete the entry of
/etc/fstab. Using your favorite partitioning tool – fdisk, gdisk, parted, or gparted, create a partition in your disk to hold the encrypted swap partition. In my case, the partition is
/dev/nvme0n1p3. Be careful in this step as you risk screwing up the installation itself.
Now we create a random key for encrypting the swap partition using
dd(1) and then use
cryptsetup(8) to create a luks header on the disk partition with the key:
dd if=/dev/urandom of=/.swap-key bs=1 count=512 cryptsetup luksFormat -d /.swap-key /dev/nvme0n1p3
It is a good idea to add a passphrase to the swap partition in case it has to be entered on console at any time – this is not exactly required but this helped me when I was playing around with the system – how would I enter a 512 byte random string on the console? 😀
cryptsetup luksAddKey -d /.swap-key /dev/nvme0n1p3
Open the encrypted partition and format it:
cryptsetup open -d /.swap-key /dev/nvme0n1p3 cryptswap mkswap /dev/mapper/cryptswap
If you note above the mapped name for the encrypted swap is named as
cryptswap – this name will be used later – you can change the name if you wish to. Add the
/etc/fstab entry so that the swap gets mounted at boot, also enable the swap at present:
echo /dev/mapper/cryptswap swap swap defaults 0 0 >> /etc/fstab swapon /dev/mapper/cryptswap
Next we have to populate
/etc/crypttab so that the initramfs can set up the swap partition and resume from hibernate. But before that, find the name of the device that is mounted as
/ (root filesystem) from
/etc/fstab. In my case that is
/dev/mapper/bcache0p1_crypt. Now we can create the
echo cryptswap UUID=$(blkid -s UUID -o value /dev/nvme0n1p3) /dev/disk/by-uuid/$(blkid -s UUID -o value /dev/mapper/bcache0p1_crypt):/.swap-key luks,discard,keyscript=/lib/cryptsetup/scripts/passdev,noauto >> /etc/crypttab
The first field in the
crypttab entry is mapped name of the device, second field is the UUID of the device which has this encrypted filesystem, the third field is path to the key file – here I have specified the path
/dev/disk/by-uuid/<UUID of ROOT FILESYSTEM>:/.swap-key. This syntax is documented in the
crypttab(5) man page for providing unlock keys – if you used a different path for the key then you have to change the path here as well. Important point to be noted here – we have put the encryption key of the swap inside encrypted root filesystem – so without unlocking the root filesystem it is not possible to access the key to the swap. Fourth field specifies the options for the encrypted device – you can omit discard in it if your swap partition is on a hard disk drive.
keyscript=/lib/cryptsetup/scripts/passdev script is documented at Debian Cryptsetup docs and
/usr/share/doc/cryptsetup-initramfs/README.initramfs.gz. It basically lets us use a key file stored on some device. The
noauto option is required to prevent systemd to try to mount the partition as systemd does not seem to support keyscript / fixed keys so when you boot the system normally you will end up without a swap partition because the systemd target fails – but with the
noauto option it gets mounted because initramfs unlocks the swap partition and then devices to be mounted are read from fstab.
Edit /etc/default/grub to disable the systemd crypto generator since we do not need it:
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash luks=no"
Now update grub and initramfs, then test with a reboot that the swap is getting mounted during normal boot process:
update-grub update-initramfs -u -k all reboot
If successful, you can try hibernate – open some text editor window for example and type the following command – as there is no way to get the hibernate button in GNOME menu yet:
Once your machine turns off start it again and you should have the text editor back on the screen in the same state you had shut it down. Hibernate working! You can make this command as a keyboard shortcut in GNOME control center so you can hibernate with a key sequence.