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 /swapfile in /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 crypttab entry:

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.

The 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:

systemctl hibernate

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.

3 Comments on “Hibernate support on Ubuntu 20.04 with encrypted swap and encrypted root filesystem”

  1. Thank you so much for this guide! Worked great 🙂

    One minor thing (probably a typo), I’m using 20.04.2, and `cryptsetup open -d /.swap-key cryptswap` didn’t work to open the drive.

    It looks like the device name was also needed, this is what worked for me (using the same dev in this post):
    `cryptsetup open -d /.swap-key /dev/nvme0n1p3 cryptswap`

    Cheers!

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: