Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Tutorial for installing a 64-bit Arch Linux ARM system on the Raspberry Pi 3B+, with an encrypted root filesystem, and the option to remotely unlock it via a pre-boot SSH daemon.

Arch Linux ARM 64 on Raspberry Pi 3 B+ With Full Disk Encryption And SSH Unlock: 2018 Edition

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.

Differences to the 32-bit arch linux arm version:

  • probably better performance
  • can run 64-bit software
  • comes without the proprietary video-driver blobs
  • uses the linux-aarch64 mainline kernel instead of linux-raspberrypi
  • uses Das U-Boot instead of the normal raspberry boot process

The 32-bit version images are named AchlinuxARM-rpi-2-latest.tar.gz, and are usable for the Raspberry Pi version 2 and 3, while the 64-bit version images are named AchlinuxARM-rpi-3-latest.tar.gz.

For different setup options, see the end of the document.

Get The Image and check the signature

wget http://os.archlinuxarm.org/os/ArchLinuxARM-rpi-3-latest.tar.gz.sig
wget http://os.archlinuxarm.org/os/ArchLinuxARM-rpi-3-latest.tar.gz
gpg --verify ArchLinuxARM-rpi-3-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

Installation

Basically, follow the installation instructions from archlinuxarm.org, 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/mmcblk0p3 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.

Prepare the rescue system

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

To be on the safe side, reboot your system now, and log in again.

Install the mkinitcpio tools

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.

Set up SSH

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.

Prepare the initial ramdisk

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)

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.

Set up the encrypted partition

sudo cryptsetup luksFormat -c aes-xts-plain64 -s 512 -h sha512 --use-random -i 1000 /dev/mmcblk0p3
sudo cryptsetup luksOpen /dev/mmcblk0p3 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.

Sync the system

Now, copy the prepared system to the encrypted partition:

sudo rsync --info=progress2 -axHAX / /mnt/

Adjust Partitions

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/mmcblk0p3   none   luks

Configure the bootloader

Note: This differs a lot from the 32-bit arch linux arm process, since U-Boot is used as bootloader. More information on the new boot process

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/mmcblk0p3: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 after setenv 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 more net options.
  • You can also set a different MAC address in the setenv line, e.g with: " smsc95xx.macaddr="ab💿ef:01:23:45".
  • For problems with building the boot image, see the U-Boot Documentation

Moment Of Truth

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!

Configure the new system

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!

Notes

  • 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/mmcblk0p1 boot
mount /dev/mmcblk0p2 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/mmcblk0p3 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 and ssh 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 packages mkinitcpio-netconf, mkinitcpio-dropbear and mkinitcpio-utils.

  • The sleep hook is not strictly necessary, but without it, on some systems, there is a race-condition. The smsc95xx module has not initialized the network interface yet before the net hook tries to configure it.

  • Instead of the netconf hook from the package mkinitcpio-netconf, the net hook from the package mkinitcpio-nfs-utils can be used to parse the ip= 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)

Other Setup Choices

Arch Linux System: You can still use the 32-bit rpi-2 image for the Raspberry Pi 3, but the installation process will be different. Especially the boot process differs a lot. Basically, you need to edit to add initramfs initrd followkernel to /boot/config.txt, and cryptdevice=/dev/mmcblk0p3:root root=/dev/mapper/root to /boot/cmdline.txt, instead of editing /boot/boot.txt and running mkscr. To get more information, follow the links below.

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-3 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-3 64-bit version.

Links

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://wiki.archlinux.org/index.php/Dm-crypt/Specialties#Remote_unlocking_of_the_root_(or_other)_partition

https://raspberrypi.stackexchange.com/questions/67051/raspberry-pi-3-with-archarm-and-encrypted-disk-will-not-boot-how-can-be-identif

Older, mostly outdated tutorials:

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

https://project.altservice.com/issues/289

@H3F3A

This comment has been minimized.

Copy link

commented Dec 10, 2018

Cool stuff, thank you for sharing!
I found the rescue partition particularly useful.

A few minor additions:

  • I can confirm DHCP config is working on boot. E.g. ip=::::pi_rescue:eth0:dhcp.
  • I had to add a ECDSA host key (besides the RSA one) to /etc/dropbear to avoid dropbear failing with Unable to read Key error on boot (mkinicpio hook did not complain). This only happened to me after my first boot / update of initramfs.
  • On my Raspberry Pi 3B+ i need to have a screen connected via HDMI at boot. Otherwise the Ethernet connector is not started correctly (recieves power, but no IP config is set). This is independent of whether I use static or dynamic IP configuration. I triple-checked my mkinitcpio.conf, looks fine. Can anyone reproduce this?
@gea0

This comment has been minimized.

Copy link
Owner Author

commented Jan 2, 2019

Hi, thanks for your feedback, and for confirming that dhcp works.

For the dropbear issue: This is strange, i remember the message about the ECDSA key, but i think it booted anyways. I appended a note for that.

I reproduced the issue of the network interface not coming up without having a HDMI cable plugged in.
As far as i can see, this is not related to HDMI, but it is some kind of a race condition:
The mkinitcpio netconf hook does not wait until the the driver smsc95xx has been loaded.
So sometimes at boot, it tries to configure a network interface which has not been initialized.

Replacing the netconf hook with net, from the package mkinitcpio-nfs-utils, did not help either.
So i propose to simply add the sleep hook before netconf, this worked for me.
My line is now:
HOOKS=(base udev autodetect modconf block keymap sleep netconf dropbear encryptssh filesystems keyboard fsck)

For completeness, here are the parts from the boot-log when it fails:

[   10.010371] smsc95xx 
:: running hook [netconf]
ipconfig: eth0: SIOCGIFINDEX: no such device
ipconfig: no devices to configure
[   10.256442] smsc95xx 1-1.1:1.0 eth0: register 'smsc95xx' at usb-3f980000.usb-1.1, smsc95xx USB 2.0 Ethernet, ab:cd:ef:gh:12:34
IP-Config: eth0: /
IP-Config: eth0: gw:   dns0:    dns1:
:: running hook [dropbear]

And here, how it should be:

[   10.010371] smsc95xx 
[   10.256442] smsc95xx 1-1.1:1.0 eth0: register 'smsc95xx' at usb-3f980000.usb-1.1, smsc95xx USB 2.0 Ethernet, ab:cd:ef:gh:12:34
:: running hook [netconf]
[   10.456371] smsc95xx  1-1.1:1.0 eth0: hardware isn't capable of remote wakeup
[   10.526428] IPV6: ADDRCONF(NETDEV_UP): eth0: link is not ready
IP-Config: eth0: 192.168.1.101/255.255.255.0   
IP-Config: eth0: gw: 192.168.1.1   dns0: 0.0.0.0 dns1: 0.0.0.0
:: running hook [dropbear]
@nghamilton

This comment has been minimized.

Copy link

commented May 1, 2019

I had to add libgcc_so.1 to encryptssh to be able to boot when using encryptssh on linux-aarch64; there is an open issue on this at grazzolini/mkinitcpio-utils#13.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.