LUKS
Documentation
- LUKS - Linux Unified Key Setup
- /usr/share/doc/cryptsetup/CryptRoot.HowTo.txt and /usr/share/doc/cryptsetup/README.initramfs.gz
To encrypt the swap
apt-get install cryptsetup
Follow instructions of /usr/share/doc/cryptsetup/CryptoSwap.HowTo
The diff is that I had to destroy the content of the swap partition before /etc/init.d/cryptdisks otherwise cryptsetup refuses to work.
To encrypt disks
Creation
cryptsetup luksFormat /dev/hdaX cryptsetup luksOpen /dev/hdaX hdaX mkfs.ext3 /dev/mapper/hdaX cryptsetup luksClose hdaX
Usage
cryptsetup luksOpen /dev/hdaX hdaX && mount -t ext3 /dev/mapper/hdaX /mnt/ umount /mnt && cryptsetup luksClose hdaX
To encrypt the root fs
Get packages
To use the XTS block chaining method we need a recent kernel (>=2.6.24 and 2.6.24 had apparently a bug related to XTS on some CPUs so I went for 2.6.25)
apt-get install initramfs-tools cryptsetup linux-image-2.6.25-2-686
If you didn't have a separate /boot partition, make one in clear as we cannot boot on an encrypted kernel & initrd!
Have /boot on a separate partition
If it's not yet done, it's time!
Moving /boot to a separate partition involves a crucial step:
Recreating the MBR stage1 so it founds the new location of stage2
cf http://www.troubleshooters.com/linux/grub/grubpartition.htm
Assuming your /boot partition is /dev/[hs]da1, here's how you do it:
grub grub> root (hd0,0) grub> setup (hd0) grub> quit
/boot/grub/menu.lst needs the following changes:
# groot=(hd0,0) # splashimage=(hd0,0)/grub/...
FYI and to understand my instructions, here's my intended layout:
# /dev/sda1 /boot # /dev/sda2 will be the encrypted / # /dev/sda5 encrypted swap # /dev/sda6 /home
reboot to your temp / after you've altered the table of partitions
Creation of the encrypted volume
Backup the original partition
dd if=/dev/sda2 of=./sda2.img bs=1024k
Fill it with random data
dd if=/dev/urandom of=/dev/sda2
Create a LUKS volume
cryptsetup luksFormat -c aes-xts-plain -s 256 /dev/sda2 YES my_boot_password
Edit /etc/crypttab and add a ref to our new partition
echo "croot /dev/sda2 none luks" >> /etc/crypttab
Start the encrypted root filesystem (don't worry if your swap is already started)
/etc/init.d/cryptdisks start my_boot_password
Setup the filesystem
mkfs.ext3 /dev/mapper/croot
Mount the device
mount /dev/mapper/croot /mnt/disk
Copy your root filesystem into place, sth like this in the simplest case
cp -axv / /mnt/disk
Make sure the root device is listed in /etc/fstab
/dev/mapper/croot / ext3 defaults 0 1
/boot/grub/menu.lst needs to point to /dev/mapper/croot:
# kopt=root=/dev/mapper/croot ro vga=791
Regenerate the initramfs image
dpkg-reconfigure linux-image-2.6.25-2-686
Reboot
Avoiding to type many times the LUKS password
One major drawback on my setup (you don't see it here) is that I've several partitions encrypted as such and it leads to some problems:
- At boot time I've to enter the passphrase for each of the partitions
- I tried the "noauto" keyword in /etc/crypttab to avoid mounting some of the partitions but it didn't work, I've to find out why.
- One solution is to use a keyfile stored in the root partition to decrypt the other partitions but I don't want to give access to all partitions to those I give access to my rootfs (e.g. my homedir to my employer)
- Another solution is to use keyfiles stored on a USB stick, which means I've to wear such USB stick and not getting it stolen aside my laptop...
- The last solution I see is to implement something like the gpg or ssh agents to remember briefly my passphrase during boot time and try it against all partitions.
- quintuple-agent could be used for example, but it has to be integrated into the initrd
- maybe a simple environment variable would be enough
That's finally the last solution I implemented, composed of one part that will join the initramfs and capture the LUKS password to tmpfs and one part that will use it during rc stage:
[{{#file:cryptoroot_persist}} /etc/initramfs-tools/hooks/cryptoroot_persist] (make it executable)
#!/bin/sh
# List the soft prerequisites here. This is a space separated list of
# names, of scripts that are in the same directory as this one, that
# must be run before this one can be.
#
PREREQ=""
prereqs()
{
echo "$PREREQ"
}
case $1 in
# get pre-requisites
prereqs)
prereqs
exit 0
;;
esac
. /usr/share/initramfs-tools/hook-functions
# Fix bug #486916 that copies /lib/cryptsetup/askpass to /lib/cryptsetup
if [ -x /lib/cryptsetup/askpass ] && [ -f "$DESTDIR/lib/cryptsetup" ]; then
rm -f "$DESTDIR/lib/cryptsetup"
copy_exec /lib/cryptsetup/askpass
fi
# Patch cryptroot script to export LUKS passphrase
cat << EOF | patch -p0
--- $DESTDIR/scripts/local-top/cryptroot 2008-06-13 23:58:53.000000000 +0200
+++ $DESTDIR/scripts/local-top/cryptroot 2008-06-13 23:45:27.000000000 +0200
@@ -182,8 +182,10 @@
# Prepare commands
if /sbin/cryptsetup isLuks \$cryptsource > /dev/null 2>&1; then
cryptcreate="/sbin/cryptsetup -T 1 luksOpen \$cryptsource \$crypttarget"
+ cryptpersist=true
else
cryptcreate="/sbin/cryptsetup -T 1 -c \$cryptcipher -s \$cryptsize -h \$crypthash create \$crypttarget \$cryptsource"
+ cryptpersist=false
fi
cryptremove="/sbin/cryptsetup remove \$crypttarget"
NEWROOT="/dev/mapper/\$crypttarget"
@@ -205,6 +207,11 @@
usplash_write "INPUTQUIET Enter password for \$crypttarget: "
PASS="\$(cat /dev/.initramfs/usplash_outfifo)"
echo -n "\$PASS" | \$cryptcreate > /dev/null 2>&1
+ \$cryptpersist && echo -n "PASS=\$PASS" > /dev/.initramfs/pass
+ elif \$cryptpersist; then
+ PASS=\$(/lib/cryptsetup/askpass "Enter passphrase:" < /dev/console 2> /dev/console)
+ echo -n "\$PASS" | \$cryptcreate > /dev/console 2>&1
+ echo -n "PASS=\$PASS" > /dev/.initramfs/pass
else
\$cryptcreate < /dev/console > /dev/console 2>&1
fi
EOF
if [ $? -ne 0 ];
then
echo "An error occured in $0: patching cryptroot script failed" >&2
exit 1
fi
exit 0
And a [{{#file:cryptdisks.functions.diff}} patch for /lib/cryptsetup/cryptdisks.functions]
--- /lib/cryptsetup/cryptdisks.functions 2008-03-31 16:36:32.000000000 +0200
+++ /lib/cryptsetup/cryptdisks.functions 2008-06-13 23:51:39.000000000 +0200
@@ -299,6 +299,8 @@
tried=$(( $tried + 1 ))
done
else
+ [ "$PASS" != "" ] && \
+ echo -n "$PASS" | cryptsetup $PARAMS luksOpen "$src" "$dst" || \
cryptsetup $PARAMS luksOpen "$src" "$dst" <&1 || tried="$TRIES"
fi
@@ -576,6 +578,10 @@
modprobe -qb dm-crypt || true
dmsetup mknodes > /dev/null 2>&1 || true
log_action_begin_msg "Starting $INITSTATE crypto disks"
+ if [ -f /dev/.initramfs/pass ]; then
+ . /dev/.initramfs/pass
+ rm /dev/.initramfs/pass
+ fi
mount_fs
egrep -v "^[[:space:]]*(#|$)" "$TABFILE" | while read dst src key opts; do
We can go one step further by
Enabling autologin
Indeed we already did the hardest security step: providing the LUKS password, so why should I prove I know my user password as well, sth so easy to circumvent with a LiveCD...
To enable autologin, you can use GDM or KDM facilities or (as I'm used of launching startx manually) you can choose a lighter way:
Add to /etc/inittab:
9:2345:respawn:/sbin/getty -L -n -l /usr/local/sbin/autologin 38400 tty9
This will launch another getty on tty9 without login prompt but a call to a handmade script /usr/local/sbin/autologin:
#!/bin/sh /bin/login -f phil AUTOX=true
And so if you want startx to be called automatically you can add to your ~/.bash_profile:
if $AUTOX = true then AUTOX=false startx logout fi
This method was inspired by Linux Mag France no 107. I added the AUTOX=false otherwise calls to "xterm -ls" in the graphical session would fail.