My Arch Disk Encryption Setup

Documenting my Arch Linux encryption setup, for when I inevitably have to set it up again :P

6. Oktober 2024 zuletzt geändert 7. Oktober 2024

Diese Seite wird aktuell nicht auf Deutsch bereitgestellt.

I’ve gotten into the habit of doing a full clean-install of my system roughly every year or so. For the last three years, that choice has always been Arch, and I don’t see myself switching to anything else soon.

Each time, I find myself having to remember the exact process of setting up my device the way I want it. I guess this blog entry can serve as notes for my future self. I’ve decided to make them public regardless, in case anyone else finds them useful .

Desired Setup

I want a LUKS-encrypted, clean root partition. Additionally, I want to mount another LUKS-encrypted partition using the same password as the root partition. On boot, both partitions must be unlocked by entering the password only once.

I use systemd-boot. Being the noob that I am, I will rely on archinstall for most of the installation.

In short, our setup will look something like this:

× — nvme
|    |— /boot  Partition  FAT32
|    \— /      Partition  LUKS(BTRFS)
|
\ — hdd
     \— /media Partition  LUKS(BTRFS)

Install from Arch ISO

I use the Arch Linux ISO and “burn” it onto a USB stick with the help of Balena Etcher (AUR / GitHub), then boot into it.

After changing the keyboard locale to German (loadkeys de), I start up archinstall.

Archinstall

I use best-effort partitioning for my NVME. This should create something like:

│ Name | Type    | Filesystem  | Path           | Start   | End        | Size | Flags
----------------------------------------------------------------------------------------
       | primary | fat32       | /dev/nvme0n1p1 |    2048 |    2099200 | 1 GB | Boot, ESP  
       | primary | crypto_LUKS | /dev/nvme0n1p2 | 2099200 | 3907027120 | 1 TB |       

1 GB for the boot partition, and the rest for the LUKS-encrypted partition.
My HDD is already encrypted and contains data, so I don’t touch it during this process.

After the partitions are set up, find the Disk encryption entry below. Here, I use LUKS and set an encryption password—the same one I use for the HDD.

From here, select whatever you need in archinstall. For me, that’s a KDE Desktop Profile, Pipewire for the audio server, firefox and neovim as additional packages, and multilib as an additional repo. Also, don’t forget to configure the network, as archinstall no longer sets it up by default. Make sure to select the correct keyboard locale under Locales, especially if your decryption password contains special characters and you are not using the US keyboard layout.

Post-Archinstall Changes

Once archinstall has done its magic, it’s time to add the additional hard drive.

Add HDD

To do this, I add the HDD’s LUKS partition to /etc/crypttab and reference the mapped, decrypted BTRFS partition in /etc/fstab.

The entry in /etc/crypttab is… basic:

media UUID=${LUKS_UUID}

Here, ${LUKS_UUID} is the UUID of the crypto_LUKS partition, which you can find by running lsblk -f. Make sure it is the UUID of the crypto_LUKS partition, not the decrypted partition.

Once you enter the password (twice) during boot, you’ll have /dev/mapper/root and /dev/mapper/media, corresponding to the respective decrypted partitions.

To get the HDD to mount on boot, add it to /etc/fstab.

You can retrieve the UUID of the decrypted partition by mounting it. Create the mount point (e.g. mkdir /media), then run luksOpen $device $name (e.g., luksOpen /dev/sda1 media). After entering the password, it should appear at /dev/mapper/$name.

Running lsblk -f again should reveal the UUID.

In my case, /etc/fstab contains the following entry for the additional partition:

# encrypted HDD
UUID=${BTRFS_UUID} /media btrfs defaults 0 0

${BTRFS_UUID} is the UUID of the media partition, which is the “child” of the crypto_LUKS partition.

For reference, here’s the lsblk -f output:

NAME        FSTYPE      FSVER            LABEL       UUID                                 FSAVAIL FSUSE% MOUNTPOINTS
sda                                                                                                      
├─sda1      crypto_LUKS 1                            ${LUKS_UUID}                
│ └─media   btrfs                                    ${BTRFS_UUID}                             2T    18% /media
... # etc   

Decrease Decryption Duration

The default decryption time for LUKS-encrypted partitions configured with archinstall tends to be on the longer side—around 6 to 10 seconds. Personally, I don’t want to wait that long.

If you’re okay with a slight compromise in security (quicker brute-forcing), you can replace the key set by archinstall with a less “expensive” one.

I usually aim for a decryption time of around ~1 second.

Using the cryptsetup utility, you can pass your desired duration (“iteration-time”) using the -i or --iter-time parameter in milliseconds.

First, run a benchmark to determine how many iterations are needed to achieve your desired decryption time (e.g., 1000 ms):

cryptsetup benchmark -i 1000

Then, examine the keyslots for your LUKS device:

cryptsetup luksDump $device
# $device is the LUKS partition (where FSTYPE is crypto_LUKS)
# In my case, /dev/nvme0n1p2

LUKS allows multiple keys, and any of these can be used to decrypt the partition. Under the hood, all keys decrypt to a “Master Key” used for the actual decryption. To shorten decryption time, you can add a new key in a separate keyslot and then delete the initial one.

archinstall typically uses keyslot 0. So, when you run luksDump, the output should look something like:

...
 Keyslots:
#  v--------------- Keyslot 0
   0: luks2
         Key:        512 bits
         ...

Add a new key into slot 1 (or any unoccupied slot) using:

#          vvvvvvv-- tries for decryption time around 1000 ms
cryptsetup -i 1000 --key-slot 1 luksAddKey $device

Afterward, run luksDump again, and you should see:

...
 Keyslots:
#  v--------------- Keyslot 0
   0: luks2
         Key:        512 bits
         ...
#  v--------------- The newly added key
   1: luks2
         Key:        512 bits
         ...

Finally, remove the first key by running:

cryptsetup luksKillSlot $device 0

Afterward, luksDump should display:

...
 Keyslots:
#  v--------------- The newly added key
   1: luks2
         Key:        512 bits
         ...

And that’s it! Decryption should now be faster.

Use sd-encrypt Instead of encrypt

By default, even if you select systemd as your boot system, archinstall will use the encrypt hook to decrypt your partition on startup.

This hook works fine if you’re only decrypting the root partition. However, it doesn’t handle additional decryption entries from /etc/crypttab. I believe that sd-encrypt manages decrypting non-root partitions.The result is that you have to enter your password twice: once for the root partition and once for the media partition.

The solution is to use the sd-encrypt hook for decrypting the root partition. sd-encrypt caches the password and reuses it to decrypt the media partition automatically.

To replace encrypt with sd-encrypt, modify the hook in the /etc/mkinitcpio.conf file. Also, don’t forget to add the systemd hook. If you’re using a non-US keyboard layout, add sd-vconsole before sd-encrypt aswell.

In my case, the changes to the HOOKS list look like this:

- HOOKS=(base udev autodetect microcode modconf kms keyboard keymap consolefont block encrypt filesystems fsck)
+ HOOKS=(base systemd udev autodetect microcode modconf kms keyboard keymap consolefont block sd-vconsole sd-encrypt filesystems fsck)

After making these changes, run mkinitcpio -P. Do not forget to run this, or the following changes will result in an unbootable system!

If you see an error like add_systemd_unit: command not found, you forgot to add the systemd hook!

Finally, modify the systemd boot entry.

You should have a config file under /boot/loader/entries/YYYY-MM-DD_HH-mm-ss_linux.conf.

In this file, replace the options line as follows:

  # Created by: archinstall
  # Created on: 2024-10-04_22-40-41
  title   Arch Linux, btw (linux)
  linux   /vmlinuz-linux
  initrd  /initramfs-linux.img
# Replace cryptdevice=... with rd.luks.name=... and use DEVICE_ID instead of PARTUUID
+ options rd.luks.name=${DEVICE_ID}=root root=/dev/mapper/root zswap.enabled=0 rootflags=subvol=@ rw rootfstype=btrfs
- options cryptdevice=PARTUUID=${PREVIOUS_PART_ID}:root root=/dev/mapper/root zswap.enabled=0 rootflags=subvol=@ rw rootfstype=btrfs

${DEVICE_ID} refers to the crypto_LUKS device.

For reference, lsblk -f should show something like this:

NAME        FSTYPE      FSVER            LABEL       UUID                                 FSAVAIL FSUSE% MOUNTPOINTS
...
nvme0n1                                                                                                  
├─nvme0n1p1 vfat        FAT32                        0000-0000                             852.7M    17% /boot
└─nvme0n1p2 crypto_LUKS 2                            11111111-1111-1111-1111-111111111111 <------- use this as DEVICE_ID                
  └─root    btrfs                                    22222222-2222-2222-2222-222222222222    1.7T     4% /var/log
                                                                                                         /home
                                                                                                         /var/cache/pacman/pkg
                                                                                                         /.snapshots
                                                                                                         /

And that’s basically it!

You should now reboot. After entering your password, both partitions should be decrypted, and decryption should be considerably faster .