Adaptive Kind

Mounting LUKS Encrypted Drive on Rasperry Pi on Boot

Published on by

LUKS provides support for encrypted drives on Linux and we can provide password for decryption during the boot sequence over SSH with dropbear so that encrypted drive can mount on startup. I had an itch to set up an encrypted drive on a Raspberry Pi to give the data some protection in case the Raspberry Pi went missing. Given I was upgrading a Raspberry Pi I was using as a small media server, I thought it would be a good time to try out LUKS and dropbear SSH.

Raspberry Pi with SSD

Create the partition

Drop into a sudo interactive shell which I'll stay in throughout this article.

sudo -i

Let's create this partition with parted, for example I used the last 10% of my 240 SSD drive for the LUKS partition.

parted /dev/sda mkpart primary 90% 100%

LUKS and cryptsetup

The Linux Unified Key Setup (LUKS) standards defines for disk encryption. cryptsetup provides an implementation to conveniently set up disk encryption. We'll need to install cryptsetup to create our LUKS partition.

apt install -y cryptsetup

Format the partition we have just created providing a password for the device.

cryptsetup --cipher xchacha20,aes-adiantum-plain64 \
  luksFormat /dev/sda3

Open the LUKS device and provide the password to unlock. This sets up a mapping for the name given, e.g. this command creates a mapping of /dev/mapper/crypt with the name crypt. Mappings a virtual device blocks managed by the Linux device mapper framework.

cryptsetup luksOpen /dev/sda3 crypt

Make the file system on this LUKS device.

mkfs.ext4 /dev/mapper/crypt

Mount the file system

mkdir -p /data/
mount /dev/mapper/crypt /data/

We now have an encrypted drive mounted at /data. We've mounted it manually for now and will cover how to mount it during the boot sequence later in this article.

Why Adiantum cipher?

When we format the LUKS partition we need to choose an appropriate cipher. The default cipher is aes-xts-plain64. Raspberry Pi 4 devices do not provide AES acceleration. LUKS on Raspberry Pi suggests that Adiantum cipher runs faster and Raspberry Pi Encrypted Boot with SSH indicates that aes-xts-plain64 is only fast on a Raspberry Pi 5 due to its hardware AES acceleration

We can benchmark the ciphers with the cryptsetup benchmark command.

cryptsetup benchmark -c xchacha12,aes-adiantum-plain64
cryptsetup benchmark -c xchacha20,aes-adiantum-plain64
cryptsetup benchmark -c aes-xts-plain64
Algorithm Key Encryption Decryption
xchacha12,aes-adiantum 256b 198.4 MiB/s 213.2 MiB/s
xchacha20,aes-adiantum 256b 170.5 MiB/s 179.3 MiB/s
aes-xts 256b 106.4 MiB/s 108.1 MiB/s

This confirms that the Adiantum cipher runs about 80% faster for my setup. Read Fast cipher without needing hardware support (like ChaCha20) for disk encryption for a background on ChaCha20 vs ChaCha12 vs AES for disk encryption. ChaCha12 may be more than adequate for my needs, but ChaCha20 is more future proofed.

IO performance of encrypted drive

We can also do a quick read / write performance check of a file system with

dd if=/dev/zero of=./speed-test.dat bs=20M count=50 oflag=direct ; \
dd if=./speed-test.dat of=/dev/zero bs=20M count=50 oflag=dsync

For my SSD I see:

Type Read Write
unencrypted 380 MB/s 229 MB/s
encrypted (Adiantum) 146 MB/s 172 MB/s
encrypted (AES) 127 MB/s 154 MB/s

We can see there is a performance penalty on the encrypted drive, which is one of the reasons I didn't want to encrypt the whole drive. At some point I'll benchmark this on a Raspberry Pi 5 to see how the AES acceleration fairs. On a Raspberry Pi 5 full disk encryption may have less of a penalty.

Re-encryption

If at any time you want to re-encrypt a device if, perhaps to apply an alternative encryption strategy, you can do so with the cryptsetup reencrypt command.

crypsetup reencrypt --hash sha256 /dev/sda4

Have patience, since this can take some time. For my drive it took 20 minutes to re-encrypt a 10GB partition.

Unlocking an encrypted drive

I would like to mount the encrypted drive on restart. To open the LUKS partition we need to supply the appropriate secret. We have a few options for this, such as providing a key file on removable media or with Trusted Platform Module (TPM) such as the LetsTrust TPM for Raspberry Pi. Or perhaps clevis client to unlock from key provided by tang server.

For my situation, this Raspberry Pi is only managed by me and a USP powers it. This means it rarely has unexpected restarts and I'm on hand to restart when I need it. I can provide the password during the boot process when needed, although I do want to do this remotely from my local machine so I can script it up and trigger it with low effort.

dropbear initramfs

This is where dropbear initramfs comes in.

initramfs is a root file system that loads temporarily into memory during the boot sequence of the Linux kernal. It can perform operations before the real root file system mounts. We can use the initramfs to open up the LUKS partition on system startup.

dropbear provides a lightweight SSH server that can run during the initramfs sequence that allows us to open the LUKS partition at boot time.

Unlocking drive on start up over SSH

Install dropbear-initramfs.

apt install -y dropbear-initramfs

Update /etc/crypttab to define how to open the LUKS partition setting the appropriate UUID for your LUKS partition. We can get the UUID from the blkid command.

LUKS_UUID=$(blkid | grep LUKS | sed 's/.* UUID="\([^"]*\)".*/\1/')
cat >> /etc/crypttab << EOF
crypt UUID=${LUKS_UUID} none luks,initramfs
EOF

Update /etc/fstab to define the mount point for the mapping device from the LUKS partition

cat >> /etc/fstab << EOF
/dev/mapper/crypt  /data ext4 defaults,noatime,nofail          0 1
EOF

Configure the dropbear SSH service that will run during the initramfs sequence. You can configure SSH to listen on a specific port, e.g. 2222, so that there is no confusion (like known hosts fingerprints in ~/.ssh/known_hosts) between SSH during initramfs and SSH to the fully started machine.

sed -i \
  '/DROPBEAR_OPTIONS/c\DROPBEAR_OPTIONS="-jks -I 180 -p 2222 -c cryptroot-unlock"' \
  /etc/dropbear/initramfs/dropbear.conf

Copy SSH authorized_keys file from the local admin user so that the same key used for the admin user SSH login is authorised for use during the initramfs sequence.

cp /home/admin/.ssh/authorized_keys /etc/dropbear/initramfs/

Update the initramfs image.

update-initramfs -u

Reboot

reboot now

When the system reboots the system will wait in the initramfs boot step until you SSH in to provide the password to unlock the LUKS device. We've set up dropbear to listen on port 2222, so let's SSH now into port 2222 with the root user and set the password.

ssh -p 2222 root@angus

Once you enter the password for the encrypted drive, the boot sequence will continue, the SSH connection will drop and once the machine has started up you can connect again with

ssh admin@angus

The encrypted drive should now have mounted.

$ df -k
Filesystem        1K-blocks    Used Available Use% Mounted on
...
/dev/mapper/crypt  22868764      28  21681736   1% /data
...

Thanks

This article has covered how to set up an encrypted drive with LUKS and gives a way to connect remotely to decrypt a drive before the boot sequence completes. It's a little simpler to set up than encrypting the root partition and for my needs, more than adequate.

Many thanks to the following articles for guiding me on this area.