How to setup passwordless disk encryption in Debian Etch
tl;dr
This article is really old; if you’re looking for general principles, fine. If you’re looking for specific solutions, you might have some luck towards the end of the page.
Introduction
Recently A long time ago I’ve installed Debian 4.0 (Etch) with
disk encryption to protect my data. However the password entry
at boot is quite tiresome after couple of days.
Fortunately, there’s a better way!
I took some inspiration in System encryption on Debian Etch article and decided to do it the “initramfs-tools way”. Because I don’t like the idea of installing yet another mkinitrd front-end AND the article on DA seems a bit dated. :-)
Prerequisites
You’ll need your Etch installation with encrypted partition that’s being setup at boot time via initramfs-tools. This is easy – it’s what you end up with when you select “encrypted filesystem” option during installation.
You’ll also need to have at least moderate understanding of how to operate shell and you absolutely HAVE TO backup your data, because if something goes wrong, you might very well end up with system you can’t get into anymore. Which is not cool situation without backup.
(OK, I know you’ll skip backing up your data because you’re lazy and/or you think you know better. Well, I had to remind you about the backup to protect myself from hate-mail. Don’t come to me crying you nuked your system.)
Part One - adding password file to LUKS
First you have to determine which partition is encrypted – you can do that by inspecting contents of /etc/crypttab:
$ cat /etc/crypttab
sda5_crypt /dev/sda5 none luks
So, we have sda5 encrypted. Good to know.
Now, we need to generate key file which we’ll name root.key (for instance):
$ head -c 2880 /dev/urandom | uuencode -m - | head -n 65 | \
tail -n 64 > root.key
If the command sequence fails for any reason, you don’t have sharutils installed. Fix that via:
$ apt-get install sharutils
and retry the previous password file generation one-liner.
You should end up with something like this:
$ wc -l root.key
64 root.key
$ head -n 3 root.key
9iDTzZlOy6P44YnoW7etVwVK7Xjj6SCvRNUkpTUPy1KjvQ3IsF8Q4hQ+Yda6
5XkXGJC8ylvAqc1ZvLMLEhIb2L73O90WCZhoj3GUkvTeohHDWLguBl23k1AX
wfVtPDZre3gpPuHhZNb3vOFzwjihfR2yMxykp6uuXjFlWLK4JNc4TLgRSWIq
Now we need to add the key file to that partition key pool:
$ cryptsetup luksAddKey /dev/sda5 root.key
You will be asked for password, which is the boot-up password you’ve been using so far.
Cool. Now we have the password file registered as a valid key, so we just copy it over to USB stick and go about changing initramfs-tools setup.
Part Two - setting up (known) safe boot option
We should make backup of existing initrd before attempting to tinker with the boot setup. Here’s how:
Go to “/boot” and copy existing initrd image with -safe extension, to have known good copy.
In my case it looks like this:
$ cd /boot/
$ ls -1 init*
initrd.img-2.6.18-5-amd64
initrd.img-2.6.18-5-amd64.bak
$ cp initrd.img-2.6.18-5-amd64 initrd.img-2.6.18-5-amd64-safe
Now we need to add the safe option to Grub (or your favorite boot manager).
Open /boot/grub/menu.lst, locate the kernel you’re booting into, copy that block under the “END DEBIAN AUTOMAGIC KERNELS LIST” line.
Change “initrd” definition by adding “-safe” at the end and change “title” to indicate it’s your safe option.
In my case the end of /boot/grub/menu.lst now looks like this:
$ tail -n 7 /boot/grub/menu.lst
### END DEBIAN AUTOMAGIC KERNELS LIST
title Debian GNU/Linux, kernel 2.6.18-5-amd64 (safe version)
root (hd0,0)
kernel /vmlinuz-2.6.18-5-amd64 root=/dev/mapper/vg-root ro
initrd /initrd.img-2.6.18-5-amd64-safe
savedefault
and I’ve created that from boot option that looked like this:
title Debian GNU/Linux, kernel 2.6.18-5-amd64
root (hd0,0)
kernel /vmlinuz-2.6.18-5-amd64 root=/dev/mapper/vg-root ro
initrd /initrd.img-2.6.18-5-amd64
savedefault
Part Three - making our boot process run passwordless
So, now we need to make few adjustments to make it all work.
First we need to add couple of modules to be loaded to the ramdisk:
$ echo -e "vfat\nfat\nnls_cp437\nnls_iso8859_1" \
>> /etc/initramfs-tools/modules
because I assume you have your USB keychain with FAT filesystem and therefore
you need vfat
, fat
, nls_cp437
, and nls_iso8859_1
modules to mount it.
Next we need to change /etc/crypttab
to accept our custom keyscript
with proper key file. Mine looks like this, after the modification:
$ cat /etc/crypttab
sda5_crypt /dev/sda5 root.key luks,keyscript=/usr/local/sbin/crypto-usb-key.sh
So I’ve changed the key
option from none
to root.key
(which is the name
of our pwfile) and added keyscript
option which says to the init scripts to
run that script in order to get password.
So far so good.
Now we need the keyscript… add this:
#!/bin/sh
# Part of passwordless cryptofs setup in Debian Etch.
# See: https://wejn.org/how-to-make-passwordless-cryptsetup.html
# Author: Wejn <wejn at box dot cz>
if [ "x$1" = "x" -o "x$1" = "xnone" ]; then
KEYF=root.key
else
KEYF=$1
fi
MD=/tmp-usb-mount
echo "Trying to get the key from USB keychain ..." >&2
mkdir -p $MD
modprobe usb-storage >/dev/null 2>&1
modprobe vfat >/dev/null 2>&1
sleep 7
OPENED=0
for SFS in /sys/block/sd*; do
DEV=`basename $SFS`
F=$SFS/${DEV}1/dev
if [ 0`cat $SFS/removable` -eq 1 -a -f $F ]; then
echo "> Trying device: $DEV ..." >&2
mount /dev/${DEV}1 $MD -t vfat -o ro 2>/dev/null
if [ -f $MD/$KEYF ]; then
cat $MD/$KEYF
umount $MD 2>/dev/null
OPENED=1
break
fi
umount $MD 2>/dev/null
fi
done
if [ $OPENED -eq 0 ]; then
echo "FAILED to find suitable USB keychain ..." >&2
echo -n "Try to enter your password: " >&2
read -s -r A
echo -n "$A"
else
echo "Success loading keyfile from the keychain!" >&2
fi
as /usr/local/sbin/crypto-usb-key.sh
and chmod it a+x …
You can download the file here if you’re not comfortable copy&pasting it.
Finishing line! All you need to do now is to update your initrd:
$ update-initramfs -u all
update-initramfs: Generating /boot/initrd.img-2.6.18-5-amd64
and you’re ready to reboot! :-)
Conclusion
It ain’t that hard to get to passwordless cryptofs setup in Etch, as you can see.
This document describes the whole process in reasonable detail, even though it doesn’t explain all the details WHY it’s done that way.
Anyway, if you have comments / improvements, feel free to contact me at: wejn at box dot cz.
Please use reasonable Subject line so I don’t mistake your email for spam.
Update: Password file generation concern
I’ve received email from Paul Walker asking me about the method used for password generation. He was concerned that using base64 on the /dev/urandom input (see part one) we might end up limiting the password strength by one third (in case the cryptsetup was limiting size of the password material).
Well, it took me a while to figure out how the password handling works with LUKS, but here’s the result of my research:
The password handling in LUKS is done with a help of hashing function and the input stream (file) is read in its entirety, see “NOTES ON PASSWORD PROCESSING FOR LUKS” section in cryptsetup manual.
The actual protocol used is PBKDF2, which is some “password-based key derivation function”, see Wikipedia’s PBKDF2 page for details.
As a conclusion, it’s perfectly safe to use any file you like, even the uuencoded one based on the recipe I have copied from the Debian Administration article referenced above.
But Paul is right, the uuencode is superfluous and simple:
head -c 256 /dev/urandom > root.key
will do just as well. You might even increase the number of characters taken from /dev/urandom and/or switch to /dev/random, if you’re really paranoid.
The only difference might be if you’re planning on printing the contents of your root.key to put it in a high-security vault for backup purposes. In that case having the file uuencoded helps a bit.
But that’s not a likely scenario… :-)
Anyway, thanks Paul for bringing it up!
Update: Using crypto-usb-key.sh with multiple devices
I’ve received email from Kix (Rodolfo Garcia) regarding problems with using my keyscript with multiple devices. The thing is that my keyscript attempts to load the kernel modules and waits for 7 seconds prior looking for the keyfile(s).
For encrypted root that is desired feature. Not so when you have more
partitions you want to auto-setup. Because in this case the sleep 7
gets annoying.
Anyway, Kix came up with modified version of the crypto-usb-key.sh
script:
Script (click to expand)
#!/bin/sh
# Part of passwordless cryptofs setup in Debian Etch.
# See: https://wejn.org/how-to-make-passwordless-cryptsetup.html
# Author: Wejn <wejn at box dot cz>
#
# Updated by Rodolfo Garcia (kix) <kix at kix dot com>
# For multiple partitions
# https://www.kix.es/
# USB Disk partition type (ext2 or vfat)
PARTTYPE=ext2
# Key file in the USB disk
KEYFILE=.key
# # # # # CODE # # # # #
MD=/tmp-usb-mount
if [ "x$1" = "x" -o "x$1" = "xnone" ]; then
KEYF=$KEYFILE
else
KEYF=$1
fi
USBLOAD=0
FSLOAD=0
cat /proc/modules | busybox grep usb_storage >/dev/null 2>&1
USBLOAD=$?
cat /proc/modules | busybox grep $PARTTYPE >/dev/null 2>&1
FSLOAD=$?
if [ $USBLOAD -gt 0 ] || [ $FSLOAD -gt 0 ]; then
modprobe usb_storage >/dev/null 2>&1
modprobe $PARTTYPE >/dev/null 2>&1
sleep 7
fi
OPENED=0
ls -d /sys/block/sd* >/dev/null 2>&1
SDS=$?
if [ $SDS -eq 0 ]; then
echo "Trying to get the key from USB keychain ..." >&2
mkdir -p $MD
for SFS in /sys/block/sd*; do
DEV=`busybox basename $SFS`
F=$SFS/${DEV}1/dev
if [ 0`cat $SFS/removable` -eq 1 -a -f $F ]; then
echo "> Trying device: $DEV ..." >&2
mount /dev/${DEV}1 $MD -t ext2 -o ro 2>/dev/null
if [ -f $MD/$KEYF ]; then
cat $MD/$KEYF
umount $MD 2>/dev/null
OPENED=1
break
fi
umount $MD 2>/dev/null
fi
done
fi
if [ $OPENED -eq 0 ]; then
echo "FAILED to find suitable USB keychain ..." >&2
echo -n "Try to enter your password: " >&2
read -s -r A </dev/console
echo -n "$A"
else
echo "Success loading keyfile from the keychain!" >&2
fi
In addition to fixing the module loading and delay it also allows you to configure partition type (for example ext2) and name of the default key file.
Nice work.
You might also note that instead of this script you might store keys for additional partitions on your (encrypted) root filesystem (in /etc, for instance) and use simple one-line keyscript like this one below:
Script (click to expand)
#!/bin/bash
## /etc/swap.cryptokey should be owned by root:root with perms: 0600
exec cat /etc/swap.cryptokey
The choice is yours, either way will work just fine.
Update: Loading keyfile from SD card
Cromwel managed (after a bit of tinkering) to get the keyscript working with his internal Ricoh SD card reader and SD-HC card.
#!/bin/sh
# Part of passwordless cryptofs setup in Debian Etch.
# See: https://wejn.org/how-to-make-passwordless-cryptsetup.html
# Author: Wejn <wejn at box dot cz>
#
# Updated by Rodolfo Garcia (kix) <kix at kix dot com>
# For multiple partitions
# http://www.kix.es/
#
# Updated by Cromwel Flores <cromwel dot flores at gmail dot com>
# For MMC/SD card
# Disk partition type (ext2 or vfat)
PARTTYPE=vfat
# Key file in the disk
KEYFILE=root.key
# # # # # CODE # # # # #
MD=/tmp-mount
if [ "x$1" = "x" -o "x$1" = "xnone" ]; then
KEYF=$KEYFILE
else
KEYF=$1
fi
USBLOAD=0
FSLOAD=0
MMCLOAD=0
cat /proc/modules | busybox grep usb_storage >/dev/null 2>&1
USBLOAD=$?
cat /proc/modules | busybox grep $PARTTYPE >/dev/null 2>&1
FSLOAD=$?
cat /proc/modules | busybox grep mmc >/dev/null 2>&1
MMCLOAD=$?
#Check if all the required modules have been already loaded
if [ $USBLOAD -gt 0 ] || [ $FSLOAD -gt 0 ] || [ $MMCLOAD -gt 0 ]; then
modprobe usb_storage
modprobe mmc_core
modprobe ricoh_mmc
modprobe mmc_block
modprobe sdhci
modprobe $PARTTYPE
fi
OPENED=0
ls -d /sys/block/sd* >/dev/null 2>&1
SDS=$?
if [ $SDS -eq 0 ]; then
echo "Trying to get the keyfile from physical keychain ..." >&2
mkdir -p $MD
# Try getting file from SD Card
echo "> Looking for keyfile in SD Card ..." >&2
mount /dev/mmcblk0p1 $MD -t $PARTTYPE -o ro 2>/dev/null
if [ -f $MD/$KEYF ]; then
cat $MD/$KEYF
umount $MD 2>/dev/null
OPENED=1
else
echo "> Could not find keyfile in SD Card ..." >&2
fi
umount $MD 2>/dev/null
# Try getting file from USB Device
if [ $OPENED -eq 0 ]; then
echo "> Now looking for keyfile in USB disk(s)..." >&2
# Sleep to allow USB drive to be recognised
sleep 7
for SFS in /sys/block/sd*; do
DEV=`busybox basename $SFS`
F=$SFS/${DEV}1/dev
if [ 0`cat $SFS/removable` -eq 1 -a -f $F ]; then
echo "> Trying device: $DEV ..." >&2
mount /dev/${DEV}1 $MD -t $PARTTYPE -o ro 2>/dev/null
if [ -f $MD/$KEYF ]; then
cat $MD/$KEYF
umount $MD 2>/dev/null
OPENED=1
break
fi
umount $MD 2>/dev/null
fi
done
fi
fi
# Could not read from physical token. So ask manual input for passphrase.
# read -s -r PASSPHRASE </dev/console does not display input.
if [ $OPENED -eq 0 ]; then
echo "> FAILED to find keyfile from a physical keychain ..." >&2
echo -n "Try to enter your passphrase: " >&2
read -s -r PASSPHRASE </dev/console
echo -n "$PASSPHRASE"
echo -e "\n> Attempting to use provided passphrase ..." >&2
else
echo "Success loading keyfile from the keychain!" >&2
fi
Update: Vast improvements to keyscript
TJ sent me link to his updated version of keyscript. Improvements include:
- Works with Ubuntu 8.04 Hardy
- Detects and uses usplash or console for messages
- Automatic detection of USB devices
- Detection and examination of all partitions on the device (not just partition #1)
- Automatic detection of partition type
- Refactored the code
- Added optional debugging code
- Added comments
You can find this version at archive.org’s dump of his site in article titled Hardy RAID-5 Encrypted with Logical Volume Management.
The script itself:
Script (click to expand)
#!/bin/sh
# Part of passwordless cryptofs setup in Debian Etch.
# See: https://wejn.org/how-to-make-passwordless-cryptsetup.html
# Author: Wejn <wejn at box dot cz>
#
# Updated by Rodolfo Garcia (kix) <kix at kix dot com>
# For multiple partitions
# http://www.kix.es/
#
# Updated by TJ <linux@tjworld.net> 7 July 2008
# For use with Ubuntu Hardy, usplash, automatic detection of USB devices,
# detection and examination of *all* partitions on the device (not just partition #1),
# automatic detection of partition type, refactored, commented, debugging code.
# define counter-intuitive shell logic values (based on /bin/true & /bin/false)
TRUE=0
FALSE=1
# set DEBUG=$TRUE to display debug messages, DEBUG=$FALSE to be quiet
DEBUG=$FALSE
# is usplash available? default false
USPLASH=$FALSE
if [ -f /sbin/usplash_write ]; then
# use innocuous command to determine if usplash is running
# usplash_write will return exit-code 1 if usplash isn't running
# need to set a flag to tell usplash_write to report no usplash
FAIL_NO_USPLASH=1
#enable verbose messages (required to display messages if kernel boot option "quiet" is enabled
/sbin/usplash_write "VERBOSE on"
if [ $? -eq $TRUE ]; then
# usplash is running
USPLASH=$TRUE
/sbin/usplash_write "CLEAR"
fi
fi
# print message to usplash or stderr
# usage: msg <command> "message" [switch]
# command: TEXT | STATUS | SUCCESS | FAILURE | CLEAR (see 'man usplash_write' for all commands)
# switch : switch used for echo to stderr (ignored for usplash)
# when using usplash the command will cause "message" to be
# printed according to the usplash <command> definition.
# using the switch -n will allow echo to write multiple messages
# to the same line
msg ()
{
if [ $# -gt 0 ]; then
# handle multi-line messages
echo $2 | while read LINE; do
if [ $USPLASH -eq $TRUE ]; then
# use usplash
/sbin/usplash_write "$1 $LINE"
else
# use stderr for all messages
echo $3 "$2" >&2
fi
done
fi
}
[ $DEBUG -eq $TRUE ] && msg STATUS "Executing crypto-usb-key.sh ..."
# flag tracking key-file availability
OPENED=$FALSE
# temporary mount path for USB key
MD=/tmp-usb-mount
if [ "x$1" = "x" -o "x$1" = "xnone" ]; then
# default key-file on the USB disk
KEYFILE=.key
else
KEYFILE=$1
fi
# Is the USB driver loaded?
cat /proc/modules | busybox grep usb_storage >/dev/null 2>&1
USBLOAD=0$?
if [ $USBLOAD -gt 0 ]; then
[ $DEBUG -eq $TRUE ] && msg TEXT "Loading driver 'usb_storage'"
modprobe usb_storage >/dev/null 2>&1
fi
# give the system time to settle and open the USB devices
sleep 7
# Are there any SCSI block devices?
ls -d /sys/block/sd* >/dev/null 2>&1
SBD=$?
if [ $SBD -eq $TRUE ]; then
mkdir -p $MD
[ $DEBUG -eq $TRUE ] && msg TEXT "Trying to get key-file '$KEYFILE' ..."
for SFS in /sys/block/sd*/sd??; do
[ $DEBUG -eq $TRUE ] && msg TEXT "Examining $SFS" -n
# is it a USB device?
ls -l ${SFS}/../device | busybox grep 'usb' >/dev/null 2>&1
USB=0$?
[ $DEBUG -eq $TRUE ] && msg TEXT ", USB=$USB" -n
# Is the device removable?
REMOVABLE=0`cat ${SFS}/../removable`
[ $DEBUG -eq $TRUE ] && msg TEXT ", REMOVABLE=$REMOVABLE" -n
if [ $USB -eq $TRUE -a $REMOVABLE -eq 1 -a -f $SFS/dev ]; then
[ $DEBUG -eq $TRUE ] && msg TEXT ", *possible key device*" -n
DEV=`busybox basename $SFS`
[ $DEBUG -eq $TRUE ] && msg TEXT ", device $DEV" -n
# No access to /sbin/vol_id so query the UDEV database directly
# to get the file-system label
LABEL=" (`cat /dev/.udev/db/*${DEV} | busybox sed -n 's/.*ID_FS_LABEL_SAFE=\(.*\)/\1/p'`) "
[ $DEBUG -eq $TRUE ] && msg TEXT ", label $LABEL" -n
# No access to /sbin/vol_id and /bin/fstype reports vfat/msdos/ntfs as 'unknown', so
# query the UDEV database directly to get the file-system type
FSTYPE=`cat /dev/.udev/db/*${DEV} | busybox sed -n 's/.*ID_FS_TYPE=\(.*\)/\1/p'`
[ $DEBUG -eq $TRUE ] && msg TEXT ", fstype $FSTYPE" -n
# Is the file-system driver loaded?
cat /proc/modules | busybox grep $FSTYPE >/dev/null 2>&1
FSLOAD=0$?
if [ $FSLOAD -gt 0 ]; then
[ $DEBUG -eq $TRUE ] && msg TEXT ", loading driver for $FSTYPE" -n
# load the correct file-system driver
modprobe $FSTYPE >/dev/null 2>&1
fi
[ $DEBUG -eq $TRUE ] && msg TEXT ", mounting /dev/$DEV on $MD" -n
mount /dev/${DEV} $MD -t $FSTYPE -o ro 2>/dev/null
[ $DEBUG -eq $TRUE ] && msg TEXT ", (`mount | busybox grep $DEV`)" -n
if [ -f $MD/$KEYFILE ]; then
[ $DEBUG -eq $TRUE ] && msg TEXT ", found $MD/$KEYFILE" -n
cat $MD/$KEYFILE
[ $DEBUG -eq $TRUE ] && msg TEXT ", umount $MD"
umount $MD 2>/dev/null
OPENED=$TRUE
break
fi
[ $DEBUG -eq $TRUE ] && msg TEXT ", umount $MD" -n
umount $MD 2>/dev/null
[ $DEBUG -eq $TRUE ] && msg TEXT ", done\n\n" -n
else
[ $DEBUG -eq $TRUE ] && msg TEXT ", device `busybox basename $SFS` ignored" -n
fi
[ $DEBUG -eq $TRUE ] && msg CLEAR ""
done
fi
# clear existing usplash text and status messages
[ $USPLASH -eq $TRUE ] && msg STATUS " " && msg CLEAR ""
if [ $OPENED -eq $FALSE ]; then
msg TEXT "FAILED to find suitable USB key-file ..."
msg TEXT "Try to enter the LUKS password: "
read -s -r A </dev/console
echo -n "$A"
else
msg TEXT "Success loading key-file from $DEV $LABEL"
fi
#
[ $USPLASH -eq $TRUE ] && /sbin/usplash_write "VERBOSE default"
Thanks, TJ!
Update: Yet another improvements to keyscript by TJ
TJ made some improvements to his keyscript (thanks!):
As a result of some feedback it seems there is a minor bug in the script where the fallback to ‘read -s …’ a password fails since /bin/sh doesn’t support “-s” (silent) although bash does.
Also, I’ve added additional preliminary logic that checks for the existence of the key-file before doing the USB mounting.
This is so the script will work with crypto-volumes that have their key-file stored in the initial crypto-root. Once the root is mounted they become available and the script should use them rather than fail and prompt for a password.
This also avoids the user needing to have two different crypto scripts, one for root and the other for ‘later’ early-crypto disks.
Script (click to expand)
#!/bin/sh
# Part of passwordless cryptofs setup in Debian Etch.
# See: https://wejn.org/how-to-make-passwordless-cryptsetup.html
# Author: Wejn <wejn at box dot cz>
#
# Updated by Rodolfo Garcia (kix) <kix at kix dot com>
# For multiple partitions
# http://www.kix.es/
#
# Updated by TJ <linux@tjworld.net> 7 July 2008
# For use with Ubuntu Hardy, usplash, automatic detection of USB devices,
# detection and examination of *all* partitions on the device (not just partition #1),
# automatic detection of partition type, refactored, commented, debugging code.
# define counter-intuitive shell logic values (based on /bin/true & /bin/false)
TRUE=0
FALSE=1
# set DEBUG=$TRUE to display debug messages, DEBUG=$FALSE to be quiet
DEBUG=$FALSE
# is usplash available? default false
USPLASH=$FALSE
if [ -f /sbin/usplash_write ]; then
# use innocuous command to determine if usplash is running
# usplash_write will return exit-code 1 if usplash isn't running
# need to set a flag to tell usplash_write to report no usplash
FAIL_NO_USPLASH=1
#enable verbose messages (required to display messages if kernel boot option "quiet" is enabled
/sbin/usplash_write "VERBOSE on"
if [ $? -eq $TRUE ]; then
# usplash is running
USPLASH=$TRUE
/sbin/usplash_write "CLEAR"
fi
fi
# print message to usplash or stderr
# usage: msg <command> "message" [switch]
# command: TEXT | STATUS | SUCCESS | FAILURE | CLEAR (see 'man usplash_write' for all commands)
# switch : switch used for echo to stderr (ignored for usplash)
# when using usplash the command will cause "message" to be
# printed according to the usplash <command> definition.
# using the switch -n will allow echo to write multiple messages
# to the same line
msg ()
{
if [ $# -gt 0 ]; then
# handle multi-line messages
echo $2 | while read LINE; do
if [ $USPLASH -eq $TRUE ]; then
# use usplash
/sbin/usplash_write "$1 $LINE"
else
# use stderr for all messages
echo $3 "$2" >&2
fi
done
fi
}
[ $DEBUG -eq $TRUE ] && msg STATUS "Executing crypto-usb-key.sh ..."
# flag tracking key-file availability
OPENED=$FALSE
# temporary mount path for USB key
MD=/tmp-usb-mount
if [ "x$1" = "x" -o "x$1" = "xnone" ]; then
# default key-file on the USB disk
KEYFILE=.key
else
KEYFILE=$1
fi
# If the file already exists use it.
# This is useful where an encrypted volume contains keyfile(s) for later
# volumes and is now mounted and accessible
if [ -f $KEYFILE ]; then
[ $DEBUG -eq $TRUE ] && msg TEXT "Found $KEYFILE"
cat $KEYFILE
OPENED=$TRUE
DEV="existing mount"
LABEL=""
else
# Is the USB driver loaded?
cat /proc/modules | busybox grep usb_storage >/dev/null 2>&1
USBLOAD=0$?
if [ $USBLOAD -gt 0 ]; then
[ $DEBUG -eq $TRUE ] && msg TEXT "Loading driver 'usb_storage'"
modprobe usb_storage >/dev/null 2>&1
fi
# give the system time to settle and open the USB devices
sleep 7
# Are there any SCSI block devices?
ls -d /sys/block/sd* >/dev/null 2>&1
SBD=$?
if [ $SBD -eq $TRUE ]; then
mkdir -p $MD
[ $DEBUG -eq $TRUE ] && msg TEXT "Trying to get key-file '$KEYFILE' ..."
for SFS in /sys/block/sd*/sd??; do
[ $DEBUG -eq $TRUE ] && msg TEXT "Examining $SFS" -n
# is it a USB device?
ls -l ${SFS}/../device | busybox grep 'usb' >/dev/null 2>&1
USB=0$?
[ $DEBUG -eq $TRUE ] && msg TEXT ", USB=$USB" -n
# Is the device removable?
REMOVABLE=0`cat ${SFS}/../removable`
[ $DEBUG -eq $TRUE ] && msg TEXT ", REMOVABLE=$REMOVABLE" -n
if [ $USB -eq $TRUE -a $REMOVABLE -eq 1 -a -f $SFS/dev ]; then
[ $DEBUG -eq $TRUE ] && msg TEXT ", *possible key device*" -n
DEV=`busybox basename $SFS`
[ $DEBUG -eq $TRUE ] && msg TEXT ", device $DEV" -n
# No access to /sbin/vol_id so query the UDEV database directly
# to get the file-system label
LABEL=" (`cat /dev/.udev/db/*${DEV} | busybox sed -n 's/.*ID_FS_LABEL_SAFE=\(.*\)/\1/p'`) "
[ $DEBUG -eq $TRUE ] && msg TEXT ", label $LABEL" -n
# No access to /sbin/vol_id and /bin/fstype reports vfat/msdos/ntfs as 'unknown', so
# query the UDEV database directly to get the file-system type
FSTYPE=`cat /dev/.udev/db/*${DEV} | busybox sed -n 's/.*ID_FS_TYPE=\(.*\)/\1/p'`
[ $DEBUG -eq $TRUE ] && msg TEXT ", fstype $FSTYPE" -n
# Is the file-system driver loaded?
cat /proc/modules | busybox grep $FSTYPE >/dev/null 2>&1
FSLOAD=0$?
if [ $FSLOAD -gt 0 ]; then
[ $DEBUG -eq $TRUE ] && msg TEXT ", loading driver for $FSTYPE" -n
# load the correct file-system driver
modprobe $FSTYPE >/dev/null 2>&1
fi
[ $DEBUG -eq $TRUE ] && msg TEXT ", mounting /dev/$DEV on $MD" -n
mount /dev/${DEV} $MD -t $FSTYPE -o ro 2>/dev/null
[ $DEBUG -eq $TRUE ] && msg TEXT ", (`mount | busybox grep $DEV`)" -n
if [ -f $MD/$KEYFILE ]; then
[ $DEBUG -eq $TRUE ] && msg TEXT ", found $MD/$KEYFILE" -n
cat $MD/$KEYFILE
[ $DEBUG -eq $TRUE ] && msg TEXT ", umount $MD"
umount $MD 2>/dev/null
OPENED=$TRUE
break
fi
[ $DEBUG -eq $TRUE ] && msg TEXT ", umount $MD" -n
umount $MD 2>/dev/null
[ $DEBUG -eq $TRUE ] && msg TEXT ", done\n\n" -n
else
[ $DEBUG -eq $TRUE ] && msg TEXT ", device `busybox basename $SFS` ignored" -n
fi
[ $DEBUG -eq $TRUE ] && msg CLEAR ""
done
fi
fi
# clear existing usplash text and status messages
[ $USPLASH -eq $TRUE ] && msg STATUS " " && msg CLEAR ""
if [ $OPENED -eq $FALSE ]; then
msg TEXT "FAILED to find suitable USB key-file ..."
msg TEXT "Try to enter the LUKS password: "
read -r A </dev/console >/dev/null
echo -n "$A"
else
msg TEXT "Success loading key-file from $DEV $LABEL"
fi
#
[ $USPLASH -eq $TRUE ] && /sbin/usplash_write "VERBOSE default"
Update: Improvement of TJ’s script by Hendrik
Hendrik van Antwerpen sent me his update to TJ’s keyscript, with the following improvements:
Improvements:
- supports encrypted (password protected) key devices
- password reading now uses stty (when available)
- password reading uses oficial function under usplash
- refactored debug code
Script (click to expand)
#!/bin/sh
# Part of passwordless cryptofs setup in Debian Etch.
# See: https://wejn.org/how-to-make-passwordless-cryptsetup.html
# Author: Wejn <wejn at box dot cz>
#
# Updated by Rodolfo Garcia (kix) <kix at kix dot com>
# For multiple partitions
# http://www.kix.es/
#
# Updated by TJ <linux@tjworld.net> 7 July 2008
# For use with Ubuntu Hardy, usplash, automatic detection of USB devices,
# detection and examination of *all* partitions on the device (not just partition #1),
# automatic detection of partition type, refactored, commented, debugging code.
#
# Updated by Hendrik van Antwerpen <hendrik at van-antwerpen dot net> 3 Sept 2008
# For encrypted key device support, also added stty support for not
# showing your password in console mode.
# define counter-intuitive shell logic values (based on /bin/true & /bin/false)
# NB. use FALSE only to *set* something to false, but don't test for
# equality, because a program might return any non-zero on error
TRUE=0
FALSE=1
# set DEBUG=$TRUE to display debug messages, DEBUG=$FALSE to be quiet
DEBUG=$FALSE
# is usplash available? default false
USPLASH=$FALSE
# test for outfifo from Ubuntu Hardy cryptroot script, the second test
# alone proves not completely reliable.
if [ -p /dev/.initramfs/usplash_outfifo -a -x /sbin/usplash_write ]; then
# use innocuous command to determine if usplash is running
# usplash_write will return exit-code 1 if usplash isn't running
# need to set a flag to tell usplash_write to report no usplash
FAIL_NO_USPLASH=1
# enable verbose messages (required to display messages if kernel boot option "quiet" is enabled
/sbin/usplash_write "VERBOSE on"
if [ $? -eq $TRUE ]; then
# usplash is running
USPLASH=$TRUE
/sbin/usplash_write "CLEAR"
fi
fi
# is stty available? default false
STTY=$FALSE
STTYCMD=false
# check for stty executable
if [ -x /bin/stty ]; then
STTY=$TRUE
STTYCMD=/bin/stty
elif [ `(busybox stty >/dev/null 2>&1; echo $?)` -eq $TRUE ]; then
STTY=$TRUE
STTYCMD="busybox stty"
fi
# print message to usplash or stderr
# usage: msg <command> "message" [switch]
# command: TEXT | STATUS | SUCCESS | FAILURE | CLEAR (see 'man usplash_write' for all commands)
# switch : switch used for echo to stderr (ignored for usplash)
# when using usplash the command will cause "message" to be
# printed according to the usplash <command> definition.
# using the switch -n will allow echo to write multiple messages
# to the same line
msg ()
{
if [ $# -gt 0 ]; then
# handle multi-line messages
echo $2 | while read LINE; do
if [ $USPLASH -eq $TRUE ]; then
# use usplash
/sbin/usplash_write "$1 $LINE"
else
# use stderr for all messages
echo $3 "$2" >&2
fi
done
fi
}
dbg ()
{
if [ $DEBUG -eq $TRUE ]; then
msg "$@"
fi
}
# read password from console or with usplash
# usage: readpass "prompt"
readpass ()
{
if [ $# -gt 0 ]; then
if [ $USPLASH -eq $TRUE ]; then
usplash_write "INPUTQUIET $1: "
PASS="$(cat /dev/.initramfs/usplash_outfifo)"
else
[ $STTY -ne $TRUE ] && msg TEXT "WARNING stty not found, password will be visible"
echo -n "$1" >&2
$STTYCMD -echo
read -r PASS </dev/console >/dev/null
[ $STTY -eq $TRUE ] && echo >&2
$STTYCMD echo
fi
fi
echo -n "$PASS"
}
dbg STATUS "Executing crypto-usb-key.sh ..."
# flag tracking key-file availability
OPENED=$FALSE
# temporary mount path for USB key
MD=/tmp-usb-mount
if [ "x$1" = "x" -o "x$1" = "xnone" ]; then
# default key-file on the USB disk
KEYFILE=.key
else
KEYFILE=$1
fi
# If the file already exists use it.
# This is useful where an encrypted volume contains keyfile(s) for later
# volumes and is now mounted and accessible
if [ -f $KEYFILE ]; then
dbg TEXT "Found $KEYFILE"
cat $KEYFILE
OPENED=$TRUE
DEV="existing mount"
LABEL=""
else
# Is the USB driver loaded?
cat /proc/modules | busybox grep usb_storage >/dev/null 2>&1
USBLOAD=0$?
if [ $USBLOAD -gt 0 ]; then
dbg TEXT "Loading driver 'usb_storage'"
modprobe usb_storage >/dev/null 2>&1
fi
# give the system time to settle and open the USB devices
sleep 7
# Are there any SCSI block devices?
ls -d /sys/block/sd* >/dev/null 2>&1
SBD=$?
if [ $SBD -eq $TRUE ]; then
mkdir -p $MD
dbg TEXT "Trying to get key-file '$KEYFILE' ..."
for SFS in /sys/block/sd*/sd??; do
dbg TEXT "Examining $SFS" -n
# is it a USB device?
ls -l ${SFS}/../device | busybox grep 'usb' >/dev/null 2>&1
USB=0$?
dbg TEXT ", USB=$USB" -n
# Is the device removable?
REMOVABLE=0`cat ${SFS}/../removable`
dbg TEXT ", REMOVABLE=$REMOVABLE" -n
if [ $USB -eq $TRUE -a $REMOVABLE -eq 1 -a -f $SFS/dev ]; then
dbg TEXT ", *possible key device*" -n
DEV=`busybox basename $SFS`
# Check if key device itself is encrypted
/sbin/cryptsetup isLuks /dev/${DEV} >/dev/null 2>&1
ENCRYPTED=0$?
# Open crypted partition and prepare for mount
if [ $ENCRYPTED -eq $TRUE ]; then
dbg TEXT ", encrypted device" -n
# Use vol_id to determine label
LABEL="`/lib/udev/vol_id /dev/${DEV} | busybox sed -n 's/.*ID_FS_LABEL_SAFE=\(.*\)/\1/p'`"
dbg TEXT ", label $LABEL" -n
TRIES=3
DECRYPTED=$FALSE
while [ $TRIES -gt 0 -a $DECRYPTED -ne $TRUE ]; do
TRIES=$(($TRIES-1))
PASS="`readpass \"Enter LUKS password for key device ${DEV} (${LABEL}) (or empty to skip): \"`"
if [ -z "$PASS" ]; then
dbg TEXT ", device skipped" -n
break
fi
echo $PASS | /sbin/cryptsetup luksOpen /dev/${DEV} bootkey >/dev/null 2>&1
DECRYPTED=0$?
done
# If open failed, skip this device
if [ $DECRYPTED -ne $TRUE ]; then
dbg TEXT "decrypting device failed" -n
break
fi
# Decrypted device to use
DEV=mapper/bootkey
fi
dbg TEXT ", device $DEV" -n
# Use vol_id to determine label
LABEL="`/lib/udev/vol_id /dev/${DEV} | busybox sed -n 's/.*ID_FS_LABEL_SAFE=\(.*\)/\1/p'`"
dbg TEXT ", label $LABEL" -n
# Use vol_id to determine fstype
FSTYPE="`/lib/udev/vol_id /dev/${DEV} | busybox sed -n 's/.*ID_FS_TYPE=\(.*\)/\1/p'`"
dbg TEXT ", fstype $FSTYPE" -n
# Is the file-system driver loaded?
cat /proc/modules | busybox grep $FSTYPE >/dev/null 2>&1
FSLOAD=0$?
if [ $FSLOAD -gt 0 ]; then
dbg TEXT ", loading driver for $FSTYPE" -n
# load the correct file-system driver
modprobe $FSTYPE >/dev/null 2>&1
fi
dbg TEXT ", mounting /dev/$DEV on $MD" -n
mount /dev/${DEV} $MD -t $FSTYPE -o ro >/dev/null 2>&1
dbg TEXT ", (`mount | busybox grep $DEV`)" -n
if [ -f $MD/$KEYFILE ]; then
dbg TEXT ", found $MD/$KEYFILE" -n
cat $MD/$KEYFILE
OPENED=$TRUE
fi
dbg TEXT ", umount $MD" -n
umount $MD >/dev/null 2>&1
# Close encrypted key device
if [ $ENCRYPTED -eq $TRUE -a $DECRYPTED -eq $TRUE ]; then
dbg TEXT ", closing encrypted device" -n
/sbin/cryptsetup luksClose bootkey >/dev/null 2>&1
fi
dbg TEXT ", done\n\n" -n
if [ $OPENED -eq $TRUE ]; then
break
fi
else
dbg TEXT ", device `busybox basename $SFS` ignored" -n
fi
dbg CLEAR ""
done
fi
fi
# clear existing usplash text and status messages
[ $USPLASH -eq $TRUE ] && msg STATUS " " && msg CLEAR ""
if [ $OPENED -ne $TRUE ]; then
msg TEXT "FAILED to find suitable USB key-file ..."
readpass "Try to enter the LUKS password: "
else
msg TEXT "Success loading key-file from $SFS ($LABEL)"
fi
#
[ $USPLASH -eq $TRUE ] && /sbin/usplash_write "VERBOSE default"
Thanks, Hendrik!
Oh, and in case you’re interested, here’s diff against tj’s script:
Script (click to expand)
--- tj-crypto-usb-key-20080816.sh 2008-08-16 21:25:09.000000000 +0200
+++ hendrik-crypto-usb-key.sh 2008-10-05 16:47:15.000000000 +0200
@@ -12,8 +12,14 @@
# For use with Ubuntu Hardy, usplash, automatic detection of USB devices,
# detection and examination of *all* partitions on the device (not just partition #1),
# automatic detection of partition type, refactored, commented, debugging code.
+#
+# Updated by Hendrik van Antwerpen <hendrik at van-antwerpen dot net> 3 Sept 2008
+# For encrypted key device support, also added stty support for not
+# showing your password in console mode.
# define counter-intuitive shell logic values (based on /bin/true & /bin/false)
+# NB. use FALSE only to *set* something to false, but don't test for
+# equality, because a program might return any non-zero on error
TRUE=0
FALSE=1
@@ -22,12 +28,14 @@
# is usplash available? default false
USPLASH=$FALSE
-if [ -f /sbin/usplash_write ]; then
+# test for outfifo from Ubuntu Hardy cryptroot script, the second test
+# alone proves not completely reliable.
+if [ -p /dev/.initramfs/usplash_outfifo -a -x /sbin/usplash_write ]; then
# use innocuous command to determine if usplash is running
# usplash_write will return exit-code 1 if usplash isn't running
# need to set a flag to tell usplash_write to report no usplash
FAIL_NO_USPLASH=1
- #enable verbose messages (required to display messages if kernel boot option "quiet" is enabled
+ # enable verbose messages (required to display messages if kernel boot option "quiet" is enabled
/sbin/usplash_write "VERBOSE on"
if [ $? -eq $TRUE ]; then
# usplash is running
@@ -36,6 +44,18 @@
fi
fi
+# is stty available? default false
+STTY=$FALSE
+STTYCMD=false
+# check for stty executable
+if [ -x /bin/stty ]; then
+ STTY=$TRUE
+ STTYCMD=/bin/stty
+elif [ `(busybox stty >/dev/null 2>&1; echo $?)` -eq $TRUE ]; then
+ STTY=$TRUE
+ STTYCMD="busybox stty"
+fi
+
# print message to usplash or stderr
# usage: msg <command> "message" [switch]
# command: TEXT | STATUS | SUCCESS | FAILURE | CLEAR (see 'man usplash_write' for all commands)
@@ -60,7 +80,34 @@
fi
}
-[ $DEBUG -eq $TRUE ] && msg STATUS "Executing crypto-usb-key.sh ..."
+dbg ()
+{
+ if [ $DEBUG -eq $TRUE ]; then
+ msg "$@"
+ fi
+}
+
+# read password from console or with usplash
+# usage: readpass "prompt"
+readpass ()
+{
+ if [ $# -gt 0 ]; then
+ if [ $USPLASH -eq $TRUE ]; then
+ usplash_write "INPUTQUIET $1: "
+ PASS="$(cat /dev/.initramfs/usplash_outfifo)"
+ else
+ [ $STTY -ne $TRUE ] && msg TEXT "WARNING stty not found, password will be visible"
+ echo -n "$1" >&2
+ $STTYCMD -echo
+ read -r PASS </dev/console >/dev/null
+ [ $STTY -eq $TRUE ] && echo >&2
+ $STTYCMD echo
+ fi
+ fi
+ echo -n "$PASS"
+}
+
+dbg STATUS "Executing crypto-usb-key.sh ..."
# flag tracking key-file availability
OPENED=$FALSE
@@ -79,7 +126,7 @@
# This is useful where an encrypted volume contains keyfile(s) for later
# volumes and is now mounted and accessible
if [ -f $KEYFILE ]; then
- [ $DEBUG -eq $TRUE ] && msg TEXT "Found $KEYFILE"
+ dbg TEXT "Found $KEYFILE"
cat $KEYFILE
OPENED=$TRUE
DEV="existing mount"
@@ -89,7 +136,7 @@
cat /proc/modules | busybox grep usb_storage >/dev/null 2>&1
USBLOAD=0$?
if [ $USBLOAD -gt 0 ]; then
- [ $DEBUG -eq $TRUE ] && msg TEXT "Loading driver 'usb_storage'"
+ dbg TEXT "Loading driver 'usb_storage'"
modprobe usb_storage >/dev/null 2>&1
fi
@@ -102,54 +149,86 @@
if [ $SBD -eq $TRUE ]; then
mkdir -p $MD
- [ $DEBUG -eq $TRUE ] && msg TEXT "Trying to get key-file '$KEYFILE' ..."
+ dbg TEXT "Trying to get key-file '$KEYFILE' ..."
for SFS in /sys/block/sd*/sd??; do
- [ $DEBUG -eq $TRUE ] && msg TEXT "Examining $SFS" -n
+ dbg TEXT "Examining $SFS" -n
# is it a USB device?
ls -l ${SFS}/../device | busybox grep 'usb' >/dev/null 2>&1
USB=0$?
- [ $DEBUG -eq $TRUE ] && msg TEXT ", USB=$USB" -n
+ dbg TEXT ", USB=$USB" -n
# Is the device removable?
REMOVABLE=0`cat ${SFS}/../removable`
- [ $DEBUG -eq $TRUE ] && msg TEXT ", REMOVABLE=$REMOVABLE" -n
+ dbg TEXT ", REMOVABLE=$REMOVABLE" -n
if [ $USB -eq $TRUE -a $REMOVABLE -eq 1 -a -f $SFS/dev ]; then
- [ $DEBUG -eq $TRUE ] && msg TEXT ", *possible key device*" -n
+ dbg TEXT ", *possible key device*" -n
DEV=`busybox basename $SFS`
- [ $DEBUG -eq $TRUE ] && msg TEXT ", device $DEV" -n
- # No access to /sbin/vol_id so query the UDEV database directly
- # to get the file-system label
- LABEL=" (`cat /dev/.udev/db/*${DEV} | busybox sed -n 's/.*ID_FS_LABEL_SAFE=\(.*\)/\1/p'`) "
- [ $DEBUG -eq $TRUE ] && msg TEXT ", label $LABEL" -n
- # No access to /sbin/vol_id and /bin/fstype reports vfat/msdos/ntfs as 'unknown', so
- # query the UDEV database directly to get the file-system type
- FSTYPE=`cat /dev/.udev/db/*${DEV} | busybox sed -n 's/.*ID_FS_TYPE=\(.*\)/\1/p'`
- [ $DEBUG -eq $TRUE ] && msg TEXT ", fstype $FSTYPE" -n
+ # Check if key device itself is encrypted
+ /sbin/cryptsetup isLuks /dev/${DEV} >/dev/null 2>&1
+ ENCRYPTED=0$?
+ # Open crypted partition and prepare for mount
+ if [ $ENCRYPTED -eq $TRUE ]; then
+ dbg TEXT ", encrypted device" -n
+ # Use vol_id to determine label
+ LABEL="`/lib/udev/vol_id /dev/${DEV} | busybox sed -n 's/.*ID_FS_LABEL_SAFE=\(.*\)/\1/p'`"
+ dbg TEXT ", label $LABEL" -n
+ TRIES=3
+ DECRYPTED=$FALSE
+ while [ $TRIES -gt 0 -a $DECRYPTED -ne $TRUE ]; do
+ TRIES=$(($TRIES-1))
+ PASS="`readpass \"Enter LUKS password for key device ${DEV} (${LABEL}) (or empty to skip): \"`"
+ if [ -z "$PASS" ]; then
+ dbg TEXT ", device skipped" -n
+ break
+ fi
+ echo $PASS | /sbin/cryptsetup luksOpen /dev/${DEV} bootkey >/dev/null 2>&1
+ DECRYPTED=0$?
+ done
+ # If open failed, skip this device
+ if [ $DECRYPTED -ne $TRUE ]; then
+ dbg TEXT "decrypting device failed" -n
+ break
+ fi
+ # Decrypted device to use
+ DEV=mapper/bootkey
+ fi
+ dbg TEXT ", device $DEV" -n
+ # Use vol_id to determine label
+ LABEL="`/lib/udev/vol_id /dev/${DEV} | busybox sed -n 's/.*ID_FS_LABEL_SAFE=\(.*\)/\1/p'`"
+ dbg TEXT ", label $LABEL" -n
+ # Use vol_id to determine fstype
+ FSTYPE="`/lib/udev/vol_id /dev/${DEV} | busybox sed -n 's/.*ID_FS_TYPE=\(.*\)/\1/p'`"
+ dbg TEXT ", fstype $FSTYPE" -n
# Is the file-system driver loaded?
cat /proc/modules | busybox grep $FSTYPE >/dev/null 2>&1
FSLOAD=0$?
if [ $FSLOAD -gt 0 ]; then
- [ $DEBUG -eq $TRUE ] && msg TEXT ", loading driver for $FSTYPE" -n
+ dbg TEXT ", loading driver for $FSTYPE" -n
# load the correct file-system driver
modprobe $FSTYPE >/dev/null 2>&1
fi
- [ $DEBUG -eq $TRUE ] && msg TEXT ", mounting /dev/$DEV on $MD" -n
- mount /dev/${DEV} $MD -t $FSTYPE -o ro 2>/dev/null
- [ $DEBUG -eq $TRUE ] && msg TEXT ", (`mount | busybox grep $DEV`)" -n
+ dbg TEXT ", mounting /dev/$DEV on $MD" -n
+ mount /dev/${DEV} $MD -t $FSTYPE -o ro >/dev/null 2>&1
+ dbg TEXT ", (`mount | busybox grep $DEV`)" -n
if [ -f $MD/$KEYFILE ]; then
- [ $DEBUG -eq $TRUE ] && msg TEXT ", found $MD/$KEYFILE" -n
+ dbg TEXT ", found $MD/$KEYFILE" -n
cat $MD/$KEYFILE
- [ $DEBUG -eq $TRUE ] && msg TEXT ", umount $MD"
- umount $MD 2>/dev/null
OPENED=$TRUE
+ fi
+ dbg TEXT ", umount $MD" -n
+ umount $MD >/dev/null 2>&1
+ # Close encrypted key device
+ if [ $ENCRYPTED -eq $TRUE -a $DECRYPTED -eq $TRUE ]; then
+ dbg TEXT ", closing encrypted device" -n
+ /sbin/cryptsetup luksClose bootkey >/dev/null 2>&1
+ fi
+ dbg TEXT ", done\n\n" -n
+ if [ $OPENED -eq $TRUE ]; then
break
fi
- [ $DEBUG -eq $TRUE ] && msg TEXT ", umount $MD" -n
- umount $MD 2>/dev/null
- [ $DEBUG -eq $TRUE ] && msg TEXT ", done\n\n" -n
else
- [ $DEBUG -eq $TRUE ] && msg TEXT ", device `busybox basename $SFS` ignored" -n
+ dbg TEXT ", device `busybox basename $SFS` ignored" -n
fi
- [ $DEBUG -eq $TRUE ] && msg CLEAR ""
+ dbg CLEAR ""
done
fi
fi
@@ -157,13 +236,11 @@
# clear existing usplash text and status messages
[ $USPLASH -eq $TRUE ] && msg STATUS " " && msg CLEAR ""
-if [ $OPENED -eq $FALSE ]; then
+if [ $OPENED -ne $TRUE ]; then
msg TEXT "FAILED to find suitable USB key-file ..."
- msg TEXT "Try to enter the LUKS password: "
- read -r A </dev/console >/dev/null
- echo -n "$A"
+ readpass "Try to enter the LUKS password: "
else
- msg TEXT "Success loading key-file from $DEV $LABEL"
+ msg TEXT "Success loading key-file from $SFS ($LABEL)"
fi
#
Update: Keith’s improvement of Hendrik’s script for old PCs
Keith Beckman sent me his update to Hendrik’s script:
Script (click to expand)
#!/bin/sh
# Part of passwordless cryptofs setup in Debian Etch.
# See: https://wejn.org/how-to-make-passwordless-cryptsetup.html
# Author: Wejn <wejn at box dot cz>
#
# Updated by Rodolfo Garcia (kix) <kix at kix dot com>
# For multiple partitions
# http://www.kix.es/
#
# Updated by TJ <linux@tjworld.net> 7 July 2008
# For use with Ubuntu Hardy, usplash, automatic detection of USB devices,
# detection and examination of *all* partitions on the device (not just partition #1),
# automatic detection of partition type, refactored, commented, debugging code.
#
# Updated by Hendrik van Antwerpen <hendrik at van-antwerpen dot net> 3 Sept 2008
# For encrypted key device support, also added stty support for not
# showing your password in console mode.
# define counter-intuitive shell logic values (based on /bin/true & /bin/false)
# NB. use FALSE only to *set* something to false, but don't test for
# equality, because a program might return any non-zero on error
TRUE=0
FALSE=1
# set DEBUG=$TRUE to display debug messages, DEBUG=$FALSE to be quiet
DEBUG=$FALSE
# is usplash available? default false
USPLASH=$FALSE
# test for outfifo from Ubuntu Hardy cryptroot script, the second test
# alone proves not completely reliable.
if [ -p /dev/.initramfs/usplash_outfifo -a -x /sbin/usplash_write ]; then
# use innocuous command to determine if usplash is running
# usplash_write will return exit-code 1 if usplash isn't running
# need to set a flag to tell usplash_write to report no usplash
FAIL_NO_USPLASH=1
# enable verbose messages (required to display messages if kernel boot option "quiet" is enabled
/sbin/usplash_write "VERBOSE on"
if [ $? -eq $TRUE ]; then
# usplash is running
USPLASH=$TRUE
/sbin/usplash_write "CLEAR"
fi
fi
# is stty available? default false
STTY=$FALSE
STTYCMD=false
# check for stty executable
if [ -x /bin/stty ]; then
STTY=$TRUE
STTYCMD=/bin/stty
elif [ `(busybox stty >/dev/null 2>&1; echo $?)` -eq $TRUE ]; then
STTY=$TRUE
STTYCMD="busybox stty"
fi
# print message to usplash or stderr
# usage: msg <command> "message" [switch]
# command: TEXT | STATUS | SUCCESS | FAILURE | CLEAR (see 'man usplash_write' for all commands)
# switch : switch used for echo to stderr (ignored for usplash)
# when using usplash the command will cause "message" to be
# printed according to the usplash <command> definition.
# using the switch -n will allow echo to write multiple messages
# to the same line
msg ()
{
if [ $# -gt 0 ]; then
# handle multi-line messages
echo $2 | while read LINE; do
if [ $USPLASH -eq $TRUE ]; then
# use usplash
/sbin/usplash_write "$1 $LINE"
else
# use stderr for all messages
echo $3 "$2" >&2
fi
done
fi
}
dbg ()
{
if [ $DEBUG -eq $TRUE ]; then
msg "$@"
fi
}
# read password from console or with usplash
# usage: readpass "prompt"
readpass ()
{
if [ $# -gt 0 ]; then
if [ $USPLASH -eq $TRUE ]; then
usplash_write "INPUTQUIET $1: "
PASS="$(cat /dev/.initramfs/usplash_outfifo)"
else
[ $STTY -ne $TRUE ] && msg TEXT "WARNING stty not found, password will be visible"
echo -n "$1" >&2
$STTYCMD -echo
read -r PASS </dev/console >/dev/null
[ $STTY -eq $TRUE ] && echo >&2
$STTYCMD echo
fi
fi
echo -n "$PASS"
}
dbg STATUS "Executing crypto-usb-key.sh ..."
# flag tracking key-file availability
OPENED=$FALSE
# temporary mount path for USB key
MD=/tmp-usb-mount
if [ "x$1" = "x" -o "x$1" = "xnone" ]; then
# default key-file on the USB disk
KEYFILE=.key
else
KEYFILE=$1
fi
# If the file already exists use it.
# This is useful where an encrypted volume contains keyfile(s) for later
# volumes and is now mounted and accessible
if [ -f $KEYFILE ]; then
dbg TEXT "Found $KEYFILE"
cat $KEYFILE
OPENED=$TRUE
DEV="existing mount"
LABEL=""
else
# Is the USB driver loaded?
cat /proc/modules | busybox grep usb_storage >/dev/null 2>&1
USBLOAD=0$?
if [ $USBLOAD -gt 0 ]; then
dbg TEXT "Loading driver 'usb_storage'"
modprobe usb_storage >/dev/null 2>&1
fi
# give the system time to settle and open the USB devices
sleep 7
# Are there any SCSI block devices?
ls -d /sys/block/sd* >/dev/null 2>&1
SBD=$?
if [ $SBD -eq $TRUE ]; then
mkdir -p $MD
dbg TEXT "Trying to get key-file '$KEYFILE' ..."
for SFS in /sys/block/sd*/sd??; do
dbg TEXT "Examining $SFS" -n
# Is the device removable?
REMOVABLE=0`cat ${SFS}/../removable`
dbg TEXT ", REMOVABLE=$REMOVABLE" -n
if [ $REMOVABLE -eq 1 -a -f $SFS/dev ]; then
dbg TEXT ", *possible key device*" -n
DEV=`busybox basename $SFS`
# Check if key device itself is encrypted
/sbin/cryptsetup isLuks /dev/${DEV} >/dev/null 2>&1
ENCRYPTED=0$?
# Open crypted partition and prepare for mount
if [ $ENCRYPTED -eq $TRUE ]; then
dbg TEXT ", encrypted device" -n
# Use vol_id to determine label
LABEL="`/lib/udev/vol_id /dev/${DEV} | busybox sed -n 's/.*ID_FS_LABEL_SAFE=\(.*\)/\1/p'`"
dbg TEXT ", label $LABEL" -n
TRIES=3
DECRYPTED=$FALSE
while [ $TRIES -gt 0 -a $DECRYPTED -ne $TRUE ]; do
TRIES=$(($TRIES-1))
PASS="`readpass \"Enter LUKS password for key device ${DEV} (${LABEL}) (or empty to skip): \"`"
if [ -z "$PASS" ]; then
dbg TEXT ", device skipped" -n
break
fi
echo $PASS | /sbin/cryptsetup luksOpen /dev/${DEV} bootkey >/dev/null 2>&1
DECRYPTED=0$?
done
# If open failed, skip this device
if [ $DECRYPTED -ne $TRUE ]; then
dbg TEXT "decrypting device failed" -n
break
fi
# Decrypted device to use
DEV=mapper/bootkey
fi
dbg TEXT ", device $DEV" -n
# Use vol_id to determine label
LABEL="`/lib/udev/vol_id /dev/${DEV} | busybox sed -n 's/.*ID_FS_LABEL_SAFE=\(.*\)/\1/p'`"
dbg TEXT ", label $LABEL" -n
# Use vol_id to determine fstype
FSTYPE="`/lib/udev/vol_id /dev/${DEV} | busybox sed -n 's/.*ID_FS_TYPE=\(.*\)/\1/p'`"
dbg TEXT ", fstype $FSTYPE" -n
# Is the file-system driver loaded?
cat /proc/modules | busybox grep $FSTYPE >/dev/null 2>&1
FSLOAD=0$?
if [ $FSLOAD -gt 0 ]; then
dbg TEXT ", loading driver for $FSTYPE" -n
# load the correct file-system driver
modprobe $FSTYPE >/dev/null 2>&1
fi
dbg TEXT ", mounting /dev/$DEV on $MD" -n
mount /dev/${DEV} $MD -t $FSTYPE -o ro >/dev/null 2>&1
dbg TEXT ", (`mount | busybox grep $DEV`)" -n
if [ -f $MD/$KEYFILE ]; then
dbg TEXT ", found $MD/$KEYFILE" -n
cat $MD/$KEYFILE
OPENED=$TRUE
fi
dbg TEXT ", umount $MD" -n
umount $MD >/dev/null 2>&1
# Close encrypted key device
if [ $ENCRYPTED -eq $TRUE -a $DECRYPTED -eq $TRUE ]; then
dbg TEXT ", closing encrypted device" -n
/sbin/cryptsetup luksClose bootkey >/dev/null 2>&1
fi
dbg TEXT ", done\n\n" -n
if [ $OPENED -eq $TRUE ]; then
break
fi
else
dbg TEXT ", device `busybox basename $SFS` ignored" -n
fi
dbg CLEAR ""
done
fi
fi
# clear existing usplash text and status messages
[ $USPLASH -eq $TRUE ] && msg STATUS " " && msg CLEAR ""
if [ $OPENED -ne $TRUE ]; then
msg TEXT "FAILED to find suitable USB key-file ..."
readpass "Try to enter the LUKS password: "
else
msg TEXT "Success loading key-file from $SFS ($LABEL)"
fi
#
[ $USPLASH -eq $TRUE ] && /sbin/usplash_write "VERBOSE default"
It’s a small change that helps with old systems that don’t have usb
string part of /sys/block/sd*/device
. If you have had problems using
the previous scripts, this one might help.
Oh, and here’s diff against Hendrik’s script:
Script (click to expand)
--- hendrik-crypto-usb-key.sh 2008-10-05 16:47:15.000000000 +0200
+++ beckman-crypto-usb-key.sh 2009-03-04 22:22:41.000000000 +0100
@@ -152,14 +152,10 @@
dbg TEXT "Trying to get key-file '$KEYFILE' ..."
for SFS in /sys/block/sd*/sd??; do
dbg TEXT "Examining $SFS" -n
- # is it a USB device?
- ls -l ${SFS}/../device | busybox grep 'usb' >/dev/null 2>&1
- USB=0$?
- dbg TEXT ", USB=$USB" -n
# Is the device removable?
REMOVABLE=0`cat ${SFS}/../removable`
dbg TEXT ", REMOVABLE=$REMOVABLE" -n
- if [ $USB -eq $TRUE -a $REMOVABLE -eq 1 -a -f $SFS/dev ]; then
+ if [ $REMOVABLE -eq 1 -a -f $SFS/dev ]; then
dbg TEXT ", *possible key device*" -n
DEV=`busybox basename $SFS`
# Check if key device itself is encrypted
Update: Matthieu’s customizations for testing/unstable Debian
Matthieu Helleboid sent me following comments regarding using this howto on Debian unstable:
I use debian testing/unstable and I made some modifications:
- I had to add nls_utf8 and nls_base to /etc/initramfs-tools/modules because of the “charset utf8 not found” error message with my usb key.
- I also changed the line to read the passphrase from stdin
withread -r A </dev/console >/dev/null echo -n "$A"
because the password was printed to screen and I think this is the way to simplicity./lib/cryptsetup/askpass "password : "
While I can’t attest to correctness of the part2, it might be of some help to you. And as always, please have backup in case anything goes wrong with these modifications.
Update: Dave Fuchs’ comments re upgrade to Lenny
Dave Fuchs wrote me about his upgrade to Lenny. He’s having two issues:
- “charset utf8 not found”
- “failed to find suitable keychain”
The solution for the first one is (obviously) adding nls_utf8
to your
/etc/initramfs-tools/modules
and re-running update-initrams.
The second one will be most likely solved by increasing the sleep()
time
in the script from 7
to a slightly larger number.
N.B.: Seems like full revision of both this guide and the final script is in order. I just don’t have the time to do so ATM. Any volunteers? ;)
Update 2009-12-13: Jan-Pascal van Best’s updates to Hendrik’s script for latest Debian
Jan-Pascal van Best sent me an update to Hendrik’s script that fixes several
issues with latest Debian update. The vol_id
program is missing so blkid
is used instead.
Script (click to expand)
#!/bin/sh
# Part of passwordless cryptofs setup in Debian Etch.
# See: https://wejn.org/how-to-make-passwordless-cryptsetup.html
# Author: Wejn <wejn at box dot cz>
#
# Updated by Rodolfo Garcia (kix) <kix at kix dot com>
# For multiple partitions
# http://www.kix.es/
#
# Updated by TJ <linux@tjworld.net> 7 July 2008
# For use with Ubuntu Hardy, usplash, automatic detection of USB devices,
# detection and examination of *all* partitions on the device (not just partition #1),
# automatic detection of partition type, refactored, commented, debugging code.
#
# Updated by Hendrik van Antwerpen <hendrik at van-antwerpen dot net> 3 Sept 2008
# For encrypted key device support, also added stty support for not
# showing your password in console mode.
#
# Updated by Jan-Pascal van Best janpascal/at/vanbest/org 2009-12-07
# to support latest debian updates (vol_id missing, blkid used instead)
# define counter-intuitive shell logic values (based on /bin/true & /bin/false)
# NB. use FALSE only to *set* something to false, but don't test for
# equality, because a program might return any non-zero on error
TRUE=0
FALSE=1
# set DEBUG=$TRUE to display debug messages, DEBUG=$FALSE to be quiet
DEBUG=$FALSE
# is usplash available? default false
USPLASH=$FALSE
# test for outfifo from Ubuntu Hardy cryptroot script, the second test
# alone proves not completely reliable.
if [ -p /dev/.initramfs/usplash_outfifo -a -x /sbin/usplash_write ]; then
# use innocuous command to determine if usplash is running
# usplash_write will return exit-code 1 if usplash isn't running
# need to set a flag to tell usplash_write to report no usplash
FAIL_NO_USPLASH=1
# enable verbose messages (required to display messages if kernel boot option "quiet" is enabled
/sbin/usplash_write "VERBOSE on"
if [ $? -eq $TRUE ]; then
# usplash is running
USPLASH=$TRUE
/sbin/usplash_write "CLEAR"
fi
fi
# is stty available? default false
STTY=$FALSE
STTYCMD=false
# check for stty executable
if [ -x /bin/stty ]; then
STTY=$TRUE
STTYCMD=/bin/stty
elif [ `(busybox stty >/dev/null 2>&1; echo $?)` -eq $TRUE ]; then
STTY=$TRUE
STTYCMD="busybox stty"
fi
# print message to usplash or stderr
# usage: msg <command> "message" [switch]
# command: TEXT | STATUS | SUCCESS | FAILURE | CLEAR (see 'man usplash_write' for all commands)
# switch : switch used for echo to stderr (ignored for usplash)
# when using usplash the command will cause "message" to be
# printed according to the usplash <command> definition.
# using the switch -n will allow echo to write multiple messages
# to the same line
msg ()
{
if [ $# -gt 0 ]; then
# handle multi-line messages
echo $2 | while read LINE; do
if [ $USPLASH -eq $TRUE ]; then
# use usplash
/sbin/usplash_write "$1 $LINE"
else
# use stderr for all messages
echo $3 "$2" >&2
fi
done
fi
}
dbg ()
{
if [ $DEBUG -eq $TRUE ]; then
msg "$@"
fi
}
# read password from console or with usplash
# usage: readpass "prompt"
readpass ()
{
if [ $# -gt 0 ]; then
if [ $USPLASH -eq $TRUE ]; then
usplash_write "INPUTQUIET $1: "
PASS="$(cat /dev/.initramfs/usplash_outfifo)"
else
[ $STTY -ne $TRUE ] && msg TEXT "WARNING stty not found, password will be visible"
echo -n "$1" >&2
$STTYCMD -echo
read -r PASS </dev/console >/dev/null
[ $STTY -eq $TRUE ] && echo >&2
$STTYCMD echo
fi
fi
echo -n "$PASS"
}
dbg STATUS "Executing crypto-usb-key.sh ..."
# flag tracking key-file availability
OPENED=$FALSE
# temporary mount path for USB key
MD=/tmp-usb-mount
if [ "x$1" = "x" -o "x$1" = "xnone" ]; then
# default key-file on the USB disk
KEYFILE=.key
else
KEYFILE=$1
fi
# If the file already exists use it.
# This is useful where an encrypted volume contains keyfile(s) for later
# volumes and is now mounted and accessible
if [ -f $KEYFILE ]; then
dbg TEXT "Found $KEYFILE"
cat $KEYFILE
OPENED=$TRUE
DEV="existing mount"
LABEL=""
else
# Is the USB driver loaded?
cat /proc/modules | busybox grep usb_storage >/dev/null 2>&1
USBLOAD=0$?
if [ $USBLOAD -gt 0 ]; then
dbg TEXT "Loading driver 'usb_storage'"
modprobe usb_storage >/dev/null 2>&1
fi
# give the system time to settle and open the USB devices
sleep 7
# Are there any SCSI block devices?
ls -d /sys/block/sd* >/dev/null 2>&1
SBD=$?
if [ $SBD -eq $TRUE ]; then
mkdir -p $MD
dbg TEXT "Trying to get key-file '$KEYFILE' ..."
#for SFS in /sys/block/sd*/sd??; do
for SFS in /sys/block/sd*/sd??; do
dbg TEXT "Examining $SFS" -n
# is it a USB device?
ls -l ${SFS}/../device | busybox grep 'usb' >/dev/null 2>&1
USB=0$?
dbg TEXT ", USB=$USB" -n
# Is the device removable?
REMOVABLE=0`cat ${SFS}/../removable`
dbg TEXT ", REMOVABLE=$REMOVABLE" -n
if [ $USB -eq $TRUE -a $REMOVABLE -eq 1 -a -f $SFS/dev ]; then
dbg TEXT ", *possible key device*" -n
DEV=`busybox basename $SFS`
# Check if key device itself is encrypted
/sbin/cryptsetup isLuks /dev/${DEV} >/dev/null 2>&1
ENCRYPTED=0$?
DECRYPTED=$FALSE
# Open crypted partition and prepare for mount
if [ $ENCRYPTED -eq $TRUE ]; then
dbg TEXT ", encrypted device" -n
# Use blkid to determine label
LABEL=$(/sbin/blkid -s LABEL -o value /dev/${DEV})
dbg TEXT ", label $LABEL" -n
TRIES=3
DECRYPTED=$FALSE
while [ $TRIES -gt 0 -a $DECRYPTED -ne $TRUE ]; do
TRIES=$(($TRIES-1))
PASS="`readpass \"Enter LUKS password for key device ${DEV} (${LABEL}) (or empty to skip): \"`"
if [ -z "$PASS" ]; then
dbg TEXT ", device skipped" -n
break
fi
echo $PASS | /sbin/cryptsetup luksOpen /dev/${DEV} bootkey >/dev/null 2>&1
DECRYPTED=0$?
done
# If open failed, skip this device
if [ $DECRYPTED -ne $TRUE ]; then
dbg TEXT "decrypting device failed" -n
break
fi
# Decrypted device to use
DEV=mapper/bootkey
fi
dbg TEXT ", device $DEV" -n
# Use blkid to determine label
LABEL=$(/sbin/blkid -s LABEL -o value /dev/${DEV})
dbg TEXT ", label $LABEL" -n
# Use blkid to determine fstype
FSTYPE=$(/sbin/blkid -s TYPE -o value /dev/${DEV})
dbg TEXT ", fstype $FSTYPE" -n
# Is the file-system driver loaded?
cat /proc/modules | busybox grep $FSTYPE >/dev/null 2>&1
FSLOAD=0$?
if [ $FSLOAD -gt 0 ]; then
dbg TEXT ", loading driver for $FSTYPE" -n
# load the correct file-system driver
modprobe $FSTYPE >/dev/null 2>&1
fi
dbg TEXT ", mounting /dev/$DEV on $MD" -n
mount /dev/${DEV} $MD -t $FSTYPE -o ro >/dev/null 2>&1
dbg TEXT ", (`mount | busybox grep $DEV`)" -n
dbg TEXT ", checking fot $MD/$KEYFILE" -n
if [ -f $MD/$KEYFILE ]; then
dbg TEXT ", found $MD/$KEYFILE" -n
cat $MD/$KEYFILE
OPENED=$TRUE
fi
dbg TEXT ", umount $MD" -n
umount $MD >/dev/null 2>&1
# Close encrypted key device
if [ $ENCRYPTED -eq $TRUE -a $DECRYPTED -eq $TRUE ]; then
dbg TEXT ", closing encrypted device" -n
/sbin/cryptsetup luksClose bootkey >/dev/null 2>&1
fi
dbg TEXT ", done\n\n" -n
if [ $OPENED -eq $TRUE ]; then
break
fi
else
dbg TEXT ", device `busybox basename $SFS` ignored" -n
fi
dbg CLEAR ""
done
fi
fi
# clear existing usplash text and status messages
[ $USPLASH -eq $TRUE ] && msg STATUS " " && msg CLEAR ""
if [ $OPENED -ne $TRUE ]; then
msg TEXT "FAILED to find suitable USB key-file ..."
readpass "Try to enter the LUKS password: "
else
msg TEXT "Success loading key-file from $SFS ($LABEL)"
fi
#
[ $USPLASH -eq $TRUE ] && /sbin/usplash_write "VERBOSE default"
Update 2010-01-05: Martin Muller’s comments on Debian squeeze
I received following comment:
Comment (click to expand)
I work on Debian squeeze and it happend the following:
After upgrading - not sure which upgrade it was - the script doesnt work with new generated initramfs. First I thought it had to do with my new kernel 2.6.30-2-amd64, so I booted with kernel 2.6.29-2-amd64. Now as I had a little time I traced the script.
Line 166 in the newest version is:
if [ $USB -eq $TRUE -a $REMOVABLE -eq 1 -a -f $SFS/dev ]; then
and TRUE is defined as 0 in line 26
Now I executed the following little script on my PC
#!/bin/sh for SFS in /sys/block/sd*/sd??; do echo "Examining $SFS" ls -l ${SFS}/../device | busybox grep 'usb' >/dev/null 2>&1 USB=0$? echo "USB is $USB" REMOVABLE=0`cat ${SFS}/../removable` echo "REMOVABLE is $REMOVABLE" DEV=`busybox basename $SFS` LABEL=$(/sbin/blkid -s LABEL -o value /dev/${DEV}) echo "Label is $LABEL" done;
that gives my:
Examining /sys/block/sda/sda1 USB is 01 REMOVABLE is 00 Label is Examining /sys/block/sda/sda2 USB is 01 REMOVABLE is 00 Label is Examining /sys/block/sda/sda3 USB is 01 REMOVABLE is 00 Label is boot Examining /sys/block/sda/sda4 USB is 01 REMOVABLE is 00 Label is Examining /sys/block/sda/sda5 USB is 01 REMOVABLE is 00 Label is Examining /sys/block/sdb/sdb1 USB is 01 REMOVABLE is 01 Label is Token
where sdb1 is my USB-Stick with key-file. Because TRUE is 0 and $USB gives 01 back, the if-clause was never fullfilled, no key-file were found.
I dont know, which update in Debian changed this output (think this former had been USB=00 ??) but now you know were occuring problems could be located.
I changed the line to
if [ $USB -ne $TRUE -a $REMOVABLE -eq 1 -a -f $SFS/dev ]; then
not logic, but working.
Update 2011-09-24: Renaud Metrich’s update for Ubuntu 10.04 and onward
I received following message:
I took some time implementing your solution for both home and work. I had to fix the latest script Jan-Pascal van Best in order to have it work on Ubuntu 10.04 and onward. The issue reported later against USB was due to the fact that devices in /sys/block/*/device point to a relative path on Ubuntu instead of full path name. The solution was to cd to that directory and issue a pwd. Also, I improved a bit the algorithm to speed up things, typically by first checking whether the device (e.g. sdb) was a USB and removable stuff, instead of doing the same test on every single partition of the device (e.g. sdb1, sdb2, …).
And here’s the update to Jan-Pascal van Best’s:
Script (click to expand)
#!/bin/sh
# Part of passwordless cryptofs setup in Debian Etch.
# See: https://wejn.org/how-to-make-passwordless-cryptsetup.html
# Author: Wejn <wejn at box dot cz>
#
# Updated by Rodolfo Garcia (kix) <kix at kix dot com>
# For multiple partitions
# http://www.kix.es/
#
# Updated by TJ <linux@tjworld.net> 7 July 2008
# For use with Ubuntu Hardy, usplash, automatic detection of USB devices,
# detection and examination of *all* partitions on the device (not just partition #1),
# automatic detection of partition type, refactored, commented, debugging code.
#
# Updated by Hendrik van Antwerpen <hendrik at van-antwerpen dot net> 3 Sept 2008
# For encrypted key device support, also added stty support for not
# showing your password in console mode.
#
# Updated by Jan-Pascal van Best janpascal/at/vanbest/org 2009-12-07
# to support latest debian updates (vol_id missing, blkid used instead)
#
# Updated by Renaud Metrich renaud.metrich/at/laposte/net 2011-09-24
# to support Ubuntu 10.04 and onward.
# Explanation of the patch:
# The issue reported later against USB was due to the fact that devices in
# /sys/block/*/device point to a relative path on Ubuntu instead of full
# path name. The solution was to cd to that directory and issue a pwd.
# Also, I improved a bit the algorithm to speed up things, typically by
# first checking whether the device (e.g. sdb) was a USB and removable
# stuff, instead of doing the same test on every single partition of the
# device (e.g. sdb1, sdb2, ...).
# define counter-intuitive shell logic values (based on /bin/true & /bin/false)
# NB. use FALSE only to *set* something to false, but don't test for
# equality, because a program might return any non-zero on error
TRUE=0
FALSE=1
# set DEBUG=$TRUE to display debug messages, DEBUG=$FALSE to be quiet
DEBUG=$TRUE
# is usplash available? default false
USPLASH=$FALSE
# test for outfifo from Ubuntu Hardy cryptroot script, the second test
# alone proves not completely reliable.
if [ -p /dev/.initramfs/usplash_outfifo -a -x /sbin/usplash_write ]; then
# use innocuous command to determine if usplash is running
# usplash_write will return exit-code 1 if usplash isn't running
# need to set a flag to tell usplash_write to report no usplash
FAIL_NO_USPLASH=1
# enable verbose messages (required to display messages if kernel boot option "quiet" is enabled
/sbin/usplash_write "VERBOSE on"
if [ $? -eq $TRUE ]; then
# usplash is running
USPLASH=$TRUE
/sbin/usplash_write "CLEAR"
fi
fi
# is stty available? default false
STTY=$FALSE
STTYCMD=false
# check for stty executable
if [ -x /bin/stty ]; then
STTY=$TRUE
STTYCMD=/bin/stty
elif [ `(busybox stty >/dev/null 2>&1; echo $?)` -eq $TRUE ]; then
STTY=$TRUE
STTYCMD="busybox stty"
fi
# print message to usplash or stderr
# usage: msg <command> "message" [switch]
# command: TEXT | STATUS | SUCCESS | FAILURE | CLEAR (see 'man usplash_write' for all commands)
# switch : switch used for echo to stderr (ignored for usplash)
# when using usplash the command will cause "message" to be
# printed according to the usplash <command> definition.
# using the switch -n will allow echo to write multiple messages
# to the same line
msg ()
{
if [ $# -gt 0 ]; then
# handle multi-line messages
echo $2 | while read LINE; do
if [ $USPLASH -eq $TRUE ]; then
# use usplash
/sbin/usplash_write "$1 $LINE"
else
# use stderr for all messages
echo $3 "$2" >&2
fi
done
fi
}
dbg ()
{
if [ $DEBUG -eq $TRUE ]; then
msg "$@"
fi
}
# read password from console or with usplash
# usage: readpass "prompt"
readpass ()
{
if [ $# -gt 0 ]; then
if [ $USPLASH -eq $TRUE ]; then
usplash_write "INPUTQUIET $1: "
PASS="$(cat /dev/.initramfs/usplash_outfifo)"
else
[ $STTY -ne $TRUE ] && msg TEXT "WARNING stty not found, password will be visible"
echo -n "$1" >&2
$STTYCMD -echo
read -r PASS </dev/console >/dev/null
[ $STTY -eq $TRUE ] && echo >&2
$STTYCMD echo
fi
fi
echo -n "$PASS"
}
dbg STATUS "Executing crypto-usb-key.sh ..."
# flag tracking key-file availability
OPENED=$FALSE
# temporary mount path for USB key
MD=/tmp-usb-mount
if [ "x$1" = "x" -o "x$1" = "xnone" ]; then
# default key-file on the USB disk
KEYFILE=.key
else
KEYFILE=$1
fi
# If the file already exists use it.
# This is useful where an encrypted volume contains keyfile(s) for later
# volumes and is now mounted and accessible
if [ -f $KEYFILE ]; then
dbg TEXT "Found $KEYFILE"
cat $KEYFILE
OPENED=$TRUE
DEV="existing mount"
LABEL=""
else
# Is the USB driver loaded?
cat /proc/modules | busybox grep usb_storage >/dev/null 2>&1
USBLOAD=0$?
if [ $USBLOAD -gt 0 ]; then
dbg TEXT "Loading driver 'usb_storage'"
modprobe usb_storage >/dev/null 2>&1
fi
# give the system time to settle and open the USB devices
sleep 7
mkdir -p $MD
dbg TEXT "Trying to get key-file '$KEYFILE' ..."
for SDB in /sys/block/sd*; do
dbg TEXT "Examining $SDB" -n
# is it a USB device?
(cd ${SDB}/device && busybox pwd) | busybox grep 'usb' >/dev/null 2>&1
USB=0$?
dbg TEXT ", USB=$USB" -n
# Is the device removable?
REMOVABLE=0`cat ${SDB}/removable`
dbg TEXT ", REMOVABLE=$REMOVABLE" -n
if [ $USB -ne $TRUE -o $REMOVABLE -ne 1 -o ! -f $SDB/dev ]; then
dbg TEXT ", device `busybox basename $SDB` ignored"
continue # for SDB
fi
for SFS in $SDB/sd*; do
dbg TEXT ", *possible key device*" -n
DEV=`busybox basename $SFS`
# Check if key device itself is encrypted
/sbin/cryptsetup isLuks /dev/${DEV} >/dev/null 2>&1
ENCRYPTED=0$?
DECRYPTED=$FALSE
# Open crypted partition and prepare for mount
if [ $ENCRYPTED -eq $TRUE ]; then
dbg TEXT ", encrypted device" -n
# Use blkid to determine label
LABEL=$(/sbin/blkid -s LABEL -o value /dev/${DEV})
dbg TEXT ", label $LABEL" -n
TRIES=3
DECRYPTED=$FALSE
while [ $TRIES -gt 0 -a $DECRYPTED -ne $TRUE ]; do
TRIES=$(($TRIES-1))
PASS="`readpass \"Enter LUKS password for key device ${DEV} (${LABEL}) (or empty to skip): \"`"
if [ -z "$PASS" ]; then
dbg TEXT ", device skipped" -n
break
fi
echo $PASS | /sbin/cryptsetup luksOpen /dev/${DEV} bootkey >/dev/null 2>&1
DECRYPTED=0$?
done
# If open failed, skip this device
if [ $DECRYPTED -ne $TRUE ]; then
dbg TEXT "decrypting device failed" -n
break
fi
# Decrypted device to use
DEV=mapper/bootkey
fi
dbg TEXT ", device $DEV" -n
# Use blkid to determine label
LABEL=$(/sbin/blkid -s LABEL -o value /dev/${DEV})
dbg TEXT ", label $LABEL" -n
# Use blkid to determine fstype
FSTYPE=$(/sbin/blkid -s TYPE -o value /dev/${DEV})
dbg TEXT ", fstype $FSTYPE" -n
# Is the file-system driver loaded?
cat /proc/modules | busybox grep $FSTYPE >/dev/null 2>&1
FSLOAD=0$?
if [ $FSLOAD -gt 0 ]; then
dbg TEXT ", loading driver for $FSTYPE" -n
# load the correct file-system driver
modprobe $FSTYPE >/dev/null 2>&1
fi
dbg TEXT ", mounting /dev/$DEV on $MD" -n
mount /dev/${DEV} $MD -t $FSTYPE -o ro >/dev/null 2>&1
dbg TEXT ", (`mount | busybox grep $DEV`)" -n
dbg TEXT ", checking for $MD/$KEYFILE" -n
if [ -f $MD/$KEYFILE ]; then
dbg TEXT ", found $MD/$KEYFILE" -n
cat $MD/$KEYFILE
OPENED=$TRUE
fi
dbg TEXT ", umount $MD" -n
umount $MD >/dev/null 2>&1
# Close encrypted key device
if [ $ENCRYPTED -eq $TRUE -a $DECRYPTED -eq $TRUE ]; then
dbg TEXT ", closing encrypted device" -n
/sbin/cryptsetup luksClose bootkey >/dev/null 2>&1
fi
dbg TEXT ", done\n\n" -n
if [ $OPENED -eq $TRUE ]; then
break
fi
dbg CLEAR ""
done
done
fi
# clear existing usplash text and status messages
[ $USPLASH -eq $TRUE ] && msg STATUS " " && msg CLEAR ""
if [ $OPENED -ne $TRUE ]; then
msg TEXT "FAILED to find suitable USB key-file ..."
readpass "Try to enter the LUKS password: "
else
msg TEXT "Success loading key-file from $SFS ($LABEL)"
fi
#
[ $USPLASH -eq $TRUE ] && /sbin/usplash_write "VERBOSE default"
Update 2011-12-29: Jay Schieber’s clarification regarding grub2 backup
Jay Schieber was wrestling a little bit with grub2 on Kubuntu 10.04. In the end he figured out how to make proper backup.
Here’s his take on it…
Problem:
The problem is that 10.04 uses grub2 instead of grub. So, there is no longer the file
/boot/grub/menu.lst
, but rather/boot/grub/grub.cfg
.Moreover, there are strong recommendations in the file header against its modification, since it is now generated by other files. At this point, I got too scared to make any guesses.
Solution:
I figured out grub2 sufficiently to make up the backup. In case you are interested, I did the following:
- I have only one operating system, so I needed to change the default to display the boot menu. I did this by editing the file
/etc/default/grub
and changed the two lines to:#GRUB_HIDDEN_TIMEOUT=0 GRUB_HIDDEN_TIMEOUT_QUIET=false
- Then, I edited the script file
/etc/grub.d/40_custom
to add to the menu list your safe kernel. This was just copied from grub.cfg and slightly modified.- Then run
sudo update-grub
. This creates something just like you suggest for the boot menu.
Update 2012-03-29: David G Beausang’s Plymouth support for rm-crypto-usb-key.sh
David G Beausang sent me his improvement of Renaud Metrich’s script that adds Plymouth support.
Diff:
Script (click to expand)
--- rm-crypto-usb-key.sh 2011-10-02 20:29:15.000000000 +0200
+++ dgb-crypto-usb-key.sh 2012-05-27 14:18:55.000000000 +0200
@@ -30,6 +30,9 @@
# first checking whether the device (e.g. sdb) was a USB and removable
# stuff, instead of doing the same test on every single partition of the
# device (e.g. sdb1, sdb2, ...).
+#
+# 2012-03-29
+# Updated by dgb for plymouth support in Ubuntu 10.04.3 LTS
# define counter-intuitive shell logic values (based on /bin/true & /bin/false)
# NB. use FALSE only to *set* something to false, but don't test for
@@ -40,6 +43,12 @@
# set DEBUG=$TRUE to display debug messages, DEBUG=$FALSE to be quiet
DEBUG=$TRUE
+# is plymouth available? default false
+PLYMOUTH=$FALSE
+if [ -x /bin/plymouth ] && plymouth --ping; then
+ PLYMOUTH=$TRUE
+fi
+
# is usplash available? default false
USPLASH=$FALSE
# test for outfifo from Ubuntu Hardy cryptroot script, the second test
@@ -83,7 +92,10 @@
if [ $# -gt 0 ]; then
# handle multi-line messages
echo $2 | while read LINE; do
- if [ $USPLASH -eq $TRUE ]; then
+ if [ $PLYMOUTH -eq $TRUE ]; then
+ # use plymouth
+ plymouth message --text="$LINE"
+ elif [ $USPLASH -eq $TRUE ]; then
# use usplash
/sbin/usplash_write "$1 $LINE"
else
@@ -106,7 +118,9 @@
readpass ()
{
if [ $# -gt 0 ]; then
- if [ $USPLASH -eq $TRUE ]; then
+ if [ $PLYMOUTH -eq $TRUE ]; then
+ PASS="$(plymouth ask-for-password --prompt "$1: ")"
+ elif [ $USPLASH -eq $TRUE ]; then
usplash_write "INPUTQUIET $1: "
PASS="$(cat /dev/.initramfs/usplash_outfifo)"
else
@@ -249,8 +263,8 @@
[ $USPLASH -eq $TRUE ] && msg STATUS " " && msg CLEAR ""
if [ $OPENED -ne $TRUE ]; then
- msg TEXT "FAILED to find suitable USB key-file ..."
- readpass "Try to enter the LUKS password: "
+ msg TEXT "Failed to find suitable USB key-file ..."
+ readpass "Enter the LUKS password: "
else
msg TEXT "Success loading key-file from $SFS ($LABEL)"
fi
@@ -258,3 +272,4 @@
#
[ $USPLASH -eq $TRUE ] && /sbin/usplash_write "VERBOSE default"
+
Full script:
Script (click to expand)
#!/bin/sh
# Part of passwordless cryptofs setup in Debian Etch.
# See: https://wejn.org/how-to-make-passwordless-cryptsetup.html
# Author: Wejn <wejn at box dot cz>
#
# Updated by Rodolfo Garcia (kix) <kix at kix dot com>
# For multiple partitions
# http://www.kix.es/
#
# Updated by TJ <linux@tjworld.net> 7 July 2008
# For use with Ubuntu Hardy, usplash, automatic detection of USB devices,
# detection and examination of *all* partitions on the device (not just partition #1),
# automatic detection of partition type, refactored, commented, debugging code.
#
# Updated by Hendrik van Antwerpen <hendrik at van-antwerpen dot net> 3 Sept 2008
# For encrypted key device support, also added stty support for not
# showing your password in console mode.
#
# Updated by Jan-Pascal van Best janpascal/at/vanbest/org 2009-12-07
# to support latest debian updates (vol_id missing, blkid used instead)
#
# Updated by Renaud Metrich renaud.metrich/at/laposte/net 2011-09-24
# to support Ubuntu 10.04 and onward.
# Explanation of the patch:
# The issue reported later against USB was due to the fact that devices in
# /sys/block/*/device point to a relative path on Ubuntu instead of full
# path name. The solution was to cd to that directory and issue a pwd.
# Also, I improved a bit the algorithm to speed up things, typically by
# first checking whether the device (e.g. sdb) was a USB and removable
# stuff, instead of doing the same test on every single partition of the
# device (e.g. sdb1, sdb2, ...).
#
# 2012-03-29
# Updated by dgb for plymouth support in Ubuntu 10.04.3 LTS
# define counter-intuitive shell logic values (based on /bin/true & /bin/false)
# NB. use FALSE only to *set* something to false, but don't test for
# equality, because a program might return any non-zero on error
TRUE=0
FALSE=1
# set DEBUG=$TRUE to display debug messages, DEBUG=$FALSE to be quiet
DEBUG=$TRUE
# is plymouth available? default false
PLYMOUTH=$FALSE
if [ -x /bin/plymouth ] && plymouth --ping; then
PLYMOUTH=$TRUE
fi
# is usplash available? default false
USPLASH=$FALSE
# test for outfifo from Ubuntu Hardy cryptroot script, the second test
# alone proves not completely reliable.
if [ -p /dev/.initramfs/usplash_outfifo -a -x /sbin/usplash_write ]; then
# use innocuous command to determine if usplash is running
# usplash_write will return exit-code 1 if usplash isn't running
# need to set a flag to tell usplash_write to report no usplash
FAIL_NO_USPLASH=1
# enable verbose messages (required to display messages if kernel boot option "quiet" is enabled
/sbin/usplash_write "VERBOSE on"
if [ $? -eq $TRUE ]; then
# usplash is running
USPLASH=$TRUE
/sbin/usplash_write "CLEAR"
fi
fi
# is stty available? default false
STTY=$FALSE
STTYCMD=false
# check for stty executable
if [ -x /bin/stty ]; then
STTY=$TRUE
STTYCMD=/bin/stty
elif [ `(busybox stty >/dev/null 2>&1; echo $?)` -eq $TRUE ]; then
STTY=$TRUE
STTYCMD="busybox stty"
fi
# print message to usplash or stderr
# usage: msg <command> "message" [switch]
# command: TEXT | STATUS | SUCCESS | FAILURE | CLEAR (see 'man usplash_write' for all commands)
# switch : switch used for echo to stderr (ignored for usplash)
# when using usplash the command will cause "message" to be
# printed according to the usplash <command> definition.
# using the switch -n will allow echo to write multiple messages
# to the same line
msg ()
{
if [ $# -gt 0 ]; then
# handle multi-line messages
echo $2 | while read LINE; do
if [ $PLYMOUTH -eq $TRUE ]; then
# use plymouth
plymouth message --text="$LINE"
elif [ $USPLASH -eq $TRUE ]; then
# use usplash
/sbin/usplash_write "$1 $LINE"
else
# use stderr for all messages
echo $3 "$2" >&2
fi
done
fi
}
dbg ()
{
if [ $DEBUG -eq $TRUE ]; then
msg "$@"
fi
}
# read password from console or with usplash
# usage: readpass "prompt"
readpass ()
{
if [ $# -gt 0 ]; then
if [ $PLYMOUTH -eq $TRUE ]; then
PASS="$(plymouth ask-for-password --prompt "$1: ")"
elif [ $USPLASH -eq $TRUE ]; then
usplash_write "INPUTQUIET $1: "
PASS="$(cat /dev/.initramfs/usplash_outfifo)"
else
[ $STTY -ne $TRUE ] && msg TEXT "WARNING stty not found, password will be visible"
echo -n "$1" >&2
$STTYCMD -echo
read -r PASS </dev/console >/dev/null
[ $STTY -eq $TRUE ] && echo >&2
$STTYCMD echo
fi
fi
echo -n "$PASS"
}
dbg STATUS "Executing crypto-usb-key.sh ..."
# flag tracking key-file availability
OPENED=$FALSE
# temporary mount path for USB key
MD=/tmp-usb-mount
if [ "x$1" = "x" -o "x$1" = "xnone" ]; then
# default key-file on the USB disk
KEYFILE=.key
else
KEYFILE=$1
fi
# If the file already exists use it.
# This is useful where an encrypted volume contains keyfile(s) for later
# volumes and is now mounted and accessible
if [ -f $KEYFILE ]; then
dbg TEXT "Found $KEYFILE"
cat $KEYFILE
OPENED=$TRUE
DEV="existing mount"
LABEL=""
else
# Is the USB driver loaded?
cat /proc/modules | busybox grep usb_storage >/dev/null 2>&1
USBLOAD=0$?
if [ $USBLOAD -gt 0 ]; then
dbg TEXT "Loading driver 'usb_storage'"
modprobe usb_storage >/dev/null 2>&1
fi
# give the system time to settle and open the USB devices
sleep 7
mkdir -p $MD
dbg TEXT "Trying to get key-file '$KEYFILE' ..."
for SDB in /sys/block/sd*; do
dbg TEXT "Examining $SDB" -n
# is it a USB device?
(cd ${SDB}/device && busybox pwd) | busybox grep 'usb' >/dev/null 2>&1
USB=0$?
dbg TEXT ", USB=$USB" -n
# Is the device removable?
REMOVABLE=0`cat ${SDB}/removable`
dbg TEXT ", REMOVABLE=$REMOVABLE" -n
if [ $USB -ne $TRUE -o $REMOVABLE -ne 1 -o ! -f $SDB/dev ]; then
dbg TEXT ", device `busybox basename $SDB` ignored"
continue # for SDB
fi
for SFS in $SDB/sd*; do
dbg TEXT ", *possible key device*" -n
DEV=`busybox basename $SFS`
# Check if key device itself is encrypted
/sbin/cryptsetup isLuks /dev/${DEV} >/dev/null 2>&1
ENCRYPTED=0$?
DECRYPTED=$FALSE
# Open crypted partition and prepare for mount
if [ $ENCRYPTED -eq $TRUE ]; then
dbg TEXT ", encrypted device" -n
# Use blkid to determine label
LABEL=$(/sbin/blkid -s LABEL -o value /dev/${DEV})
dbg TEXT ", label $LABEL" -n
TRIES=3
DECRYPTED=$FALSE
while [ $TRIES -gt 0 -a $DECRYPTED -ne $TRUE ]; do
TRIES=$(($TRIES-1))
PASS="`readpass \"Enter LUKS password for key device ${DEV} (${LABEL}) (or empty to skip): \"`"
if [ -z "$PASS" ]; then
dbg TEXT ", device skipped" -n
break
fi
echo $PASS | /sbin/cryptsetup luksOpen /dev/${DEV} bootkey >/dev/null 2>&1
DECRYPTED=0$?
done
# If open failed, skip this device
if [ $DECRYPTED -ne $TRUE ]; then
dbg TEXT "decrypting device failed" -n
break
fi
# Decrypted device to use
DEV=mapper/bootkey
fi
dbg TEXT ", device $DEV" -n
# Use blkid to determine label
LABEL=$(/sbin/blkid -s LABEL -o value /dev/${DEV})
dbg TEXT ", label $LABEL" -n
# Use blkid to determine fstype
FSTYPE=$(/sbin/blkid -s TYPE -o value /dev/${DEV})
dbg TEXT ", fstype $FSTYPE" -n
# Is the file-system driver loaded?
cat /proc/modules | busybox grep $FSTYPE >/dev/null 2>&1
FSLOAD=0$?
if [ $FSLOAD -gt 0 ]; then
dbg TEXT ", loading driver for $FSTYPE" -n
# load the correct file-system driver
modprobe $FSTYPE >/dev/null 2>&1
fi
dbg TEXT ", mounting /dev/$DEV on $MD" -n
mount /dev/${DEV} $MD -t $FSTYPE -o ro >/dev/null 2>&1
dbg TEXT ", (`mount | busybox grep $DEV`)" -n
dbg TEXT ", checking for $MD/$KEYFILE" -n
if [ -f $MD/$KEYFILE ]; then
dbg TEXT ", found $MD/$KEYFILE" -n
cat $MD/$KEYFILE
OPENED=$TRUE
fi
dbg TEXT ", umount $MD" -n
umount $MD >/dev/null 2>&1
# Close encrypted key device
if [ $ENCRYPTED -eq $TRUE -a $DECRYPTED -eq $TRUE ]; then
dbg TEXT ", closing encrypted device" -n
/sbin/cryptsetup luksClose bootkey >/dev/null 2>&1
fi
dbg TEXT ", done\n\n" -n
if [ $OPENED -eq $TRUE ]; then
break
fi
dbg CLEAR ""
done
done
fi
# clear existing usplash text and status messages
[ $USPLASH -eq $TRUE ] && msg STATUS " " && msg CLEAR ""
if [ $OPENED -ne $TRUE ]; then
msg TEXT "Failed to find suitable USB key-file ..."
readpass "Enter the LUKS password: "
else
msg TEXT "Success loading key-file from $SFS ($LABEL)"
fi
#
[ $USPLASH -eq $TRUE ] && /sbin/usplash_write "VERBOSE default"
Update 2013-01-24: Travis Burtrum’s overhaul of David G Beausang’s script
Travis Burtrum sent me his overhaul of David G Beausang’s script. The changelog is quite long and it is posted within the script:
Script (click to expand)
#!/bin/sh
# Part of passwordless cryptofs setup in Debian Etch.
# See: https://wejn.org/how-to-make-passwordless-cryptsetup.html
# Author: Wejn <wejn at box dot cz>
#
# Updated by Rodolfo Garcia (kix) <kix at kix dot com>
# For multiple partitions
# http://www.kix.es/
#
# Updated by TJ <linux@tjworld.net> 7 July 2008
# For use with Ubuntu Hardy, usplash, automatic detection of USB devices,
# detection and examination of *all* partitions on the device (not just partition #1),
# automatic detection of partition type, refactored, commented, debugging code.
#
# Updated by Hendrik van Antwerpen <hendrik at van-antwerpen dot net> 3 Sept 2008
# For encrypted key device support, also added stty support for not
# showing your password in console mode.
#
# Updated by Jan-Pascal van Best janpascal/at/vanbest/org 2009-12-07
# to support latest debian updates (vol_id missing, blkid used instead)
#
# Updated by Renaud Metrich renaud.metrich/at/laposte/net 2011-09-24
# to support Ubuntu 10.04 and onward.
# Explanation of the patch:
# The issue reported later against USB was due to the fact that devices in
# /sys/block/*/device point to a relative path on Ubuntu instead of full
# path name. The solution was to cd to that directory and issue a pwd.
# Also, I improved a bit the algorithm to speed up things, typically by
# first checking whether the device (e.g. sdb) was a USB and removable
# stuff, instead of doing the same test on every single partition of the
# device (e.g. sdb1, sdb2, ...).
#
# 2012-03-29
# Updated by dgb for plymouth support in Ubuntu 10.04.3 LTS
#
# Updated by Travis Burtrum <admin@moparisthebest.com> 2013-01-24
# * Merged in MMC support originally by Cromwel Flores <cromwel dot flores at gmail dot com>
# now the same script works with USB or MMC devices if they exist with complete code reuse.
# * Modified to loop while trying to detect USB/MMC devices, sleeping for only one
# second at a time, in case they are ready earlier than expected, instead of just
# sleeping for X seconds (previously 7) and trying once. Significant speedup.
# * Fixed a bug where after finding the key on one device, it would continue looping
# through the rest of the devices. Now it breaks out earlier.
# * Changed a few minor cosmetic things, moved some global variables people might need
# to modify up top, and changed script output to match exactly the standard cryptsetup
# text as of Ubuntu 12.04
# define counter-intuitive shell logic values (based on /bin/true & /bin/false)
# NB. use FALSE only to *set* something to false, but don't test for
# equality, because a program might return any non-zero on error
TRUE=0
FALSE=1
# set DEBUG=$TRUE to display debug messages, DEBUG=$FALSE to be quiet
DEBUG=$TRUE
# default path to key-file on the USB/MMC disk
KEYFILE=".keyfile"
# maximum time to sleep waiting for devices to become ready before
# asking for passphrase
MAX_SECONDS=2
# is plymouth available? default false
PLYMOUTH=$FALSE
if [ -x /bin/plymouth ] && plymouth --ping; then
PLYMOUTH=$TRUE
fi
# is usplash available? default false
USPLASH=$FALSE
# test for outfifo from Ubuntu Hardy cryptroot script, the second test
# alone proves not completely reliable.
if [ -p /dev/.initramfs/usplash_outfifo -a -x /sbin/usplash_write ]; then
# use innocuous command to determine if usplash is running
# usplash_write will return exit-code 1 if usplash isn't running
# need to set a flag to tell usplash_write to report no usplash
FAIL_NO_USPLASH=1
# enable verbose messages (required to display messages if kernel boot option "quiet" is enabled
/sbin/usplash_write "VERBOSE on"
if [ $? -eq $TRUE ]; then
# usplash is running
USPLASH=$TRUE
/sbin/usplash_write "CLEAR"
fi
fi
# is stty available? default false
STTY=$FALSE
STTYCMD=false
# check for stty executable
if [ -x /bin/stty ]; then
STTY=$TRUE
STTYCMD=/bin/stty
elif [ `(busybox stty >/dev/null 2>&1; echo $?)` -eq $TRUE ]; then
STTY=$TRUE
STTYCMD="busybox stty"
fi
# print message to usplash or stderr
# usage: msg <command> "message" [switch]
# command: TEXT | STATUS | SUCCESS | FAILURE | CLEAR (see 'man usplash_write' for all commands)
# switch : switch used for echo to stderr (ignored for usplash)
# when using usplash the command will cause "message" to be
# printed according to the usplash <command> definition.
# using the switch -n will allow echo to write multiple messages
# to the same line
msg ()
{
if [ $# -gt 0 ]; then
# handle multi-line messages
echo $2 | while read LINE; do
if [ $PLYMOUTH -eq $TRUE ]; then
# use plymouth
plymouth message --text="$LINE"
elif [ $USPLASH -eq $TRUE ]; then
# use usplash
/sbin/usplash_write "$1 $LINE"
else
# use stderr for all messages
echo $3 "$2" >&2
fi
done
fi
}
dbg ()
{
if [ $DEBUG -eq $TRUE ]; then
msg "$@"
fi
}
# read password from console or with usplash
# usage: readpass "prompt"
readpass ()
{
if [ $# -gt 0 ]; then
if [ $PLYMOUTH -eq $TRUE ]; then
PASS="$(plymouth ask-for-password --prompt "$1")"
elif [ $USPLASH -eq $TRUE ]; then
usplash_write "INPUTQUIET $1"
PASS="$(cat /dev/.initramfs/usplash_outfifo)"
else
[ $STTY -ne $TRUE ] && msg TEXT "WARNING stty not found, password will be visible"
echo -n "$1" >&2
$STTYCMD -echo
read -r PASS </dev/console >/dev/null
[ $STTY -eq $TRUE ] && echo >&2
$STTYCMD echo
fi
fi
echo -n "$PASS"
}
dbg STATUS "Executing crypto-usb-key.sh ..."
# flag tracking key-file availability
OPENED=$FALSE
# temporary mount path for USB/MMC key
MD=/tmp-usb-mount
# if we were passed a different than default key to use on the command
# line, then use it
[ -n "$1" -a "$1" != "none" ] && KEYFILE=$1 # should use $CRYPTTAB_KEY instead?
# If the file already exists use it.
# This is useful where an encrypted volume contains keyfile(s) for later
# volumes and is now mounted and accessible
if [ -f $KEYFILE ]; then
dbg TEXT "Found $KEYFILE"
cat $KEYFILE
OPENED=$TRUE
DEV="existing mount"
LABEL=""
else
# Is the USB driver loaded?
cat /proc/modules | busybox grep usb_storage >/dev/null 2>&1
USBLOAD=0$?
if [ $USBLOAD -gt 0 ]; then
dbg TEXT "Loading driver 'usb_storage'"
modprobe usb_storage >/dev/null 2>&1
fi
# Is the MMC (SDcard) driver loaded?
cat /proc/modules | busybox grep mmc >/dev/null 2>&1
MMCLOAD=0$?
if [ $MMCLOAD -gt 0 ]; then
dbg TEXT "Loading drivers 'mmc_block' and 'sdhci'"
modprobe mmc_block >/dev/null 2>&1
modprobe sdhci >/dev/null 2>&1
fi
USB_LOADED=$FALSE
mkdir -p $MD
dbg TEXT "Trying to get key-file '$KEYFILE' ..."
for SECONDS_SLEPT in $(seq 1 1 $MAX_SECONDS); do
for SDB in $(ls -d /sys/block/sd* /sys/block/mmc* 2> /dev/null); do
dbg TEXT "Examining $SDB" -n
# is it a USB device?
(cd ${SDB}/device && busybox pwd) | busybox grep 'usb\|mmc' >/dev/null 2>&1
USB=0$?
dbg TEXT ", USB/MMC=$USB" -n
# Is the device removable? (usb devices have this flag set, but mmc devices don't, is it really needed?)
#REMOVABLE=0`cat ${SDB}/removable`
#dbg TEXT ", REMOVABLE=$REMOVABLE" -n
#if [ $USB -ne $TRUE -o $REMOVABLE -ne 1 -o ! -f $SDB/dev ]; then
if [ $USB -ne $TRUE -o ! -f $SDB/dev ]; then
dbg TEXT ", device `busybox basename $SDB` ignored"
continue # for SDB
fi
USB_LOADED=$TRUE
for SFS in $(ls -d $SDB/sd* $SDB/mmc* 2> /dev/null); do
dbg TEXT ", *possible key device*" -n
DEV=`busybox basename $SFS`
# Check if key device itself is encrypted
/sbin/cryptsetup isLuks /dev/${DEV} >/dev/null 2>&1
ENCRYPTED=0$?
DECRYPTED=$FALSE
# Open crypted partition and prepare for mount
if [ $ENCRYPTED -eq $TRUE ]; then
dbg TEXT ", encrypted device" -n
# Use blkid to determine label
LABEL=$(/sbin/blkid -s LABEL -o value /dev/${DEV})
dbg TEXT ", label $LABEL" -n
TRIES=3
DECRYPTED=$FALSE
while [ $TRIES -gt 0 -a $DECRYPTED -ne $TRUE ]; do
TRIES=$(($TRIES-1))
PASS="`readpass \"Enter LUKS password for key device ${DEV} (${LABEL}) (or empty to skip): \"`"
if [ -z "$PASS" ]; then
dbg TEXT ", device skipped" -n
break
fi
echo $PASS | /sbin/cryptsetup luksOpen /dev/${DEV} bootkey >/dev/null 2>&1
DECRYPTED=0$?
done
# If open failed, skip this device
if [ $DECRYPTED -ne $TRUE ]; then
dbg TEXT "decrypting device failed" -n
break
fi
# Decrypted device to use
DEV=mapper/bootkey
fi
dbg TEXT ", device $DEV" -n
# Use blkid to determine label
LABEL=$(/sbin/blkid -s LABEL -o value /dev/${DEV})
dbg TEXT ", label $LABEL" -n
# Use blkid to determine fstype
FSTYPE=$(/sbin/blkid -s TYPE -o value /dev/${DEV})
dbg TEXT ", fstype $FSTYPE" -n
# Is the file-system driver loaded?
cat /proc/modules | busybox grep $FSTYPE >/dev/null 2>&1
FSLOAD=0$?
if [ $FSLOAD -gt 0 ]; then
dbg TEXT ", loading driver for $FSTYPE" -n
# load the correct file-system driver
modprobe $FSTYPE >/dev/null 2>&1
fi
dbg TEXT ", mounting /dev/$DEV on $MD" -n
mount /dev/${DEV} $MD -t $FSTYPE -o ro >/dev/null 2>&1
dbg TEXT ", (`mount | busybox grep $DEV`)" -n
dbg TEXT ", checking for $MD/$KEYFILE" -n
if [ -f $MD/$KEYFILE ]; then
dbg TEXT ", found $MD/$KEYFILE" -n
cat $MD/$KEYFILE
OPENED=$TRUE
fi
dbg TEXT ", umount $MD" -n
umount $MD >/dev/null 2>&1
# Close encrypted key device
if [ $ENCRYPTED -eq $TRUE -a $DECRYPTED -eq $TRUE ]; then
dbg TEXT ", closing encrypted device" -n
/sbin/cryptsetup luksClose bootkey >/dev/null 2>&1
fi
dbg TEXT ", done"
if [ $OPENED -eq $TRUE ]; then
break
fi
dbg CLEAR ""
done
# if we found the keyfile on one device, we don't want to process any more
if [ $OPENED -eq $TRUE ]; then
break
fi
done
# didn't find the keyfile, if USB is loaded we must give up, otherwise sleep for a second
if [ $USB_LOADED -eq $TRUE ]; then
dbg TEXT "USB/MMC Device found in less than ${SECONDS_SLEPT}s"
break
elif [ $SECONDS_SLEPT -ne $MAX_SECONDS ]; then
dbg TEXT "USB/MMC Device not found yet, sleeping for 1s and trying again"
sleep 1
else
dbg TEXT "USB/MMC Device not found, giving up after ${MAX_SECONDS}s... (increase MAX_SECONDS?)"
fi
done
fi
# clear existing usplash text and status messages
[ $USPLASH -eq $TRUE ] && msg STATUS " " && msg CLEAR ""
if [ $OPENED -ne $TRUE ]; then
dbg TEXT "Failed to find suitable USB/MMC key-file ..."
readpass "$(printf "Unlocking the disk $CRYPTTAB_SOURCE ($CRYPTTAB_NAME)\nEnter passphrase: ")"
else
dbg TEXT "Success loading key-file from $SFS ($LABEL)"
msg TEXT "Unlocking the disk $CRYPTTAB_SOURCE ($CRYPTTAB_NAME)"
fi
#
[ $USPLASH -eq $TRUE ] && /sbin/usplash_write "VERBOSE default"
Update 2019-01-24: “Chew, Kean Ho”’s version for Stretch and other improvements
Holloway sent me this nice message explaining how he took inspiration in the script for his project:
It helps greatly in my exploration for building an open-source usb-TPM project code-named ‘Devora’.
I re-wrote the script from scratch mainly to enable unit-testing capability, update to Debian Stretch, and some touch-ups features. I’ll add the unit tests in a separate patch after I’m done with my grub2 auto-unlock with keyfile exploration. You can find the new script in my GitLab project here: https://gitlab.com/ZORALab/devora/blob/next/shell/keyscan.sh
Might be interesting for you to check the Devora project.