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 keyb
despite the great answer from @Andrew which works in previous versions. The solution actually is outdated and needs lots of tuning for ubuntu 18.04 and 19.10. So I want to share my research on this.
There are several catches about crypttab. The sepcs actually changed a lot from 14.04 to 18.04 and to 19.10. It starts to support more parameters for cryptsetup. For example keyfile-offset, keyfile-size, etc. Some of the options e.g. nobootwait are gone. Some parameters supported in other distro already but is not supported in ubuntu yet (for example very nice parameter keyfile-timeout. This can eliminate the entire keyscript since it will automatically fallback to keyboard input after the keyfile-timeout.)
The major pit-fall for crypttab on ubuntu is that it actually processed by 2 different processes. One is the traditionally initramfs and another is the modern systemd. Systemd is supposed to be more advanced and flexiable in many aspect. However, systemd has poor support for crypptab, there are many options such as keyscript just silently ignored. so I have no idea what is going on, until I spotted this post. Almost all the posts online about crypttab settings is for initramfs not for systemd. So we need to add initramfs
to all the entries in crypttab to avoid problems.
I also discovered a nice way to debug our keyscript and crypttab without VM or repeatedly rebooting. It is cryptdisks_start
. Before we actually propagate our changes to initramfs, we should always test it with this nice command. Otherwise, you have to end-up locked out from your system and can only recover it through chroot environment.
@andrew posted a nice way to use data hide in the raw area of a file system. However, I found it is very annoying when we want to automatically create partitions and dd the raw data to lots of usbkeys, we have to calculate the offset for all different file systems and different partition sizes. Moreover, if a user accidentally write onto the FS, there is some risk that the key got overritten. A raw partition without any FS on it makes more sense in this case. However raw partition does not have UUID which is not very useful for automatic unlocking. Thus, I would like introduce a way just use normal passphrase files on the usbkey filesystem. The major issue of passdev is it does not seek/stop during reading the file. Thus we cannot use the keyfile-offset and keyfile-size option when we want to fallback to keyboard input. Because cryptsetup will actually try to skip in the input content and if the content is shorter than keyfile-size, it raises an error. This also means if there is large offset, passdev can be very slow since it always read from beginning. However, there is no point to implement offset and keyfile size for a actual file on file system. I believe those are created for raw device.
The crypttab
luks-part UUID="" /dev/disk/by-uuid/:/: luks,keyfile-offset=,keyfile-size=<>,keyscript=/bin/passphrase-from-usbfs.sh,tries=,initramfs
the keyscript passphrase-from-usbfs.sh utilized the /lib/cryptsetup/scripts/passdev
which will wait the usb device and mount the fs then pipe out the file content. It supports the CRYPTTAB_KEY
in format of /device-path/
.
#!/bin/sh
#all message need to echo to stderr, the stdout is used for passphrase
# TODO: we may need to do something about the plymouth
echo "CRYPTTAB_KEY=$CRYPTTAB_KEY" >&2
echo "CRYPTTAB_OPTION_keyfile_offset=$CRYPTTAB_OPTION_keyfile_offset" >&2
#set your offset and file size here if your system does not support those paramters
#CRYPTTAB_OPTION_keyfile_offset=
#CRYPTTAB_OPTION_keyfile_size=
echo "timeout=$CRYPTTAB_OPTION_keyfile_timeout" >&2
CRYPTTAB_OPTION_keyfile_timeout=10 # keyfile-timeout is not supported yet
pass=$(/lib/cryptsetup/scripts/passdev $CRYPTTAB_KEY)
rc=$?
if ! [ $rc -eq 0 ]; then
echo "Can't find $CRYPTTAB_KEY; USB stick not present?" >&2
/lib/cryptsetup/askpass "Unlocking the disk $CRYPTTAB_SOURCE ($CRYPTTAB_NAME) Enter passphrase: "
else
echo "successfully load passphrase." >&2
echo -n $pass
fi
The hook tell update-initramfs to copy our scripts.
#!/bin/sh
PREREQ=""
prereqs() {
echo "$PREREQ"
}
case "$1" in
prereqs)
prereqs
exit 0
;;
esac
. "${CONFDIR}/initramfs.conf"
. /usr/share/initramfs-tools/hook-functions
copy_exec /bin/passphrase-from-usbfs.sh
copy_exec /bin/passphrase-from-usb.sh
#when using passdev we need to hook additionaly FS and binary
copy_exec /lib/cryptsetup/scripts/passdev
manual_add_modules ext4 ext3 ext2 vfat btrfs reiserfs xfs jfs ntfs iso9660 udf
Finally I posted the updated version of passphrase-from-usb.sh which can use the new parameters in crypttab: