TGLMAN

USB or password boot decrypt

Here is a small guide to create a USB key that store the decryption key for your LUKS encrypted disk, this is useful for when your device is in a safe place and you want it to boot without the need to type a password, and then going back to normal password workflow simply unplugging the USB key.

Generate the decryption key

We will generate a random decryption key and will store it in a file enc_file in the USB key, to do that just get in the root folder of the USB key and run:

dd if=/dev/urandom bs=1 count=256 > enc_file

Let's make sure that the file has the right permissions:

sudo chown root:root enc_file
# 400 is user read only 
sudo chmod 400 enc_file

Add the key to the encrypted drive

Done this let's figure out the device that is a LUKS encrypted device with:

sudo blkid --match-token TYPE=crypto_LUKS -o device

Now that we know the device (in my case /dev/nvme0n1p1) we can add the generated key as decryption key:

sudo cryptsetup luksAddKey /dev/nvme0n1p1 enc_file

To check if the key is added successfully you can use the command:

sudo cryptsetup --verbose open /dev/nvme0n1p1 --test-passphrase --key-file enc_file

Change the boot configuration

The next step is to change the boot decryption process to try to fetch the decryption key from the USB key, for do this we need a script, in my case I used the following script that I put in /bin/luksunlockusb

set -e
if [ ! -e /mnt ]; then
    mkdir -p /mnt
    sleep 3
fi
for usbpartition in /dev/disk/by-id/usb-*-part1; do
    usbdevice=$(readlink -f $usbpartition)
    if mount -t ext4 $usbdevice /mnt 2>/dev/null; then
        if [ -e /mnt/enc_file ]; then
            cat /mnt/enc_file
            umount $usbdevice
            exit
        fi
        umount $usbdevice
    fi
done
/lib/cryptsetup/askpass "Insert USB key or password and press ENTER: "
END

This script at boot list the plugged USB keys, mount them and try to read the enc_file, it will iterate all of them until it find one, otherwise it exit and ask for a password or to plug the USB key.

Now we need to make sure that this script is used, so let's edit the /etc/cryptab from:

nvme0n1p1_crypt UUID=033ad4d9-78d5-4b69-8eab-30c89000fc76 none luks,discard

to:

nvme0n1p1_crypt UUID=033ad4d9-78d5-4b69-8eab-30c89000fc76 none luks,keyscript=/bin/luksunlockusb,initramfs

Done this we just need to run the following command to make sure that all the configuration and scripts are copied in the initramfs so can be used in the boot process:

update-initramfs -u

Things to be careful

When I wrote this not all went smooth, it has been quite hard to test and debug, because you cannot really get debug output from decryption scripts. So do not give up at the first problem, just try again double checking things and tweaking things after some internet search.

Things that I got wrong when trying this:

  • Missing the option -t ext4 in the mount command, often mount works fine without it in your normal shell but is not the case when run in the boot
  • Make sure that your initramfs has all the kernel modules loaded for reading the USB key and the file system in the key.
  • Make sure the mount command has the correct file system of the USB key.
  • This seems to work fine also if you have multiple devices you just need to repeat the commands and settings for all the devices, one thing I noticed was for work with multiple devices I need to have the additional option initramfs in the cryptab file (like I did), it may work without if you have only one device, have your own try.

References

I did not do this by scratch I learned and copied from a number of guides online here the few main one:

https://tqdev.com/2022-luks-with-usb-unlock
https://linuxconfig.org/usb-stick-encryption-using-linux
https://wejn.org/how-to-make-passwordless-cryptsetup.html