ArchLinux on LUKS-encrypted Btrfs with UEFI

Recently I have upgraded my system to Lenovo ThinkPad X1 Carbon Gen2 laptop. I decided to install relatively complicated setup: ArchLinux on Btrfs with full drive encryption (LUKS) and UEFI boot from USB key with /boot and LUKS header.

It allows to have deniable encryption (LUKS header on USB key, laptop's SSD is entirely encrypted), two-factor authorization (you can't load without LUKS header which is encrypted with your password). UEFI boot is just for fun. I highly recommend to read all ArchWiki pages about full disk encryption to understand different stages of installation.

I have choosed Btrfs because it is a modern, fast filesystem and has some cool features like snapshots and dynamic subvolumes. It can also manage its partitions (subvolumes) without partition table. As we put /boot on USB key, we can give entire SSD for Btrfs (no swap support though). Another important question is TRIM/discard support. In this setting it is totally possible, but it is considered insecure. It is up to you to decide.

I have read lots of wiki pages and forums to figure out the installation process. So I want to explain it step-by-step for other people.

As USB key I have chosed Integral Fusion USB 3.0. It has rather good read speed, but awful write speed (not important for me). It is also very small and has no cap.

DISCLAIMER: You do everything described on your own risk. By the way, you will destroy all the data present on your laptop. I hope you understand it. If it isn't clear, please re-read ArchWiki.


First of all, don't forget to update your BIOS version. It can be done from Windows slightly easier. You need another USB key to write down ArchLinux installation image. Then go to BIOS and set the boot mode as UEFI first. Boot from this USB in UEFI mode. On X1 Carbon you should press F12 after powering on to choose USB device to boot from.

If you have a laptop with HiDPI you will be surprised with such a small font. Fix it with command:

setfont sun12x22

It becomes a bit better. Actually it is the largest console font available. Then check that you are in UEFI mode:

efivar -l

If you get an error, go again to BIOS. Now you need to connect to the Internet. I connect via WiFi so:

wifi-menu

Double check that you have an Internet access. First of all, wipe the disk. I amn't sure if it really necessary with the SSD, but it is widely recommended (especially for deniable security). To fill a disk with pseudo-random data you can use /dev/urandom (it is too slow) or open the whole disk as an encrypted volume and write zeros inside. The sequence of zeros will be encrypted in very messy data. If you are really serious about deniable security, choose the same cipher that you want to use later. I need to put an usual disclaimer that next actions are irreversible, you destroy all data on /dev/sdX (it is your SSD by the way).

cryptsetup open --type plain /dev/sdX ssd

Enter anything as password.

ddrescue -f /dev/zero /dev/mapper/ssd

It'll take a while. Hopefully SSD is fast, for me it was a bit less than 10 min.

cryptsetup close ssd

Now initialization of bootable USB key. I will denote it as /dev/sdY.

gdisk /dev/sdY

Create new GPT partition table and small partition for /boot (about 300-500Mb). Define its type as EF00 (in gdisk EFI System Partition). Exit from gdisk and format it in FAT32:

mkfs.fat -F32 /dev/sdY1
mkdir /efi
mount /dev/sdY1 /efi
cd /efi

Next create an empty file for LUKS header (you might modify header size if you choose other encryption settings):

truncate -s 2M header.img

Create device-mapping encrypted device with this header. Before choosing a cipher, you can test the speed of your system with

cryptsetup benchmark

If you choose XTS mode, remember that effective key size is divided by two. Let's create an encrypted device:

cryptsetup --cipher=aes-xts-plain64 --hash=sha512 --verify-passphrase --key-size=256 luksFormat /dev/sdX --header header.img
cryptsetup open --header header.img --type luks /dev/sdX root

Next create the filesystem and mount it. If you decide to enable TRIM, add discard to mount options:

mkfs.btrfs -L "ARCHROOT" /dev/mapper/root
mount -o defaults,noatime,ssd /dev/mapper/root /mnt/btrfs-root
btrfs subvolume create /mnt/btrfs-root/__active
btrfs subvolume create /mnt/btrfs-root/__active/home
btrfs subvolume create /mnt/btrfs-root/__active/var

You can add some other subvolumes if you want.

mount -o subvol=__active /dev/mapper/root /mnt

Change default permissions (700):

chmod 755 /mnt/btrfs-root/__active
chmod 755 /mnt/btrfs-root/__active/home
chmod 755 /mnt/btrfs-root/__active/var

Before chrooting remount USB key:

umount /efi
mkdir /mnt/boot
mount /dev/sdY1 /mnt/boot

Now you can proceed with ordinary install, you can consult ArchWiki installation guide:

nano /etc/pacman.d/mirrorlist
pacstrap /mnt base base-devel wpa_supplicant gummiboot
genfstab -U -p /mnt >> /mnt/etc/fstab

Later you can add noauto option in fstab for /boot partition. Nevertheless, it must be mounted to update the kernel. Now we are ready to go inside!

arch-chroot /mnt /bin/bash
nano /etc/locale.gen

Uncomment your favorite locale, for example, en_US.UTF-8 UTF-8.

locale-gen
echo LANG=en_CA.UTF-8 > /etc/locale.conf
export LANG=en_US.UTF-8

Choose your timezone

ls /usr/share/zoneinfo/
ln -s /usr/share/zoneinfo/<continent>/<city> /etc/localtime
hwclock --systohc --utc

In the next file you should enter

FONT=sun12x22
KEYMAP=us

or another keymap in which you have password:

nano /etc/vconsole.conf

Store the desired network name:

nano /etc/hostname

You could make a netctl profile for the first boot. Then set root password:

passwd

Now it is an important moment. You need to set up initcpio hooks to successfully unlock the disk. Unfortunately, default encrypt hook doesn't yet support remote LUKS header, so you need to modify it.

nano /etc/mkinitcpio.conf

Remove fsck hook, insert

keyboard keymap consolefont encrypt2

just before filesystems hook (keyboard exists normally, but you should move it before encrypt2). Add also

MODULES="loop"
FILES="/boot/header.img"

I added also in MODULES i915 to enable early KMS on my laptop. Create encrypt2 hook as described in ArchWiki

cp /lib/initcpio/hooks/encrypt{,2}
cp /usr/lib/initcpio/install/encrypt{,2}
nano /lib/initcpio/hooks/encrypt2

Now you are ready to regenerate initramfs image:

mkinitcpio -p linux

It is time to install bootloader. I decided to use gummiboot because it is purely UEFI, simple, text-based. You could use GRUB2 or rEFInd:

gummiboot install

Insert following files. If you don't want menu, insert timeout 0. In this case you can summon it if you press space while loading.

Put the following text into file /boot/loader/loader.conf:

default  arch
timeout 3

And create a corresponding file /boot/loader/entries/arch.conf:

title Arch Linux
linux /vmlinuz-linux
initrd /initramfs-linux.img
options cryptdevice=/dev/sdX:root:header root=/dev/mapper/root rootflags=subvol=__active rw

Add ,allow-discards after header option if you decided to go with TRIM/discard support.

Hope that it works. It is time to try!

exit
umount /mnt/boot
umount /mnt
cryptsetup close root
reboot
Written on January 15, 2015