I want to set up a headless Linux (Debian Wheezy) PC with whole disk encryption, with the ability to unlock the disk either with a USB drive, or by entering a passphrase by keyboard. My starting point is a fresh install using the basic whole disk encryption option in the Debian Installer, which manages everything besides /boot as a LUKS-encrypted logical volume group and gives me the keyboard option. I will describe my current solution in an answer, in hopes that it will be useful and that others can improve on it.
Here are some of the issues I had:
Setting up a passphrase and putting it on the USB drive.
Loading the USB modules in time.
Waiting for the USB drive to recognized by Linux before trying to read from it.
Identifying the correct USB drive (not some other drive that happens to be inserted).
Writing a "keyscript" to pull a passphrase off the USB drive.
Ensuring that the fall-back to keyboard kicks in in all USB failure cases.
I will accept an answer with significant improvements and upvote answers that offer contributions.
A lot of my solution is derived from the post, Using A USB Key For The LUKS Passphrase.
Create a random passphrase:
Insert a USB drive.
dmesgoutput will show the device name; assume/dev/sdd. Figure out its size:I decided to install the passphrase at the end of the raw device, figuring it might survive any accidental use of the USB drive.
Add the passphrase to the LUKS volume:
This does not affect the existing hand-entered passphrase from the installer. The passphrase file can be deleted:
Find a unique name for the USB stick, so we can identify it when present:
You should see one symlink. I will call it
/dev/disk/by-id/<ID>.Edit
/etc/crypttab. You should see a line like:Modify it to:
The
keyscriptreferred to above will need to read the passphrase from the USB device. However, it needs to do more than that. To understand how it is used, check/usr/share/initramfs-tools/scripts/local-top/cryptroot, the script that runs at boot time to unlock the root device. Note when akeyscriptis set, it is simply run and the output piped toluksOpenwith no other checking. There is no way to signal an error (USB drive not present) or fall back to keyboard input. If the passphrase fails, the keyscript is run again in a loop, up to some number of times; however we are not told which iteration we are on. Also, we have no control over when the keyscript is run, so we can't be sure Linux has recognized the USB drive.I addressed this with some hacks:
Poll on the USB drive and wait 3 seconds for it to appear. This works for me, but I would love to know a better way.
Create a dummy file
/passphrase-from-usb-triedon first run to indicate that we have been run at least once.If we have been run at least once, or the USB drive cannot be found, run the
askpassprogram used bycryptrootfor keyboard input.The final script:
Finally, we need to ensure that this script is available in the initramfs. Create
/etc/initramfs-tools/hooks/passphrase-from-usbcontaining:The USB drivers were not present in my initramfs. (It appears they are by default in later versions of Debian.) I had to add them by adding to
/etc/initramfs-tools/modules:When all is done, update the initramfs: