One tool that can be used to increase system security is encryption. This article discusses using sdm to configure encryption for the rootfs partition on a Raspberry Pi system disk. This makes the loss of a disk far less of a problem, since the content cannot be read, nor can the disk be booted, without knowing how to decrypt the partition either with a passphrase or a USB Keyfile Disk.
Although encryption does increase security, there are some challenges, such as:
- The rootfs passphrase must be typed on the console every time the Pi reboots, but you can also use a USB Keyfile Disk, or enter the passphrase remotely via SSH. sdm fully supports both methods. Details below.
- rootfs encryption does not make the running system any more secure
- This tool does not provide any way to undo disk encryption if you decide you don't want it
- You'll have to rebuild the system disk
- Good news: If you're using sdm to create your customized IMG, rebuilding your disk is much less of an issue
With those caveats, if rootfs encryption is useful for you, sdm makes it quite simple to configure and use an encrypted rootfs.
NOTES
-
This tool only supports sdm-integrated encryption configuration using the
cryptrootplugin on RasPiOS Bookworm and later.sdm-cryptconfigcan be used on already-running RasPiOS systems as well as on Debian Bookworm (arm and X86_64) and derivatives. -
Your system MUST be fully updated with apt before starting the encryption process documented here (
sudo apt update ; sudo apt full-upgrade) -
Since the encryption process is not reversible you are encouraged to try the process on a COPY of your system disk or a freshly burned/updated disk to ensure you fully understand the process
There are many articles about rootfs disk encryption on the Internet. If you're interested in learning more about it, your favorite search engine will reveal a bazillion articles on the subject.
Additionally, this Wikipedia article discusses LUKS encryption, which is utilized to encrypt your rootfs.
sdm supports enabling rootfs encryption configuration in two different ways:
- sdm-integrated, using the
cryptrootplugin - Standalone on RasPiOS and Debian Bookworm without needing all of sdm by using
sdm-cryptconfigon your running system
These two methods are discussed in the following sections.
The system reboots a couple of times, performing steps during each reboot:
- First system boot: At the end, the
sdm-firstbootservice runs, which completes sdm system configuration and reboots- An sdm FirstBoot script,
/etc/sdm/0piboot/099-enable-auto-encrypt.shruns and configures the servicesdm-auto-encryptto run on reboot
- An sdm FirstBoot script,
- Second boot: At the end of system startup, the
sdm-auto-encryptservice runs which reconfigures the system for encryption and reboots- The
sdm-auto-encryptservice runssdm-cryptconfigto configure the system for encryption and configures thesdm-cryptfs-cleanupservice
- The
- Third boot: System startup drops into initramfs to perform the encryption process
-
In initramfs you use the
sdmcryptfscommand to encrypt rootfs -
Upon initramfs exit, system continues booting
-
At end of system startup the
sdm-cryptfs-cleanupservice tidies sdm-related services on the running system, removes sdmcryptfs-related bits from the initramfs, and then rebootsNOTE: You MUST wait for this stage to automatically reboot or the encryption will fail
-
- Final reboot: System is now running on an encrypted rootfs
- All system boots now require the rootfs unlock passphrase or USB Keyfile Disk to continue
When customizing an IMG or burning an IMG to an SSD/SD Card, you can start the encryption configuration process by using the cryptroot plugin. See cryptroot plugin documentation for details on the cryptroot plugin. This plugin performs several steps:
- Installs the required crypto software:
cryptsetup,cryptsetup-initramfs, andcryptsetup-bin - Configures sdm to create and run the
sdm-auto-encryptservice after the system has fully completed the sdm FirstBoot process - Provides an overview of what steps will be taken to encrypt your system's rootfs
The sdm-auto-encrypt service runs the script sdm-cryptconfig with arguments indicating that it should operate in sdm-integrated mode. See below for details on sdm-cryptconfig.
sdm-integrated rootfs encryption is nearly fully automatic if you use the sdm switch --restart. From the time you first boot your newly-burned disk you'll only need to type 2 commands, both when running in initramfs:
- A command to encrypt rootfs (see below)
exit, to exit the initramfs and continue the system boot on a newly-encrypted rootfs
All other steps are done automatically.
If your RasPiOS system was not built with sdm (why not?), or if your distro is Debian Bookworm-based (or later) you can still use a single sdm script to encrypt your rootfs: sdm-cryptconfig.
When your system is running, simply download and run sdm-cryptconfig:
# sdm-make-luks-usb-key and sdm-add-luks-key are only needed if you want to use a USB Keyfile Disk
sudo curl --fail --silent --show-error -L https://github.com/gitbls/sdm/raw/master/sdm-make-luks-usb-key -o /usr/local/bin/sdm-make-luks-usb-key
sudo curl --fail --silent --show-error -L https://github.com/gitbls/sdm/raw/master/sdm-add-luks-key -o /usr/local/bin/sdm-add-luks-key
sudo chmod 755 /usr/local/bin/sdm-add-luks-key /usr/local/bin/sdm-make-luks-usb-key
# sdm-cryptconfig is required for rootfs encryption
sudo curl --fail --silent --show-error -L https://github.com/gitbls/sdm/raw/master/sdm-cryptconfig -o /usr/local/bin/sdm-cryptconfig
sudo chmod 755 /usr/local/bin/sdm-cryptconfig
sudo sdm-cryptconfig [optional switches; see below]
sdm-cryptconfig performs all necessary configuration before the rootfs can be encrypted:
- Downloads the script
sdmcryptfsfrom Github to /usr/local/bin if it's not present on the system (sdm-enhanced systems will already have it) - Ensures the required disk crypto software is installed:
cryptsetup,cryptsetup-initramfs, andcryptsetup-bin - If SSH access to initramfs was requested,
dropbear-initramfsanddropbear-binare also installed - Updates the initramfs configuration to enable encrypting rootfs (primarily
bashandsdmcryptfs) - Builds the updated initramfs with encryption support
- Updates /boot/firmware/cmdline.txt, /etc/crypttab, and /etc/fstab for an encrypted rootfs
- If sdm-cryptconfig was run via the cryptroot sdm plugin or if
--rebootspecified, the system will automatically reboot- If not, reboot the system manually when you are ready to proceed
sdm-cryptconfig has several switches. When using sdm-integrated rootfs encryption the cryproot plugin takes care of setting the appropriate switches, based on the arguments to the plugin. All switches are optional.
Switches to sdm-cryptconfig include:
--authorized-keys authkeyfile— Specifies an SSH authorized_keys file to use in the initramfs. Required with--ssh--crypto crypt-type— Specifies the encryption to use.aesused by default, which usesaes-xts-plain64. Usexchachaon Pi4 and earlier for best performance. See Encryption/Decryption performance comparison below.--dns dnsaddr— Set IP Address of DNS server--gateway gatewayaddr— Set IP address of gateway--hostname hostname— Set hostname--ipaddr ipaddr— set IP address to use in initramfs--keyfile /path/to/keyfile— A keyfile used for passphrase-less booting. See Unlocking rootfs with a USB Keyfile Disk for details--mapper cryptmapname— Set cryptroot mapper name [Default: cryptroot]--mask netmask— Set network mask for initramfs--nopwd— Do not configure passphrase unlock; a keyfile is required--quiet— Keep graphical desktop startup quiet (see 'known issues' below)--ssh— Enable SSH in initramfs. Requires--authorized-keysto provide an authorized keys file for SSH security--sshbash— Leave bash enabled in the SSH session rather than switching to the captivecryptroot-unlock(DEBUG only!)--sshport portnum— Use the specified port rather than the Default 22--sshtimeout secs— Use the specified timeout rather than the Default 300 seconds--reboot— Reboot the system (into initramfs) when sdm-cryptconfig is complete--sdm— sdmcryptrootplugin sets this. Not for manual use--tries n— Set the number of retries to decrypt rootfs before giving up [Default: 0 (infinite)]--unique-ssh— Use a different SSH host key in initramfs than the host OS SSH key
The network configuration switches (dns, gateway, hostname, ipaddr, and mask) are only needed and should only be used if you know that the system is unable to get an IP address and network configuration information from the network (e.g., via DHCP). These settings are ONLY used in the initramfs if SSH is enabled and are not automatically removed.
A fully-booted RasPiOS system uses a different mechanism to configure a static network, such as Network Manager, or other network configuration tools.
initramfs is one of the first programs run during a RasPiOS system boot. Since the system has been configured to use an encrypted rootfs, initramfs will try to boot using that configuration, and it will fail.
But not for lack of trying! initramfs will try to open the encrypted disk 30 (!) times before it gives up, reports an error, and prompts with:
(initramfs)
At this point, you need to know two important details:
- The name of your system disk, which will most likely be
/dev/mmcblk0(integrated SD reader),/dev/sda(a USB-connected disk), or/dev/nvme0n1for an NVME disk - The name of the scratch disk, which must be larger than the used space on your rootfs. sdm-cryptconfig will tell you what size this must be
It's best to not plug in the scratch disk until you are at the (initramfs) prompt, because log messages will tell you the name of the disk you just plugged in.
With this information, you'll enter the command (for example):
(initramfs) sdmcryptfs /dev/mmcblk0 /dev/sda
This will cause sdmcryptfs to encrypt the rootfs on /dev/mmcblk0, using /dev/sda as a scratch disk.
sdmcryptfs will then:
- Print the size of the rootfs
- Save the contents of the rootfs to the scratch disk
- Enable encryption on the rootfs
- You will be prompted to enter YES (all in upper case) to continue
- You will then be prompted to provide the passphrase for $rootfs unless
nopwdwas specified - Be sure that your CapsLock is set correctly (in case you changed it to type YES)!!!
- After a short pause you'll be prompted for the passphrase again to unlock the now-encrypted rootfs unless
nopwdwas specified - If you provided an encryption keyfile to
sdm-cryptconfigor thecryptrootplugin it will be installed into the encrypted rootfs - The saved rootfs content will be restored from /dev/sdX to the encrypted rootfs
- When the restore finishes sdmcryptfs will exit and drop you to the (initramfs) prompt
- Type
exitto continue the boot sequence - Once the system boot has completed the sdm-cryptfs-cleanup service will run which:
- Removes some content that is no longer needed (
bashandsdmcryptfs) and rebuilds initramfs - NOTE: You MUST wait for this stage to automatically reboot or the encryption will fail
- Automatically reboots the system one last time
- Removes some content that is no longer needed (
- As the system reboots you'll once again be prompted for the rootfs passphrase
- NOTE: Without the 30 tries!
- If using a USB Keyfile Disk insert the disk into the reader at any time
- The system will now ask for the rootfs passphrase like this (or use the USB Keyfile Disk) every time the system boots
Do not lose or forget the rootfs passphrase. It is not possible to unlock the encrypted rootfs without a USB Keyfile Disk or rootfs passphrase
Lines not preceded by > yyyy-mm-dd hh:mm:ss are the output of programs (dd, cryptsetup, resize2fs) that are run by sdmcryptfs. The date/time may be incorrect if the system doesn not have a battery backed up clock.
(initramfs) sdmcryptfs /dev/sda /dev/sdb
> 1970-01-01 00:00:59 Shrink partition /dev/sda2 and get its size
> 1970-01-01 00:01:17 Device ‘/dev/sda’ rootfs size 743448 4K blocks (3.0GB; 2.86GiB)
> 1970-01-01 00:01:17 Save rootfs '/dev/sda2' to /dev/sdb
> 1970-01-01 00:01:17 rootfs Save should take less than 3 minutes
743448+0 records in
743448+0 records out
> 1970-01-01 00:02:04 Enable luks2 encryption on '/dev/sda2'
> 1970-01-01 00:02:04 OK to ignore superblock signature warning
> 1970-01-01 00:02:04 Enabling encryption could take up to a minute or two
WARNING: Device /dev/sda2 already contains a 'ext4' superblock signature.
WARNING!
=========
This will overwrite data on /dev/sda2 irrevocably.
Are you sure? (Type ‘yes’ in capital letters): YES
Enter passphrase for /dev/sda2:
Verify passphrase:
Ignoring bogus optimal-io size for data device (33553920 bytes).
> 1970-01-01 00:03:31 Unlock encrypted partition ‘/dev/sda2’
> 1970-01-01 00:03:31 Unlock will take several seconds
Enter passphrase for /dev/sda2:
> 1970-01-01 00:03:41 Restore ‘/dev/sda2’ from /dev/sdb
> 1970-01-01 00:03:41 rootfs Restore should take about the same time as the rootfs Save
743448+0 records in
743448+0 records out
> 1970-01-01 00:04:53 Restore complete; Expand rootfs…
Resize2fs 1.47.0 (5-Feb-2023)
Resizing the filesystem on /dev/mapper/cryptroot to 117076694 (4k) blocks.
The file system on /dev/mapper/cryptroot is now 117076694 (4k) blocks long.
> 1970-01-01 00:04:56 rootfs partition size: 479546138624 Bytes (479.5GB, 446.6GiB)
Enter the 'exit' command to resume the system boot
(initramfs) exit
If the Pi is headless (no keyboard/video/mouse) it is quite difficult (OK, it's impossible or close to it) to unlock the rootfs partition. There are two solutions that you can use with sdm's encrypted rootfs support. You can:
- Use a USB Keyfile Disk (described in the next section).
- Enable SSH in the initramfs. When the system boots you can SSH into the initramfs and you'll be prompted for the rootfs unlock passphrase. After you enter it correctly, the system boot will proceed.
SSH can also be used during the initial rootfs encryption process, discussed in the next section. Everything works exactly the same as if you are sitting on the console, with the exception that log entries (e.g. plugging in a disk) do not show up in the SSH session.
You can use parted -l in the initramfs to determine which disks are plugged in to decide, for example, what scratch disk to use with sdmcryptfs.
Note that once you've enabled SSH in the initramfs, sdm does not provide an easy way to disable it. That said, it is typically not active for very long, and once encryption has been configured the SSH port is locked down to only prompting for the unlock passphrase.
sdm-cryptconfig switches relevant for SSH are:
--authorized-keys keyfile— Specifies an SSH authorized_keys file to use in the initramfs. This is required with SSH, since there is no password authentication in initramfs--sshbash— Leave bash enabled in the SSH session rather than switching to the captivecryptroot-unlock--sshport portnum— Use the specified port rather than the Default 22--sshtimeout secs— Use the specified timeout rather than the Default 300 seconds--unique-ssh— Use a different SSH host key in the initramfs. The default is to use the host OS SSH key- Network configuration settings — You may need to use some or all of these depending on your network configuration
Note that if SSH is enabled in initramfs, you can also SSH into the initramfs to perform the initial configuration (sdmcryptfs). As part of the post-encryption cleanup, this capability is removed in favor of only being able to enter the decryption passphrase.
If you encrypted your rootfs but didn't add SSH and now wish you did, you can! On your running, rootfs encrypted system:
sudo /usr/local/sdm/sdm-ssh-initramfs --authorized-keys /path/to/ssh/authorized_keys
sdm-ssh-initramfs will install and configure dropbear, and then rerun update-initramfs -u. After it completes, reboot the system, and the SSH server will be active, and you'll be able to unlock the encrypted rootfs over the network using SSH with a key that is accepted in the authorized_keys file.
sdm-ssh-initramfs has a few other configuration switches. They are documented above at sdm-cryptconfig switches. sdm-ssh-initramfs supports the --authorized-keys, --dns, --gateway, --hostname, --ipaddr, --mask, and --unique-ssh switches.
Things to know when using SSH as documented here:
- You must use
ssh root@address. The usernamerootis important, as that's how SSH is configured in the initramfs - You can use
ssh root@hostnameif DNS (not MDNS) on your network is set up correctly for resolving local host names. - You will not be able to SSH using ".local" names when initramfs SSH is running; avahi is not running in the initramfs so the system is unknown to MDNS (that's the protocol that is used for ".local")
- If your local network does not have a properly-configured DNS server, you'll need to use
ssh root@ip.ad.dd.rs - WiFi is not supported for the SSH initramfs connection
Instead of typing the rootfs passphrase every boot you can use a USB Keyfile Disk to unlock the rootfs.
Use sudo /usr/local/sdm/sdm-make-luks-usb-key on a host system to create a USB keyfile disk and key. sdm-make-luks-usb-key takes one argument, the name of an unmounted disk where the keyfile will be written. The disk will be re-partitioned with a small FAT32 partition.
Use --init for the first key you create and save to the USB Keyfile Disk. If you add additional keys to the disk (for the same or other systems), only use --init if you intend to delete ALL keys already on the disk.
Switches include:
--ext4— Also create a small second partition, formatted as ext4--hidden— Create a GPT formatted disk and tag the partition as EFI. It will not be readable on Windows. Requires--init--hostname hname— Add this key to the filehostkeys.txton the USB Keyfile Disk. This is handy if you have multiple keys on the disk.--init— Re-initialize the USB disk and re-create the FAT32 partition--keyfile /path/to/keyfile— Add an existing keyfile to the USB Keyfile disk rather than creating a new one
The sdmluksunlock initramfs script continuously scans the available USB drives for the required USB Keyfile disk, so you can insert the disk at any point. It may take a few seconds for the disk to be recognized and scanned, and then it will take several more seconds to unlock the rootfs and continue the system boot.
-
In addition to writing the USB Keyfile Disk,
sdm-make-luks-usb-keyalso places a copy of the newly-created encryption key file in/root/big-long-uid.lek.You may find it handy for use during customization runs, but once a USB Keyfile Disk has been successfully created, you can
sudo rm -f /root/big-long-uid.lek, or*.lekto delete them all.
If your rootfs is already encrypted with a passphrase, but no keyfile, you can easily add a keyfile to it:
- Create the USB keyfile disk
- This can be done on any host and writes the keyfile to a USB disk. See above Creating a USB Keyfile Disk
- Add the USB keyfile on the host with the encrypted rootfs (on the system running with an encrypted rootfs):
sudo mount /dev/sdX /mnt
sudo /usr/local/sdm/sdm-add-luks-key /mnt/big-long-uuid.lek
sudo umount /mnt
- Reboot
Encrypted disks can be explored or mounted with the --encrypted switch.
If a keyfile has been added to the encrypted disk you can use --keyfile /path/to/keyfile.lek to unlock the rootfs with a keyfile. --keyfile implies --encrypted.
As mentioned above, it's best to use aes encryption on the Pi5, which has built-in crypto instructions. All other Pis lack these instructions, so xchacha is recommended for them.
Here's a performance comparison on a Pi5, first showing xchacha, then aes. As you can see, aes encryption is more than twice as fast as xchacha, and more than 4 times as fast on decryption.
pw/ssdy/work$ sudo cryptsetup benchmark -c xchacha20,aes-adiantum-plain64
# Tests are approximate using memory only (no storage IO).
# Algorithm | Key | Encryption | Decryption
xchacha20,aes-adiantum 256b 394.4 MiB/s 421.6 MiB/s
pw/ssdy/work$ sudo cryptsetup benchmark -c aes-xts-plain64
# Tests are approximate using memory only (no storage IO).
# Algorithm | Key | Encryption | Decryption
aes-xts 256b 1774.5 MiB/s 1836.1 MiB/s
pw/ssdy/work$ sudo cryptsetup benchmark -c aes-cbc-essiv:sha256
# Tests are approximate using memory only (no storage IO).
# Algorithm | Key | Encryption | Decryption
aes-cbc 256b 923.4 MiB/s 1895.6 MiB/s
On a Pi4, the results are quite different. Using xchacha is more than twice as fast as aes on both encryption and decryption.
p84~$ sudo cryptsetup benchmark -c xchacha20,aes-adiantum-plain64
# Tests are approximate using memory only (no storage IO).
# Algorithm | Key | Encryption | Decryption
xchacha20,aes-adiantum 256b 170.9 MiB/s 180.0 MiB/s
p84~$ sudo cryptsetup benchmark -c aes-xts-plain64
# Tests are approximate using memory only (no storage IO).
# Algorithm | Key | Encryption | Decryption
aes-xts 256b 87.5 MiB/s 108.4 MiB/s
p84~$ sudo cryptsetup benchmark -c aes-cbc-essiv:sha256
# Tests are approximate using memory only (no storage IO).
# Algorithm | Key | Encryption | Decryption
aes-cbc 256b 68.8 MiB/s 81.3 MiB/s
-
On the Pi5 a 4Kb page size is not supported. Changing the page size from the default 16Kb to 4Kb (using kernel=kernel8.img) on a Pi5 AFTER encryption has been enabled causes encryption to fail. The failure is reversible by undoing the pagesize change. Configuring the page size before enabling disk encryption also fails in
sdmcryptfsfor reasons as yet unknown. -
To use disk encryption on disks other than rootfs that you have manually encrypted, remove
luks.crypttab=nofrom /boot/firmware/cmdline.txt -
When running RasPiOS with Desktop (both X11 and Wayland) sdm-cryptconfig will unconditionally make these adjustments to your system:
- Remove 'quiet' and 'splash' from /boot/firmware/cmdline.txt, making the system boot far less quiet
- Disable the plymouth splash screen
- Configure the system so that the boot following the disk encryption boots to the CLI
- The systemd service
sdm-cryptfs-cleanuprestores the boot to graphical desktop
- The systemd service
The above changes are made to ensure that you have full visibility into what's happening in the boot process. You can override these changes with the sdm-cryptconfig
--quietswitch.After the system has fully completed the encryption process, if you want you can
sudoedit /boot/firmware/cmdline.txtand addquiet splash. Also, if you want to re-enable plymouth, do the following once you're logged in:
for svc in plymouth-start plymouth-read-write plymouth-quit plymouth-quit-wait plymouth-reboot
do
sudo systemctl unmask $svc
doneEncryption configuration is based on https://rr-developer.github.io/LUKS-on-Raspberry-Pi. As of 2024-01-01 it predates Bookworm, but was very helpful in working out the initramfs configuration.