DM-Crypt LUKS
This article aims to get started with DM-Crypt LUKS to be able to install a new system from scratch, using Gentoo installation documents for example, and generate an initramfs with that in no time. So this article will skip right away the premises on why to encrypt a system with DM-Crypt LUKS and on security insights. That said, encrypting a system with DM-Crypt LUKS will immediately put you in a position to choose between security versus usability, and secure versus system speed/responsiveness.
Contents |
Which key (file) mode?
Choosing a key or key file mode depends on the secure requirements of the system: a long and random password with special characters is more secure than an easy dictionary breakable password of course. So to meet the length, randomness and complexity of password requirements a key file seems to be the right spot. However, a key file dose not meet the security/secure requirements side because it is always better to leave no traces behind which could compromise or ease the break ability of an encrypted system or disk. This is where GnuPG crypted key files comes into play which will satisfy almost every aspect with a little minus in security because the key file can be accessible from world.
GnuPG crypted key file
To get a secure key file that could be piped to cryptsetup, one could generate a random key from /dev/random and encrypt it with GnuPG. Or else, a simple password will be sufficient if there are not severe secure/security requirements.
user $ head -c66 /dev/random | uuencode -m - | head -n2 | tail -n1 | gpg --symmetric --cipher-algo aes --armor >/path/to/key.gpgOr to get maximum (528 bits) entropy use the following instead (to get 88 characters).
user $ head -c66 /dev/random | openssl base64 -A | gpg --symmetric --cipher-algo aes --armor >/path/to/key.gpgLUKS crypted key file
To get a simple and secure crypted key file, one could use DM-Crypt LUKS to generate one via loop back device to avoid having an extra binary to deal with, if size and such are limiting factors for an initramfs for example.
root # dd if=/dev/null of=key.lbd bs=512 seek=2050
root # losetup key.ldb
root # cryptsetup luksFormat /dev/loop<n> -c aes-ecb-plain:sha256 -s 256
root # cryptsetup luksOpen /dev/loop<n> key
root # dd if=/dev/random of=/dev/mapper/keyThat's all, now one can use that secure crypted key file to decrypt cyphertext.
Which cipher:hash combination?
I will spare you a cryptographic cipher:hash discussion. Though there is a simple paradigm on secure versus speed for a cipher: secure cipher are usually slow and require more computing cycles. A few benchmarks can be found out there: cipher benchmark for DM-Crypt LUKS. AES is the fastest cipher out there, especially if used in ECB (electronic code book) mode (-c aes-ecb-plain[|benbi|null]) with key size of 128 bits (-s 128), which is widely used. [Excuse me but this information is very very wrong. ECB is extremely rarely used for the very good reason that it is very insecure. Do NOT use ECB mode under any circumstances.] blowfish cipher is just behind, twofish is relatively slower than AES and serpent is the slowest in the cipher set. serpent and twofish is considered to be more secure than AES.
Following the breakage of previous SHA-0 and SHA-1, SHA-2 (SHA-256/224, SHA-512/384) is considered to be secure enough to be used in governmental agencies. Whirlpool, based on AES and its source is open and the authors declared it will remain open, is considered to be more secure than SHA-2. There are other cipher:hash like the RIPEMD family and others: checkout the cipher:hash supported by your kernel by looking at `cat /proc/crypto'.
At this point, you should have decided `-c ... -s ...' argument that will be used to encrypt physical device(s) or partition(s) or cyphertext in DM-Crypt LUKS terms.
Preparing the disk(s)
Lets prepare the disk(s) is the only thing that deviate from the official installation documents along with generating an initramfs.
With the previous section, remains encrypting the physical devices. Before doing just that, one should consider the order of DM stack depending of using RAID, LVM or a modern file system that include both in the file system layer like ZFS.
Using RAID and/or LVM together make it easier to only encrypt the resulting logical volume especially for RAID. If using LVM with fewer logical volume than the number of physical volume, it makes sense to crypt the logical volume. There's no practical advantages to use LUKS on the underlaying volumes of RAID arrays but to raise the complexity while lowing usability.
With a modern file system like ZFS, there's not choice but encrypt the physical volume or vdev in ZFS terms.
Before encrypting the devices, considering the `/boot' partition should be taken into account as many bootloader does not support LUKS. GRUB2 should support LUKS formated devices although I did not try to load kernel+initramfs yet. So some spare space should be allocated for `/boot' if necessary.
GRUB2 also support ZFS so in that case, one could encrypt with '--align-payload 0 --header /dev/<removable_media>|/path/to/file', the whole disk, to set up a more secure setup and be able to claim the "plausible deniability" because nothing in the disk can prove that the disk is encrypted. This, however, require >=sys-fs/cryptsetup-1.4.0.
GnuPG crypted key file should be piped to cryptsetup with something like `gpg -qd /path/to/key |' while LUKS crypted key file via loop back device is given like a regular key file (/dev/mapper/key.lbd) after decryption.
root # cryptsetup luksFormat /dev/sda -ctwofish-xts-plain:wd256 -s 256When done, creating logical volume if using LVM or adding the crypted cyphertext to a vdev can be done then.
Generating an initramfs
After encrypting system or disk(s), one will need an initramfs so that rootfs can be mounted in there and then pass the control to real init. There are a few generic initramfs builder that can be used to accomplish the task such as dracut, mkinitcpio (there's an ebuild ad thread in the forums) sys-kernel/mkinitramfs-ll or even sys-kernel/genkernel[cryptsetup] which has LUKS support.
Now, with a complicated setup one could have to build his/her own to satisfy specific requirements. This where modular or advanced initramfs package shine such as mkinitramfs-ll dracut or mkinitcpio.
The following is a simple script that will build an initramfs with LUKS support for the running kernel or for the kernel version passed as argument 1. Be careful as this will build the initramfs image and copy it into '/boot' so you need to have that mounted (and if you have an existing initramfs for this kernel, it might get overwritten). Also notice that you need a statically linked lvm binary.
#!/bin/bash
kv=${1:-$(uname -r)}
[[ -n "$(uname -m | grep 64)" ]] && arc=64 || arc=32
pushd
mkdir -p initramfs-$kv && pushd initramfs-$kv
mkdir -p {,s}bin lib$arc dev proc sys newroot mnt
[[ "$arc" = "64" ]] && mkdir lib32
ln -s lib$arc lib
mknod -m 600 dev/console c 5 1
mknod -m 666 dev/urandom c 1 9
mknod -m 666 dev/random c 1 8
mknod -m 640 dev/mem c 1 1
mknod -m 666 dev/null c 1 3
mknod -m 666 dev/tty c 5 0
mknod -m 666 dev/zero c 1 5
mknod -m 640 dev/tty1 c 4 1
[[ $(echo "$kv" | cut -d'.' -f1 ) -eq 3 ]] &&
[[ $(echo "$kv" | cut -d'.' -f2) -ge 1 ]] &&
mknod -m 600 dev/loop-control c 10 237
cp $(which bb) bin/busybox || exit 1
cp ../init . && chmod 755 init || exit 1
for app in $(bin/busybox --list-full); do
ln -sf /bin/busybox $app
done
# this is handy for password
keymap="${2:-$(grep -E '^keymap' /etc/conf.d/keymaps|cut -d'"' -f2)}"
loadkeys -b -u $keymap > usr/share/keymaps/${keymap}-$(uname -m).bin
cp $(which cryptsetup) sbin/
cp $(which lvm.static) sbin/lvm
mount /boot &>/dev/null
find . -print0 | cpio --null -ov --format=newc | xz -9 --check=crc32 > /boot/initramfs-$kv.cpio.xz
popd
unset -v arc kv keymapAnd the following is a simple init script which will mount rootfs in initramfs environment. The following script and the previous are adapted from mkinitramfs-ll.
#!/bin/sh
init=/sbin/init # real init to execute after switching to real root
rmap=root # root mapping for dmcrypt
sh=/bin/sh
rescueshell() {
export PS1='rsh:$(tty | cut -c6-):$PWD # '
if which setsid &>/dev/null; then setsid $sh -i 0<$console 1>$console 2>&1
else $sh -i 0<$console 1>$console 2>&1; fi
}
die() {
echo -ne "Dropping into a rescueshell..."
echo -ne "$@"
rescueshell || exec $sh -i
}
kmap() {
local _font=$(echo "$kmap" | cut -d':' -f2)
local _kmap=$(echo "$kmap" | cut -d':' -f1)
if [ -n "$_kmap" ]; then
for _dir in /usr/share/keymaps /etc /; do
if [ -f "$_dir/$_kmap" ]; then
loadkmap < "$_dir/$_kmap" && break
fi
done
fi
if [ -n "$_font" ]; then
for _dir in /usr/share/consolefonts /etc /; do
if [ -f "$_dir/$_font" ]; then
loadfont < "$_dir/$_font" && break
fi
done
fi
}
export PATH=/bin:/sbin
umask 0077
mount -t proc proc /proc
mount -t sysfs sysfs /sys
if grep devtmpfs /proc/filesystems &>/dev/null; then
mount -t devtmpfs devtmpfs /dev
else mount -t tmpfs tmpfs /dev; fi
mdev -s
echo /sbin/mdev > /proc/sys/kernel/hotplug
[ -h /dev/fd ] || ln -fs /proc/self/fd /dev/fd
[ -n /dev/stderr ] || ln -fs /proc/self/fd/2 /dev/stderr
[ -n /dev/stdin ] || ln -fs /proc/self/fd/0 /dev/stdin
[ -n /dev/stdout ] || ln -fs /proc/self/fd/1 /dev/stdout
: ${console:=/dev/tty1}
exec 0<$console 1>$console 2>&1
for arg in $(cat /proc/cmdline); do
case $arg in
rescue*) rescue=1;;
single) level=2;;
*init=*) export init=${arg#*=};;
*root*|kmap*) export $arg;;
esac
done
[ -n "$kmap" ] && kmap
# do your stuff here e.g. opening LUKS device, scanning for LVM etc. (this section
# needs to be tweaked to match your setup (LUKS devices, LVM volume groups etc.)
#
# cryptsetup luksOpen /dev/sda vault
# lvm vgscan
# lvm vgchange -ay vg
# mount /dev/mapper/vg-root /newroot
#
# You should also take care of /dev, /proc and /sys filesystems - mount them into
# the new root (/newroot).
#
# mount -t devtmpfs none /newroot/dev
# mount -t proc none /newroot/proc
# mount -t sysfs none /newroot/sys
exec switch_root /newroot ${init:-/sbin/init} $level
See mkintramfs-ll/init for a fully featured init script.
Finally, you need to tweak the bootloader to use the initramfs - e.g. for Grub, something like this should work
title Gentoo Linux 3.4.0-gentoo root (hd0,0) kernel /boot/kernel-3.4.0-gentoo initrd /boot/initramfs-3.4.0-gentoo.cpio.xz