Skip to content

Instantly share code, notes, and snippets.

@HacKanCuBa
Last active October 24, 2024 10:36
Show Gist options
  • Save HacKanCuBa/b8565369de9620ba1eb24b75ee836857 to your computer and use it in GitHub Desktop.
Save HacKanCuBa/b8565369de9620ba1eb24b75ee836857 to your computer and use it in GitHub Desktop.
Encrypted SWAP hibernation in Debian 9+

Encrypted SWAP hibernation in Debian 9+

It took me about 6 hours to find out all of this, but after reading a ton of man pages, initram scripts, and bug reports, I got a working result that takes about 2' to set up...

The point is to have a SWAP partition encrypted with LUKS, and it should be decypted during boot.

When using SysV, initram hooks and scripts in Debian worked like a charm but then, Systemd came and it's not yet fully implemented so this kind of crap happens. Systemd's cryptsetup doesn't support parameters in /etc/crypttab so using a script there is ignored:

/* Options Debian's crypttab knows we don't:

    precheck=
    check=
    checkargs=
    noearly=
    loud=
    keyscript=
*/

Source.

Trying to decrypt SWAP partition via /etc/crypttab ends up usable but it can't resume from hibernation because Systemd tries to open it way too late, so the kernel gives up looking for a SWAP. To make it work, you need to pass parameters to the kernel, which Systemd will elegantly take.

Here's the whole deal (read everything first before starting doing things):

Let's say that your encrypted root partition is at /dev/disk/by-partlabel/root and your SWAP, /dev/disk/by-partlabel/swap (here I used GPT partition labels, you can also use UUID). I'll be naming cryptoroot and cryptoswap to the opened devices (accesible via /dev/mapper/...).

1- Edit or create /etc/initramfs-tools/conf.d/resume:
RESUME=/dev/mapper/cryptoswap

2- Remove references to SWAP in /etc/crypttab, i.e. a line like cryptoswap /dev/disk... /dev/urandom swap must be commented out or deleted.

3- Edit /etc/default/grub to set the kernel parameters for resume device and encryption: GRUB_CMDLINE_LINUX="resume=/dev/mapper/cryptoswap cryptopts=source=/dev/disk/by-partlabel/root,target=cryptoroot cryptopts=source=/dev/disk/by-partlabel/swap,target=cryptoswap"

4- Update initramfs and grub: sudo update-initramfs -u && sudo update-grub

Up to this point, you will need a password to open both devices, which is horribly anoying. However, a neat script, provided by cryptsetup, can be used: decypt_derived, which derives a key from an opened device (say, the root device). So, here's what you need to do (skip previous 3rd and 4th steps):

3- Add derived key to SWAP: sudo cryptsetup luksAddKey /dev/disk/by-partlabel/swap <(/lib/cryptsetup/scripts/decrypt_derived cryptoroot)
Verify that it worked: cryptsetup -v --test-passphrase -d <(/lib/cryptsetup/scripts/decrypt_derived cryptoroot) luksOpen /dev/disk/by-partlabel/swap

4- Edit /etc/default/grub: GRUB_CMDLINE_LINUX="resume=/dev/mapper/cryptoswap cryptopts=source=/dev/disk/by-partlabel/root,target=cryptoroot cryptopts=source=/dev/disk/by-partlabel/swap,target=cryptoswap,keyscript=/lib/cryptsetup/scripts/decrypt_derived,key=cryptoroot"
Double-check device and partition names!

5- Add an initram hook to copy decypt_derived binary to the initramfs, create the file /etc/initramfs-tools/hooks/cp_decrypt_derived:

#!/bin/sh
PREREQ=""
prereqs()
{
   echo "$PREREQ"
}

case $1 in
prereqs)
   prereqs
   exit 0
   ;;
esac

. /usr/share/initramfs-tools/hook-functions
# Begin real processing below this line

copy_exec /lib/cryptsetup/scripts/decrypt_derived /lib/cryptsetup/scripts/ >&2

6- Update initramfs and grub: sudo update-initramfs -u && sudo update-grub

That's it! You can hibernate with systemctl hibernate (no need for sudo). If you use a keyfile for the root partition, the same can be done by pointing the kernel to an appropriate keyscript that reads and pushes the key, and a hook that copies said script into initramfs.

Sources

@HacKanCuBa
Copy link
Author

In Debian 12.7, your upgrade may fail with

mkdir: cannot stat ‘/var/tmp/mkinitramfs_lYliay//usr/lib/cryptsetup/scripts’: Too many levels o f symbolic links
cp: cannot stat '/var/tmp/mkinitramfs_lYliay//usr/lib/cryptsetup/scripts/decrypt_derived': Too many levels of symbolic links
E: /etc/initramfs-tools/hooks/cp_decrypt_derived failed with return 1.
update-initramfs: failed for /boot/initrd.img-6.1.0-25-amd64 with 1.

If that's so, you have to disable the cp_decrypt_derived script by marking it as non-executable: sudo chmod 0644 /etc/initramfs-tools/hooks/cp_decrypt_derived (or you could just delete it) and running apt upgrade again.

This could mean that you can no longer use this option, so check your devices to prevent getting yourself locked out.

All in all, this gist is quite outdated, and as a previous comment mentions, there are new ways of doing stuff.

I'm just leaving this here in case someone arrives here looking for this solution.

@rjl6789
Copy link

rjl6789 commented Sep 2, 2024

Cheers noted and will add a note to the gist to this effect.

@domenpk
Copy link

domenpk commented Oct 24, 2024

The script problem on Debian bookworm can also be resolved by changing "copy_exec" line into (it seems it gets confused by the "target" argument, and "copy_exec" should work without that as well):

copy_file script /usr/lib/cryptsetup/scripts/decrypt_derived

Only now have I read https://gist.github.com/HacKanCuBa/b8565369de9620ba1eb24b75ee836857?permalink_comment_id=3432544#gistcomment-3432544 which seems like a more sensible option! Thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment