Generated by spec.rb at: Thu Feb 28 18:04:59 +0100 2013

How to setup passwordless disk encryption in Debian Etch

Table of contents

Introduction

Recently 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: http://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.

Oh, and I won't mind you digg-ing this how-to if you happen to like it.

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:

#!/bin/sh

# Part of passwordless cryptofs setup in Debian Etch.
# See: http://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/

# 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

which can be downloaded here (or viewed as syntax-colored).

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:

#!/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: Ubuntu-specific instructions

Zenon sent me link to his ubuntu hard drive encryption with external key article.

You might find it interesting.

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.

Here's the modified keyscript to load keyfile from SD cards (also in syntax-colored version).

Update: Vast improvements to keyscript

TJ sent me link to his updated version of keyscript. Improvements include:

You can find this version at his site in article titled Hardy RAID-5 Encrypted with Logical Volume Management (mirror here, colored version).

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.

You will find the latest script at TJ's wiki and of course mirror here (and colored version).

Update: Improvement of TJ's script by Hendrik

Hendrik van Antwerpen sent me his update to TJ's keyscript (colored version).

Improvements:

Thanks, Hendrik!

Oh, and in case you're interested, here's diff against tj's script and also colored version of the diff.

Update: Keith's improvement of Hendrik's script for old PCs

Keith Beckman sent me his update to Hendrik's script (colored version).

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 and also colored version of the diff.

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 :
1 - 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.
2 - I also changed the line to read the passphrase from stdin
        read -r A </dev/console >/dev/null
        echo -n "$A"
    with
        /lib/cryptsetup/askpass "password : "
    because the password was printed to screen and I think this is the way
    to simplicity.

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:

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. Get it here (and colored version).

Update 2010-01-05: Martin Muller's comments on Debian squeeze

I received following comment:

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 (plus colored version).

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:

1. 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

2.  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.

3.  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.

The diff is here (+ colored) and the full script is here (+ colored).

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 here it is in it's entirety:

* 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

You can find the script here (+ colored).