Skip to content

Instantly share code, notes, and snippets.

@szocsbarni
Last active March 16, 2024 18:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save szocsbarni/6c5ddcab91824105c2f1c6821878dbf3 to your computer and use it in GitHub Desktop.
Save szocsbarni/6c5ddcab91824105c2f1c6821878dbf3 to your computer and use it in GitHub Desktop.
Custom kernel level LUKS decrypt script

Custom LUKS volume decryption scheme

Below are the steps to create a custom decryption strategy for LUKS encrypted volumes, which needs to be decrypted and mounted during kernel boot:

  1. backup current initramfs image
  2. create decryption script
  3. use decryption script with crypttab
  4. rebuild kernel
  5. (optional) debug

The solution was tested on Debian 11 and 12.

Backup current kernel

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.

Create decryption script

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

Reference the new decryption script

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

Rebuild kernel

Via: sudo update-initramfs -u -k all

Debug

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 with linux and append break=mount and press Ctrl+x. The boot process then will stop before reaching the mount 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 with reboot -f
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment