From Gentoo Wiki
Jump to: navigation, search

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. For those new to this DM stands for Device-mapper, a kernel module for logical volume management. 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.

Which key (file) mode?

Choosing “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 does 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 (cryptsetup is the command line tool to interface with the kernel module dm-crypt), one could generate a random key and encrypt it with GnuPG. Or else, a simple password will be sufficient if there are not severe secure/security requirements.

user $openssl rand -base64 48 | gpg --symmetric --cipher-algo aes --armor >/path/to/key.gpg

Above we are requesting 48 bytes of random data because that will be exactly one line of base64 output.

LUKS 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/zero of=key.lbd bs=512 count=2050
root #losetup -f key.ldb
root #cryptsetup luksFormat /dev/loop<n> -c aes-xts-plain64:sha512 -s 512
root #cryptsetup luksOpen /dev/loop<n> key
root #dd if=/dev/random of=/dev/mapper/key
Note that >=sys-fs/cryptsetup-1.3.0 has loop back device support so two lines can be combined to `cryptsetup luksFormat /path/to/file ...'.

That's all, now one can use that secure crypted key file to decrypt cyphertext.

Which cipher:hash combination?

You can read more about cryptographic cipher:hash elsewhere. 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 and is widely used. Note that dm-crypt supports many different ciphers and block modes, some of which are not considered secure.

blowfish cipher is just behind, twofish is relatively slower than AES and serpent is the slowest in the cipher set and that feature has some positive security characteristics. During the public contest for the AES implementation, Serpent and Twofish were considered to have a higher security tolerance 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.

Twofish tree way seems to be very fast as AES, just compile the three way kernel module to be able to take advantage of your CPU.

Preparing the disk(s)

Preparing the disk(s) is the only thing that deviates from the official installation documents along with generating an initramfs. You may want to add a proper amount of entropy to new disks through some mechanism such as `cat /dev/random | wcs > /dev/XXX' or using other more usable methods be it secure erasing disks. The drawback is... a very long time to complete such a task.

A usable alternative and straight forward method is to set up DM-Crypt LUKS and then zero-ing the whole disk: e.g. after LUKS formating the disks run the following command.

root #dd if=/dev/zero of=/dev/mapper/root

Of course you have to replace root by the actual mapping name. This method will save several hours of secure erasing disks or dozen of hours to set up enough randomness or entropy. This step might be necessary or even required depending on the plausible deniability requirements. Just make sure, afterwards, to not use specific block device commands like TRIM which will destroy this tedious effort. Anyway, nobody would ever want to do this with SSDs, so this is a non issue.

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 256

When 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] (or the next variant) which has LUKS support.


To use sys-kernel/genkernel or sys-kernel/genkernel-next, edit /etc/portage/package.use to enable the cryptsetup USE flag before emerging it. The static USE flag may also be enabled on the sys-fs/cryptsetup so that genkernel will use the system binaries (otherwise it will build its own private copy). The following example will build only an initramfs (not an entire kernel) and enable support for luks. Even if you don't use lvm, `--lvm' option is required to include necessary udev rules.

root #genkernel --luks --lvm initramfs

The genkernel manpage outlines other options depending on system requirements.

The initrd will require parameters to tell it how to decrypt the drive, and they are supplied the same way as other kernel parameters. For example:

FILE grub.conf
title Gentoo Linux 3.4.0-gentoo
root (hd0,0)
kernel /boot/kernel-3.4.0-gentoo crypt_root=UUID=<encrypted partition uuid> root=/dev/mapper/root
initrd /boot/initramfs-3.4.0-gentoo
Note TRIM support may be enabled if the encrypted device is capable (ie. SSD) with root_trim=yes but please read first about the security implications of this outlined in the --allow-discards section of the cryptsetup wiki.


The sys-kernel/dracut package was ported from the RedHat project and serves a similar tool for generating an initramfs. Since it is currently in ~arch for testing, users will need to edit /etc/portage/package.accept_keywords to emerge it. Before doing so, the variable DRACUT_MODULES="crypt" should be added to /etc/portage/make.conf. Other modules may be desired, please refer to Dracut. Generally, the following command will generate a usable default initramfs.

root #dracut -a crypt

The initrd will require parameters to tell it how to decrypt the drive, and they are supplied the same way as other kernel parameters. For example:

FILE grub.conf
title Gentoo Linux 3.4.0-gentoo
root (hd0,0)
kernel /boot/kernel-3.4.0-gentoo root=UUID=<root filesystem uuid> rd.luks.uuid=<encrypted partition uuid>
initrd /boot/initramfs-3.4.0-gentoo.img
Dracut will match UUIDs that are not complete as long as they are not ambiguous, so it is possible to only enter the first stanza for brevity/clarity desired
Note TRIM support may be enabled if the encrypted device is capable (ie. SSD) with rd.luks.allow-discards but please read first about the security implications of this outlined in the --allow-discards section of the cryptsetup wiki.

For a comprehensive list of luks options within dracut please see the section in the Dracut Manual.


This tools is a lightweight and modular variant of the previous well known initramfs generating tools which comes with udev free dependency. It depends only on busybox with mdev by default and depends on extra packages for additional functionalities. So, nor bash, coreutils nor util-linux is bundled into the initramfs. Extra flexibilities are offered as well, like the possibility to have DM-Crypt LUKS on top of LVM or vice versa, btrfs or ZFS on top of DM-Crypt LUKS, DM-Crypt LUKS on top of RAID, detached header (to a device or a file) for dm-crypt LUKS et al.

root #mkinitramfs-ll --luks --lvm --firmware=iwlwifi-5000

Use the following GRUB2 configuration excerpt to get going for LVM/LUKS and regular key file on a removable device setup.

FILE /etc/default/grub
GRUB_CMDLINE_LINUX="root=<VG-LV> luks=reg:LABEL=PENDRIVE:/key.reg lvm=<MAPPING>-UUID=<uuid>"

There is an optional environment variable in the configuration file (mkinitramfs-ll.conf) to set environment variables that have the same effect as the the kernel command line arguments that let boot with a kernel cmdline free kernel. This default cmdline (as environment variables), however, can be disabled at run time if necessary by appending env=No cmdline argument.


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

FILE mkinitramfs.bash
kv=${1:-$(uname -r)}
arc=$(getconf LONG_BIT)

mkdir -p initramfs-$kv && pushd initramfs-$kv
mkdir -p {usr/,}{{,s}bin,lib$arc} dev proc sys newroot mnt/tok
ln -s lib{$arc,}
pushd usr && ln -s lib{$arc,} && popd
mkdir -p usr/share/{consolefonts,keymap}

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 busybox) bin/busybox || exit
cp ../init . && chmod 755 init || exit

# this is handy for password
keymap="${2:-$(sed -nre 's,^keymap="([a-zA-Z].*)",\1,p' /etc/conf.d/keymaps)}"
[[ $keymap ]] && loadkeys -b -u $keymap >usr/share/keymaps/${keymap}-$(uname -m).bin

consolefont="${3:-$(sed -nre 's,^consolefont="([a-zA-Z].*)",\1,p' /etc/conf.d/consolefont)}"
[[ $consolefont ]] && pushd usr/share/consolefonts &&
cp /usr/share/consolefonts/${consolefont}*.gz . &&
gzip -d ${consolefont}*.gz && popd

cp $(which cryptsetup) sbin || exit
cp $(which lvm.static) sbin/lvm && lvm=lvm

function docp()
	local link=${1} prefix
	[[ -n ${link} ]] || return
	cp -a {,.}${link}

	[[ -h ${link} ]] &&
	while true; do
		link=$(readlink ${link})
		[[ ${link%/*} == ${link} ]] && link=${prefix}/${link}
		cp -a {,.}${link} || die
		[[ -h ${link} ]] || break

	return 0

for bin in busybox cryptsetup $lvm; do
    ldd $bin >/dev/null || continue
    for lib in $(ldd $bin  | sed -nre 's,.* (/.*lib.*/.*.so.*) .*,\1,p' \      
        -e 's,.*(/lib.*/ld.*.so.*) .*,\1,p')
        mkdir -p ${lib%/*} && docp {,.}$lib

mount /boot
find . -print0 | cpio --null -ov --format=newc | xz -9 --check=crc32 > /boot/initramfs-$kv.cpio.xz

unset -v arc consolefont kv keymap

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

FILE init
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
export init=/sbin/init newroot=/newroot 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

getdev() {
    echo $(blkid | grep $1 | cut -d: -f1)

for arg in $(cat /proc/cmdline); do                                             
    case $arg in                                                                
        rescue*) export rescue=1;;                                            
        ro|rw) export mtopt=$arg;;                        
        single) export level=2;;
        console*|font*|init*|keyfile*|keymap*|lvm*|root*) export $arg;;                                           

[ $keymap ] && loadkmap </usr/share/keymaps/$keymap
[ $font ] && loadfont </usr/share/consolefont/$font

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/console}
exec 0<$console 1>$console 2>&1

if [ $keyfile ]; then
    dev=$(echo $keyfile | cut -d: -f1)
    key=$(echo $keyfile | cut -d: -f2)
    dev=$(getdev $dev)
    mount $dev /mnt/tok || die

root=$(getdev $root)
[ $root ] || die
cryptsetup open $root root ${key:+-d $key} && root=/dev/mapper/root || die

if [ $lvm ]; then
    # lvm cmdline argument is passed as <vg-lv>, standard way
    lvm vgscan ${lvm%-*}
    lvm vgchange -ay ${lvm%-*} && root=/dev/mapper/$lvm || die

mount $root $newroot

umount -l /mnt/tok
umount /sys
umount /dev
umount /proc

exec switch_root $newroot ${init:-/sbin/init} $level

Note that, LVM is optional, just omit the cmdline argument to remove LVM support.

See mkintramfs-ll/init for a fully featured init script.

Notice that the previous init script support LABEL UUID and raw block device name sd[a-z][0-9] with or without the /dev/ prefix. One can even provide part of a LABEL or UUID, getdev() will just return the block device rightly.

Finally, you need to tweak the bootloader to use the initramfs - e.g. for Grub, something like this should work.

FILE grub.conf
title Gentoo Linux 3.4.0-gentoo
root (hd0,0)
kernel /boot/kernel-3.4.0-gentoo root=UUID<uuid> lvm=<VG-LV> keyfile=LABEL=PENDRIVE:/key
initrd /boot/initramfs-3.4.0-gentoo.cpio.xz
While playing with the initramfs (finding out what needs to be done in the init script), I do recommend to disable automatic start of X Window. It may happen that some of the devices won't work under X (e.g. keyboard and mouse), thus making you stuck on login screen. The chance of this happening in the console is much lower, and you can always start X with something like 'sleep 30; /etc/init.d/xdm' stop in another console.