Full Disk Encryption
Switching to Disk Encryption
A Raspberry Pi formatted without encryption typically would have a disk layout similar to:
pi@zero:~ $ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
mmcblk0 179:0 0 29.8G 0 disk
├─mmcblk0p1 179:1 0 512M 0 part /boot/firmware
└─mmcblk0p2 179:2 0 30G 0 part /By using a separate Linux machine with an SD card reader, the disk layout of the SD card can be modified offline to make room for a new partition using resize2fs and fdisk. The new partition must be larger than the existing partition since the encrypted partition will have additional metadata stored:
pi@tart:~ $ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 179:0 0 29.8G 0 disk
├─sda1 179:1 0 512M 0 part
├─sda2 179:2 0 7G 0 part
└─sda3 179:3 0 15G 0 part
...Then the new partition can formatted for LUKS, for example using a supported cipher for the Raspberry Pi:
$ sudo cryptsetup --cipher xchacha20,aes-adiantum-plain64 luksFormat /dev/sda3
...
$ sudo cryptsetup luksOpen /dev/sda3 secure
...
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 179:0 0 29.8G 0 disk
├─sda1 179:1 0 512M 0 part
├─sda2 179:2 0 7G 0 part
└─sda3 179:3 0 15G 0 part
└─secure 254:0 0 15G 0 cryptThe data from the existing partition can then be cloned to the encrypted volume, and the UUID can be reset to avoid conflicts:
$ sudo dd if=/dev/sda2 of=/dev/mapper/secure bs=64M status=progress conv=noerror,sync
$ sudo tune2fs -U random /dev/mapper/secure
$ sudo blkid
/dev/mapper/secure: LABEL="rootfs" UUID="09df36ff-24d6-46cb-b1dd-28a33ed18378" BLOCK_SIZE="4096" TYPE="ext4"
/dev/mmcblk0p2: PARTUUID="aa82a918-02"
/dev/mmcblk0p3: UUID="86df4385-ecfc-478f-a62f-08db219fb388" TYPE="crypto_LUKS" PARTUUID="aa82a918-03"
/dev/mmcblk0p1: LABEL_FATBOOT="bootfs" LABEL="bootfs" UUID="F781-C387" BLOCK_SIZE="512" TYPE="vfat" PARTUUID="aa82a918-01"
$ sudo cryptsetup luksClose secureBooting the Raspberry Pi with the SD card will still continue to use the unencrypted system for the root filesystem (/).
pi@zero:~ $ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
mmcblk0 179:0 0 29.8G 0 disk
├─mmcblk0p1 179:1 0 512M 0 part /boot/firmware
├─mmcblk0p2 179:2 0 7G 0 part /
└─mmcblk0p3 179:3 0 15G 0 partTo switch to using the encrypted volume as the root filesystem, the system must be able to unlock the volume during startup. To accomplish this, new /boot/firmware/initramfs files must be created, which contain the initial files loaded.
Installing the cryptsetup-initramfs package adds support for reading /etc/crypttab and requesting a password for unlocking volumes during boot. It does this by adding additional files used by initramfs-tools:
pi@zero:~ $ dpkg -L cryptsetup-initramfs
...
/usr/share/initramfs-tools
/usr/share/initramfs-tools/conf-hooks.d
/usr/share/initramfs-tools/conf-hooks.d/cryptsetup
/usr/share/initramfs-tools/hooks
/usr/share/initramfs-tools/hooks/cryptgnupg
/usr/share/initramfs-tools/hooks/cryptgnupg-sc
/usr/share/initramfs-tools/hooks/cryptkeyctl
/usr/share/initramfs-tools/hooks/cryptopensc
/usr/share/initramfs-tools/hooks/cryptpassdev
/usr/share/initramfs-tools/hooks/cryptroot
/usr/share/initramfs-tools/hooks/cryptroot-unlock
/usr/share/initramfs-tools/scripts
/usr/share/initramfs-tools/scripts/local-block
/usr/share/initramfs-tools/scripts/local-block/cryptroot
/usr/share/initramfs-tools/scripts/local-bottom
/usr/share/initramfs-tools/scripts/local-bottom/cryptgnupg-sc
/usr/share/initramfs-tools/scripts/local-bottom/cryptopensc
/usr/share/initramfs-tools/scripts/local-bottom/cryptroot
/usr/share/initramfs-tools/scripts/local-top
/usr/share/initramfs-tools/scripts/local-top/cryptopensc
/usr/share/initramfs-tools/scripts/local-top/cryptroot
...Set up the crypttab file to list the encrypted volume based on the UUID and ensure it is marked to be included in the initramfs:
pi@zero:~ $ cat /etc/crypttab
root UUID=86df4385-ecfc-478f-a62f-08db219fb388 none luks,initramfsSimilarly, the encrypted volume is designated as the root filesystem:
pi@zero:~ $ cat /etc/fstab
...
/dev/mapper/root / ext4 defaults,noatime 0 1Adding modules related to the cipher used can ensure the required kernel modules are included in the initramfs for the system:
pi@zero:~ $ cat /etc/initramfs-tools/hooks/nbde
#!/bin/sh
PREREQ=""
prereqs()
{
echo "$PREREQ"
}
case $1 in
prereqs)
prereqs
exit 0
;;
esac
. /usr/share/initramfs-tools/hook-functions
...
# Encryption
manual_add_modules algif_skcipher
manual_add_modules xchacha20
manual_add_modules adiantum
manual_add_modules aes_arm64
manual_add_modules sha256
manual_add_modules nhpoly1305
manual_add_modules dm-crypt
...Be sure it’s set as executable:
pi@zero:~ $ ls -ahl /etc/initramfs-tools/hooks/nbde
-rwxr-xr-x 1 root root 1.2K Nov 11 07:57 /etc/initramfs-tools/hooks/nbdeConfiguring initramfs-tools to include “most” modules also helps ensure any required kernel modules are included:
pi@zero:~ $ cat /etc/initramfs-tools/initramfs.conf
...
MODULES=most
...The initramfs files can then be rebuilt:
pi@zero:~ $ sudo update-initramfs -u -v
Latest RPi versions: 6.12.25+rpt-rpi-v8
6.12.25+rpt-rpi-v7l
6.12.25+rpt-rpi-v7
6.12.25+rpt-rpi-v6
Execute: /usr/sbin/update-initramfs -u -k "6.12.25+rpt-rpi-v8" -b /boot -v
...
Copying module directory kernel/crypto
Adding module /usr/lib/modules/6.12.25+rpt-rpi-v8/kernel/crypto/af_alg.ko.xz
Adding module /usr/lib/modules/6.12.25+rpt-rpi-v8/kernel/crypto/ghash-generic.ko.xz
...
Calling hook cryptroot
Adding module /usr/lib/modules/6.12.25+rpt-rpi-v8/kernel/drivers/md/dm-mod.ko.xz
Adding module /usr/lib/modules/6.12.25+rpt-rpi-v8/kernel/drivers/md/dm-crypt.ko.xz
Adding binary /usr/sbin/cryptsetup
Adding binary-link /usr/lib/arm-linux-gnueabihf/libcryptsetup.so.12
Adding binary /usr/lib/arm-linux-gnueabihf/libcryptsetup.so.12.9.0
...
Calling hook nbde
...Finally, the kernel options can updated to use the unlocked encrypted volume as the root filesystem:
pi@zero:~ $ cat /boot/firmware/cmdline.txt
console=serial0,115200 console=tty1 root=/dev/mapper/root rootfstype=ext4 ...The system can then be rebooted. It will ask for the password during startup, then the system will complete booting with the encrypted volume as the root filesystem:
pi@zero:~ $ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
mmcblk0 179:0 0 29.8G 0 disk
├─mmcblk0p1 179:1 0 512M 0 part /boot/firmware
├─mmcblk0p2 179:2 0 7G 0 part
└─mmcblk0p3 179:3 0 15G 0 part
└─root 254:0 0 15G 0 crypt /The changes described above for building the initramfs must now be made to this new filesystem so that update-initramfs will continue to generate an initramfs that will support unlocking during startup.
cryptsetup-initramfs/etc/crypttab/etc/fstab/etc/initramfs-tools/hooks/nbde/etc/initramfs-tools/initramfs.conf
Network-Bound Disk Encryption (NBDE)
Instead of requiring someone to manually enter a password, encrypted volumes can be automatically unlocked during startup by using McCallum-Relyea exchange with other servers. The system will connect to the network and communicate with servers to automatically recover the key needed to unlock the volume. The two packages used for this are clevis, which runs on the system to unlock the volume, and tang, which runs on servers participating in the exchange.
The tang package adds the service and configures a systemd socket to listen for requests. This means tangd is short-lived and only runs when a request is received.
pi@zero:~ $ sudo dpkg -L tang tang-common
...
/lib/systemd/system/tangd.socket
/lib/systemd/system/tangd@.service
/usr/libexec/tangd
/usr/libexec/tangd-keygen
/usr/libexec/tangd-rotate-keys
...The port to listen on can be configured using a systemd override.
pi@zero:~ $ cat /etc/systemd/system/tangd.socket.d/override.conf
[Socket]
# Reset the default port
ListenStream=
ListenStream=0.0.0.0:7500tangd stores data needed for McCallum-Relyea exchange in /var/lib/tang.
pi@zero:~ $ sudo ls -ahl /var/lib/tang/
total 16K
drwxr-x--- 2 _tang _tang 4.0K Nov 7 16:13 .
drwxr-xr-x 30 root root 4.0K Nov 10 13:43 ..
-r--r----- 1 _tang _tang 367 Nov 7 16:13 4fwfWPvoDD-MMDWAZ3vYICX8tLxe44_v7vLZNW0dwRI.jwk
-r--r----- 1 _tang _tang 361 Nov 7 16:13 fpY6lka_Id-eDdKvkL0BwSbmooVcMU3MmPcv6OM_Mbg.jwkBy running tang on servers that are only accessible on the local network and are also difficult to move, such as those without backup power, there can be confidence that the system being unlocked is at a secure location if that system can contact the tang server.
For automatic decryption, the clevis-initramfs package adds clevis to the initramfs and configures clevis to intercept when cryptsetup asks for the volume password at startup.
pi@zero:~ $ sudo dpkg -L clevis-initramfs
/usr/share/initramfs-tools
/usr/share/initramfs-tools/hooks
/usr/share/initramfs-tools/hooks/clevis
/usr/share/initramfs-tools/scripts
/usr/share/initramfs-tools/scripts/local-bottom
/usr/share/initramfs-tools/scripts/local-bottom/clevis
/usr/share/initramfs-tools/scripts/local-top
/usr/share/initramfs-tools/scripts/local-top/clevisEnabling a volume to be used with clevis is done by binding the volume and using Shamir Secret Sharing allows for performing the exchange with multiple servers with a minimum threshold required to complete the exchange. This threshold allows for tuning between availability and security.
pi@zero:~ $ sudo clevis luks bind \
-d /dev/mmcblk0p3 \
sss \
'{
"t": 1,
"pins": {
"tang": [
{"url": "http://192.168.1.118:7500"},
...
]
}
}'Each of the tang servers listed will be contacted to establish trust and perform the initial exchange. Then the necessary data to perform the exchange again will be stored in the LUKS metadata as a token.
pi@zero:~ $ sudo cryptsetup luksDump /dev/mmcblk0p3
LUKS header information
Version: 2
Epoch: 5
Metadata area: 16384 [bytes]
Keyslots area: 16744448 [bytes]
...
Keyslots:
...
1: luks2
Key: 256 bits
Priority: normal
Cipher: xchacha20,aes-adiantum-plain64
Cipher key: 256 bits
PBKDF: pbkdf2
...
Tokens:
0: clevis
Keyslot: 1
Digests:
0: pbkdf2
Hash: sha256
...The JWE in the token contains the configuration for the exchange to reproduce the key needed.
pi@zero:~ $ sudo cryptsetup token export --token-id=0 /dev/mmcblk0p3
{ "type": "clevis", "keyslots": ["1"], "jwe": { "protected": "...", ... } }For a Raspberry Pi that is wirelessly connected, the system can be configured to automatically connect to a Wi-Fi network during startup. With this method, the Wi-Fi credentials will be unencrypted since they are used before the encrypted volume is unlocked. The necessary modules will need to be included in the initramfs to connect to Wi-Fi.
pi@zero:~ $ cat /etc/initramfs-tools/hooks/nbde
...
manual_add_modules brcmfmac
manual_add_modules brcmfmac_wcc
for f in /lib/firmware/brcm/brcmfmac*-sdio.*.bin; do
[ -e "${DESTDIR}${f}" ] || [ -L "${DESTDIR}${f}" ] || copy_file firmware "$f"
done
for f in /lib/firmware/brcm/brcmfmac*-sdio.*.txt; do
[ -e "${DESTDIR}${f}" ] || [ -L "${DESTDIR}${f}" ] || copy_file firmware "$f"
done
copy_exec /usr/sbin/rfkill
copy_exec /sbin/wpa_supplicant
copy_file config /etc/initramfs-tools/wpa_supplicant.conf /etc/wpa_supplicant.conf
...The Wi-Fi configuration file would use the wpa_supplicant format.
pi@zero:~ $ sudo cat /etc/initramfs-tools/wpa_supplicant.conf
country=US
ctrl_interface=/tmp/wpa_supplicant
network={
scan_ssid=1
ssid="..."
psk="..."
}A script can be set to run that configures Wi-Fi with wpa_supplicant before the system attempts to unlock the encrypted volume.
pi@zero:~ $ cat /etc/initramfs-tools/scripts/init-premount/wifi
#!/bin/sh
PREREQ=""
prereqs()
{
echo "$PREREQ"
}
case $1 in
prereqs)
prereqs
exit 0
;;
esac
. /scripts/functions
/usr/sbin/rfkill unblock all
/sbin/wpa_supplicant -i wlan0 -c /etc/wpa_supplicant.conf -P /run/initramfs-wpa_supplicant.pid -B -f /tmp/wpa_supplicant.logOnce the startup process reaches the stage for unlocking the volume, the initramfs scripts added by clevis will ask initramfs-tools to configure networking. The network device used can be configured with the ip kernel option:
pi@zero:~ $ cat /boot/firmware/cmdline.txt
console=serial0,115200 console=tty1 ... cfg80211.ieee80211_regdom=US ip=:::::wlan0:dhcpThe ip kernel option is described in https://www.kernel.org/doc/Documentation/filesystems/nfs/nfsroot.txt 
ip=<client-ip>:<server-ip>:<gw-ip>:<netmask>:<hostname>:<device>:<autoconf>:
<dns0-ip>:<dns1-ip>:<ntp0-ip>Once the network is configured, clevis will attempt to contact the tang servers described in the LUKS token to complete the exchange and reproduce the key, which it then provides to cryptsetup to unlock the volume.
Finally, the Wi-Fi configuration should be reset after the system unlocks the volume which can be done with an additional script set to run afterwards.
pi@zero:~ $ cat /etc/initramfs-tools/scripts/local-bottom/reset-wifi
#!/bin/sh
PREREQ=""
prereqs()
{
echo "$PREREQ"
}
case $1 in
prereqs)
prereqs
exit 0
;;
esac
kill $(cat /run/initramfs-wpa_supplicant.pid)