I feel that using full disk encryption of laptops is a must. Not to protect against attacks with physical access (to the unencrypted boot loader or unprotected BIOS), but to avoid leaking data when the laptop is either lost or stolen. Entering a long passphrase is not very convenient, especially when you are sharing the device with multiple people. This post will explain how to unlock your computer by inserting a USB drive containing a key file, while still allowing to unlock using a passphrase. At the end of the post we describe how to conveniently hide the USB drive in Windows and Linux.

Instructions
I have tested the below steps on Ubuntu 22.04 and these are expected to be correct for any recent Debian based distribution.
- Install the “uuid” tool
sudo apt install uuid
- Create a random key name using the “uuid” tool:
uuid
will show a random UUID, mine was:
85125e5e-7bc4-11ec-afea-67650910c179
- Create a 256 byte key file with random data (.lek = LUKS Encryption Key):
dd if=/dev/urandom bs=1 count=256 > 85125e5e-7bc4-11ec-afea-67650910c179.lek
- Insert a USB drive. It gets mounted somewhere in “/media”, let’s find it:
lsblk
will show that the 16GB USB stick is mounted as “/media/maurits/B54D-B744”:
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sdb 8:0 1 14,7G 0 disk
└─sdb1 8:1 1 14,7G 0 part /media/maurits/B54D-B744
...
- Copy the key file to the USB drive:
cp 85125e5e-7bc4-11ec-afea-67650910c179.lek /media/maurits/B54D-B744
- Find the encrypted volume:
sudo blkid --match-token TYPE=crypto_LUKS -o device
will show:
/dev/sda3
- Add the key file to the LUKS volume:
sudo cryptsetup luksAddKey /dev/sda3 85125e5e-7bc4-11ec-afea-67650910c179.lek
This does not affect the existing hand-entered passphrase from the installer (in slot 0).
- Delete the key file (it is loaded in LUKS and copied to the USB drive):
rm 85125e5e-7bc4-11ec-afea-67650910c179.lek
- Edit /etc/crypttab. You should see a line like:
sda3_crypt UUID=b9570e0f-3bd3-40b0-801f-ee20ac460207 none luks,discard
Modify it to:
sda3_crypt UUID=b9570e0f-3bd3-40b0-801f-ee20ac460207 85125e5e-7bc4-11ec-afea-67650910c179 luks,discard,keyscript=/bin/luksunlockusb
- Add a script that will search for the key on USB drives during boot:
cat << "END" > luksunlockusb
#!/bin/sh
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 vfat $usbdevice /mnt 2>/dev/null; then
if [ -e /mnt/$CRYPTTAB_KEY.lek ]; then
cat /mnt/$CRYPTTAB_KEY.lek
umount $usbdevice
exit
fi
umount $usbdevice
fi
done
/lib/cryptsetup/askpass "Insert USB key and press ENTER: "
END
- Make the script executable and move it to the right location:
chmod 755 luksunlockusb
sudo mv luksunlockusb /bin/luksunlockusb
- Debian 11 only, add some modules to the
/etc/initramfs-tools/modulesfile:
vfat
nls_cp437
nls_ascii
usb_storage
- Include the “luksunlockusb” script (and modules) in the initial ram file system using:
sudo update-initramfs -u
- Done. Reboot and enjoy!
Note that next to inserting the USB drive you can still enter the old passphrase during the boot even though the script has changed the prompt.
Creating a hidden partition
In order to hide the USB drive (prevent the partition from mounting in Linux and Windows) you can create a new GPT partition table on the USB drive and add only a bootable EFI Startup Partition (ESP) to hold your keys. This partition must be the first partition on the drive and have a minimum size of 16 megabytes. Technically it may contain any other content and may be followed by one or more partitions of any type. I prefer to leave them with only this single hidden partition as it prevents (non-technical) people from using the USB stick as a drive (I use key shaped USB drives). You can find some of my scripts on my GitHub:
https://github.com/mevdschee/bitlocker-luks-tools
Alternative: “passdev” keyscript
Some people say that one should use the (Debian) included “passdev” keyscript (see: /lib/cryptsetup/scripts/passdev). You can set it to wait for a USB drive with label ‘USB_ENC_KEY’ that contains the file ‘/85125e5e-7bc4-11ec-afea-67650910c179.lek’ for a maximum of 10 seconds using:
sda3_crypt UUID=b9570e0f-3bd3-40b0-801f-ee20ac460207 /dev/disk/by-label/USB_ENC_KEY:/85125e5e-7bc4-11ec-afea-67650910c179.lek:10 luks,discard,keyscript=passdev
Note that Debian 11 does NOT support the timeout parameter and also that it doesn’t properly unmount the drive, causing the start-job to hang for 1 minute and 30 seconds. I do recommend writing your own keyscript instead of using passdev.
Links
- How to load LUKS passphrase from USB, falling back to keyboard?
- Using a USB key for the LUKS passphrase
- GitHub (mevdschee): Bitlocker and LUKS tools
- Why I use Bitlocker without TPM
- TQdev.com: LUKS with SSH unlock
- TQdev.com: LUKS with HTTPS unlock
- Configuration for passwordless root filesystem
- Debian: Unlock LUKS root device on LVM by an USB key
- How to configure LVM & LUKS to autodecrypt partition?