There are multiple ways to get a full disk encrypted arch linux system on raspberry. In this tutorial, we will install a 64-bit arch linux armv8 system, using dropbear as ssh server for remote pre-boot unlocking of the root filesystem. However, it will still be possible to unlock and use the pi as usual, with a keyboard and monitor. We will also create an unencrypted partition in the installation process, usable as a rescue system.
For different setup options, see the end of the document.
wget http://os.archlinuxarm.org/os/ArchLinuxARM-rpi-aarch64-latest.tar.gz.sig
wget http://os.archlinuxarm.org/os/ArchLinuxARM-rpi-aarch64-latest.tar.gz
gpg --verify ArchLinuxARM-rpi-aarch64-latest.tar.gz.sig
Make sure to verify the GPG-key from Arch Linux ARM Build System <builder@archlinuxarm.org>
and its fingerprint. At this time it is 68B3 537F 39A3 13B3 E574 D067 7719 3F15 2BDB E6A6
Basically, follow the installation instructions from archlinuxarm.org for the "AArch64 Installation", with a few changes:
The boot partition needs to be larger than 100M, use e.g. 300M to be on the safe side. The second partition will be unencrypted and used for the installation system, use 3G or more if you want to include more software here. Make a third partition from the remaining space, it will be our encrypted system.
You should overwrite the third partition with random bytes, to achieve greater forensic resistance:
sudo dd if=/dev/urandom of=/dev/mmcblk1p3 bs=4M status=progress conv=fsync
Now put the sdcard in the pi, apply power, log in (over ssh if you want) as user alarm
, password alarm
. The root password root
.
On the new system on the pi, upgrade, and install the necessary software:
pacman-key --init
pacman-key --populate archlinuxarm
pacman -Syu
pacman -S --needed sudo git rsync base-devel uboot-tools dropbear
You might also want to set a locale, keymap, hostname and everything else you want to have in the rescue system. Use the usual arch wiki installation guide for reference.
Enable sudo (you need it to build packages from AUR).
Use visudo
and append the line alarm ALL=(ALL) ALL
.
To be on the safe side, reboot
your system now, and log in again.
You need the following AUR packages: mkinitcpio-utils mkinitcpio-netconf mkinitcpio-dropbear
.
Using an AUR helper is not strictly necessary, as you can install the mkinitcpio packages manually from the AUR, but it is probably more convenient.
E.g. after installing yay
, use:
yay -S mkinitcpio-utils mkinitcpio-netconf mkinitcpio-dropbear
Note: yay is an especially handy AUR helper on Arch Linux ARM, since it can easily skip architecture checks when building pkgbuilds with an officially unsupported arch.
mkinitcpio-dropbear
only seems to be able to deal with RSA keys. So, on your primary computer, generate a new one:
ssh-keygen -t rsa -b 4096 -a 100 -f ~/.ssh/pi_rescue_key
Transfer it to the pi:
ssh-copy-id -i ~/.ssh/pi_rescue_key.pub alarm@192.168.1.100
(The IP address is probably different, of course) Then, on the pi:
sudo cp ~/.ssh/authorized_keys /etc/dropbear/root_key
The matching lines in your ~/.ssh/config
file should be something like this:
Host pi_rescue
HostName 192.168.1.100
User root
IdentityFile ~/.ssh/pi_rescue
Host pi
HostName 192.168.1.100
User alarm
IdentityFile ~/.ssh/pi_rescue
You can then simply use ssh pi
, and ssh pi_rescue
to unlock at boot.
You might want to backup the files we will be editing:
sudo cp /etc/mkinitcpio.conf /etc/mkinitcpio.conf.rescue
sudo cp /boot/boot.txt /boot/boot.txt.rescue
Or, even better, backup the whole /boot/
partition. If you break your encrypted system, you can simply overwrite the /boot/
partition with the backup, and thus easily boot the rescue system to fix things.
sudo cp -r /boot /root/boot_rescue
In /etc/mkinitcpio.conf
:
Change the line MODULES=()
to
MODULES=(g_cdc usb_f_acm usb_f_ecm smsc95xx g_ether broadcom)
These are needed for the initramfs to contain the ethernet and usb drivers (the ethernet is connected over usb internally). More Information on this.
Also, insert the hooks sleep netconf dropbear encryptssh
before filesystem
in the line HOOKS=()
.
The line should look like this:
HOOKS=(base udev autodetect modconf block sleep netconf dropbear encryptssh filesystems keyboard fsck)
You might also want to add the keymap
hook after block
, and set up a different keymap in /etc/vconsole.conf
, if you want to use a non-US keyboard layout for entering your encryption passphrase.
Then, regenerate the initramfs:
sudo mkinitcpio -P
Note: If you get the Error: Unrecognised key type
message while the mkinitcpio-dropbear
hook is running:
Remove at least one of these ssh hostkeys, and regenerate it in the /etc/ssh
directory with the -m PEM
option.
Example:
cd /etc/ssh
sudo rm ssh_host_*key*
sudo ssh-keygen -t ed25519 -f ssh_host_ed25519_key -N "" -m PEM < /dev/null
sudo ssh-keygen -t rsa -b 4096 -f ssh_host_rsa_key -N "" -m PEM < /dev/null
Then re-run mkinitcpio -P
.
See this dropbear bug on the key converting error.
sudo cryptsetup luksFormat -c aes-xts-plain64 -s 512 -h sha512 --use-random -i 1000 /dev/mmcblk1p3
sudo cryptsetup luksOpen /dev/mmcblk1p3 root
sudo mkfs.ext4 /dev/mapper/root
sudo mount /dev/mapper/root /mnt
The number of iterations in the key derivation function, here -i 1000
, can be increased to make the encryption passphrase more resistant.
With 1000 iterations, it takes about 2 seconds to unlock the partition.
Now, copy the prepared system to the encrypted partition:
sudo rsync --info=progress2 -axHAX / /mnt/
Add to /mnt/etc/fstab
(file on the encrypted partition /mnt/etc/, not in /etc/!):
/dev/mapper/root / ext4 defaults,noatime 0 1
and to /mnt/etc/crypttab
:
root /dev/mmcblk1p3 none luks
More information on the new boot process that follows
You don't have to edit /boot/config.txt
and /boot/cmdline.txt
anymore, also the latter doesn't even exists anymore.
Instead, edit /boot/boot.txt
.
Comment out the part uuid
line, add a static ip setup, the cryptdevice, and change the root filesystem, all in the setenv
line. It should look like this:
# After modifying, run ./mkscr
# Set root partition to the second partition of boot device
#part uuid ${devtype} ${devnum}:2 uuid
setenv bootargs console=ttyS1,115200 console=tty0 ip=192.168.1.100::192.168.1.1:255.255.255.0:pi_rescue:eth0:none cryptdevice=/dev/mmcblk1p3:root root=/dev/mapper/root rw rootwait smsc95xx.macaddr="${usbethaddr}"
if load ${devtype} ${devnum}:${bootpart} ${kernel_addr_r} /Image; then
if load ${devtype} ${devnum}:${bootpart} ${fdt_addr_r} /dtbs/${fdtfile}; then
if load ${devtype} ${devnum}:${bootpart} ${ramdisk_addr_r} /initramfs-linux.img; then
booti ${kernel_addr_r} ${ramdisk_addr_r}:${filesize} ${fdt_addr_r};
else
booti ${kernel_addr_r} - ${fdt_addr_r};
fi;
fi;
fi
After changing the file, regenerate the bootloader image:
cd /boot/
sudo ./mkscr
Notes:
- You can also add
earlyprintk
aftersetenv bootargs
to get more debug output from the boot process. - Of course, adjust your IP address, gateway and subnet mask
- You can also get an IP Address with DHCP here, use e.g.
ip=::::pi_rescue:eth0:dhcp
(See the arch wiki for morenet
options. - You can also set a different MAC address in the
setenv
line, e.g with: " smsc95xx.macaddr="ab:cd:ef:01:23:45". - For problems with building the boot image, see the U-Boot Documentation
Now, reboot
your pi. You should be prompted for a the encryption passphrase when connecting the pi to a screen and a keyboard.
Also, you should be able to connect with ssh pi_rescue
, and enter you passphrase there.
After unlocking, your ssh connection will be dropped.
You can now ssh to your encrypted system with ssh pi
!
You can make all the usual configuration like language, hostname, timezone, NTP, ... you didn't make in the rescue system. It is also possible to use completely different settings here!
- If you broke your encrypted system somehow, and were wise enough to made a backup of your
/boot/
partition: Plug the sd-card into another computer and regain acces to your rescue system like so:
cd $(mktemp -d) && mkdir boot root
mount /dev/mmcblk1p1 boot
mount /dev/mmcblk1p2 root
cp -r root/root/boot_rescue boot/
Then, boot the pi, and log into the rescue system. Depending on how you messed up, you may want to change-root into the encrypted system and fix stuff:
cryptsetup open /dev/mmcblk1p3 root
mount /dev/mapper/root /mnt
arch-chroot /mnt
Or, maybe you need to re-do the steps above after Prepare the rescue system.
-
Currently, the boot process hangs with the message
USB0: scanning bus 0 for devices...
, when some USB-devices are connected. Try different USB-devices or disconnect them before booting the pi. This seems to be a bug in U-Boot. -
If you have issues with ssh, try to connect with
ssh root@192.168.1.100
andssh alarm@192.168.1.100
. The-F /etc/ssh/ssh_config
and-v
are also helpful to debug ssh problems. -
If dropbear, for some reason, didn't use the openssh hostkeys, but created its own, you will see the
WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!
message when connecting to the encrypted system. OpenSSH might also prefer other hostkeys over the rsa ones dropbear uses. The solution is to accept two different hostkeys for the same IP address of the pi. Edit~/.ssh/known_hosts
, search for IP address of your pi. Copy the line and delete it, then ssh to the pi. Now paste the line back into the file, so you have two lines with the same ip, but with different hostkeys. -
Instead of the default
linux-aarch64
kernel, linux-aarch64-raspberrypi-bin from the AUR can be used. This is worth a try if some features are not working, like bluetooth, the Raspberry Touch Display, or video. -
Previously, the AUR package
dropbear_initrd_encrypt
could be used. This was split into the packagesmkinitcpio-netconf
,mkinitcpio-dropbear
andmkinitcpio-utils
. -
The
sleep
hook is not strictly necessary, but without it, on some systems, there is a race-condition. Thesmsc95xx
module has not initialized the network interface yet before thenet
hook tries to configure it. -
Instead of the
netconf
hook from the packagemkinitcpio-netconf
, thenet
hook from the packagemkinitcpio-nfs-utils
can be used to parse theip=
kernel parameter. It is more up-to-date, but so far, there does not seem to be a difference between them. -
You might have to also add an ECDSA key to
/etc/dropbear
, or your first boot could fail. -
In similar tutorials, you often see the advice to wipe the encrypted partition with
/dev/zero
instead of/dev/urandom
. But this doesn't add security, it is basically useless! (Unless you only want to wipe previous data from the sdcard, but then you should wipe the whole card and not one partition. Or, unless, you plan to give the encryption passphrase to someone, and want to be able to prove that there are no hidden containers in the un-used space)
Installation method: Instead of using an additional unencrypted partition to make the install, you can emulate the pi cpu architecture on main computer using the qemu
and qemu-arch-extra
packages. See this tutorial, and adapt it to the new rpi-4
64-bit version of arch linux arm. Also: arch wiki on QEMU
SSH daemon: Instead of using dropbear
, you can also include tinyssh
in the initial ramdisk. See the arch wiki.
mkinitcpio hooks: Instead of using mkinitcpio-dropbear
, mkinitcpio-netconf
, and mkinitcpio-utils
, it can all be done with systemd and the mkinitcpio-systemd-tool
AUR package. See the arch wiki entry on remote unlocking of dm-crypt.
File system: Some folks might want to use btrfs
instead of ext4
on the encrypted filesystem. This gives the advantage See this tutorial, and adapt it for the newer rpi-4
64-bit version.
https://archlinuxarm.org/platforms/armv8/broadcom/raspberry-pi-3#installation
https://github.com/grazzolini/mkinitcpio-netconf
https://github.com/grazzolini/mkinitcpio-dropbear
https://github.com/grazzolini/mkinitcpio-utils
https://www.denx.de/wiki/U-Boot/Documentation
https://wiki.archlinux.org/index.php/Mkinitcpio#HOOKS
https://gist.github.com/gea0/4fc2be0cb7a74d0e7cc4322aed710d38
https://gist.github.com/pezz/5310082
http://www.deadunicornz.org/blog/2013/12/20/raspberrypi-root-partition-encryption/index.html
https://github.com/phortx/Raspberry-Pi-Setup-Guide
https://gist.github.com/morgner/82105e8ce053b22b284eac86ce89555d
https://github.com/NicoHood/NicoHood.github.io/wiki/Raspberry-Pi-Encrypted-Btrfs-Root
https://wiki.polaire.nl/doku.php?id=archlinux-raspberry-encrypted
https://raspberrypi.stackexchange.com/questions/7159/can-the-raspberry-boot-to-an-lvm-root-partition
The solution for me was to instead keep two separate known_hosts files for the two different hosts. Here's the snippet in my
~/.ssh/config
: