Below are the steps to create a custom decryption strategy for LUKS encrypted volumes, which needs to be decrypted and mounted during kernel boot:
- backup current initramfs image
- create decryption script
- use decryption script with crypttab
- rebuild kernel
- (optional) debug
The solution was tested on Debian 11 and 12.
Locate the latest initrd
image inside the /boot/
folder and back it up via:
sudo cp -aRf /boot/initrd.img-5.10.0-23-amd64 /boot/initrd.img-5.10.0-23-amd64.bak
If something goes wrong in the steps later, this backup initramfs image can be used anytime. To specify this backup image to be loaded instead of any other, press e
on the GRUB menu before boot and go to line starting with initrd
and change the name of the image to the name of backup image and press Ctrl+x
to boot.
In order to create a decryption startegy (aka keyscript), first the crypttab docs and the existing keyscripts should be analyzed, which can be found on a Debian distribution at the following location: /lib/cryptsetup/scripts/
The most import step to be considered for the design of the new script is to avoid printing anything on the stdout, anything but the password that the kernel should pass for cryptsetup
to decrypt a volume. From the docs:
The keyscript's standard output is passed to cryptsetup as decyption key. Its exit status is currently ignored, but no assumption should be made in that regard.
The script should be located next to existing ones, so it gets included automatically in the kernel, when it is rebuilt:
sudo nano /lib/cryptsetup/scripts/decrypt_test
A simple startegy, is to ask the user to manually type in the password, the below script is doing that by using a simple tool called askpass
to handle the IO operations and prints the user provided passphrase to the stdout. Note -n
argument when using echo
, which prints only the variable content to stdout without the (default) trailing new line:
#!/bin/sh
die()
{
echo "$@" >&2
exit 1
}
manual_unlock()
{
ASKPASS_='/lib/cryptsetup/askpass'
PROMPT_="Passphrase for ${CRYPTTAB_NAME}: "
KEY_="$($ASKPASS_ "$PROMPT_")" || die "Error executing $ASKPASS_"
echo -n $KEY_
exit 0
}
manual_unlock
Add execution rights to the newly created script:
sudo chmod +x /lib/cryptsetup/scripts/decrypt_test
The newly created script should be refenreced by crypttab
, so the kernel knows which script to call to get the passphrase during the mount of the encrypted volume. Modify the config file for crypttab
:
sudo nano /etc/crypttab
Example content:
luks1 UUID="aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" none luks,keyscript=decrypt_test,initramfs
Via: sudo update-initramfs -u -k all
If any problems arise during boot, a terminal access helps a lot to inspect the system for errors. This can de done via:
- press
e
on the GRUB menu before boot and go to line starting withlinux
and appendbreak=mount
and pressCtrl+x
. The boot process then will stop before reaching themount
target and terminal will be spawn. - test decryption key for a volume by using the command:
cryptsetup luksOpen --test-passphrase /dev/sdX
- resume the boot process with the
exit
command or reboot withreboot -f