Thanks to the amazing work of @Rex, i recently switched to Bookworm. I built my own custom img with all my tools / games / setting properly set up, from the latest image he provides here : Bookworm 6.6.y for the uConsole and DevTerm.
In order to stay worry free in case of a lost or stolen uConsole, I managed to have my uconsole use a LUKS encrypted root partition while still booting
Here are my notes on how to do it !
The original work for most of this is still here : LUKS on Raspberry Pi | LUKS-on-Raspberry-Pi
And resources that helped me with bookworm specifics :
- [Bookworm] cannot unlock LUKS2 volume from initramfs · Issue #362 · RPi-Distro/repo · GitHub
- I just experimented some simplifications for Debian 12 based RPi OS · Issue #11 · rr-developer/LUKS-on-Raspberry-Pi · GitHub
- boot - What filename does auto_initramfs look for? - Raspberry Pi Stack Exchange
- documentation/documentation/asciidoc/computers/config_txt/boot.adoc at develop · raspberrypi/documentation · GitHub
- Bookworm 6.6.y for the uConsole and DevTerm - #864 by Rex
Prerequisites:
- uConsole CM4
- HDMI display and proper cable to connect to the uConsole
- Your favorite Linux computer
For a smoother process I recommend that you already boot you system from the image at least once, that will ensure that first-boot scripts have done their magic.
It will however resize your root partition to take all the available space and its an annoyance because it means a much bigger image to handle (when dumping with dd
). And later in the guide, i like to expend the encrypted LUKS partition a bit just to be sure that all my dumped data will fit.
The most straightforward way I found to prevent resizing at first boot is to create a single partition after the existing one on your image. You can do this easily by increasing your image size with dd : dd if=/dev/zero bs=1M count=100 >> bookworm_image.img
and use your favorite partitioning tool (i.e. parted
/ gparted
) to add a partition in this free space. Boot once and delete the unused partition.
So, at the very beginning of this guide I expect your sd-card to look like this :
- /dev/mmcblk0p1 : boot partition (512M I think)
- /dev/mmcblk0p2 : root partition (whatever size)
- some empty trailing space.
Okay, boot up your uconsole with the sdcard in. Ensure you have the proper tools installed on your uConsole system:
sudo apt install busybox cryptsetup initramfs-tools cryptsetup-initramfs
cryptsetup
version should be 2.0.6 or later and benchmark should succeed.
cryptsetup --version
cryptsetup benchmark -c xchacha20,aes-adiantum-plain64
If a new kernel is published via apt, we want to have a new initramfs built and dropped where it is needed.
Before anything, we have to patch a function that won’t work in our case (see [Bookworm] cannot unlock LUKS2 volume from initramfs · Issue #362 · RPi-Distro/repo · GitHub) :
sudo sed -i '/^resolve_device()/,/^}/c\resolve_device() {\n DEV="\$1"\n\n case "\$DEV" in\n /dev/*)\n ;;\n LABEL=* | UUID=* | PARTLABEL=* | PARTUUID=*)\n DEV="\$(blkid -l -t "\$DEV" -o device)" || return 1\n ;;\n esac\n\n [ -e "\$DEV" ] && echo "\$DEV"\n}' /usr/share/initramfs-tools/scripts/functions
We can now create the following file: /etc/kernel/postinst.d/initramfs-rebuild
with this content:
#!/bin/sh -e
version="$1"
current_version="$(uname -r)"
boot_initramfs_path="/boot/firmware/initramfs8"
if [ "$1" = "$current_version" ]; then
echo "Initramfs needs rebuilding."
else
echo "Not current kernel version, initramfs needs no rebuilding."
exit 0
fi
if [ -e "$boot_initramfs_path" ]; then
echo "Backing up previous initramfs..."
cp "$boot_initramfs_path" "$boot_initramfs_path".bak
echo "Done."
fi
# Don't know if both paths are needed. Just in case...
echo "Rebuilding..."
update-initramfs -c -k "$version"
mkinitramfs -o "$boot_initramfs_path" "$version"
echo "All done."
And make it executable:
sudo chmod +x /etc/kernel/postinst.d/initramfs-rebuild
Next, we add a hook script to ensure we got LUKS tools on our initramfs. To do so create the following file: /etc/initramfs-tools/hooks/luks_hooks
with the following content:
#!/bin/sh -e
PREREQS=""
case $1 in
prereqs) echo "${PREREQS}"; exit 0;;
esac
. /usr/share/initramfs-tools/hook-functions
copy_exec /usr/lib/aarch64-linux-gnu/libgcc_s.so.1 /usr/lib/aarch64-linux-gnu
copy_exec /usr/lib/aarch64-linux-gnu/libpthread.so.0 /usr/lib/aarch64-linux-gnu
copy_exec /sbin/resize2fs /sbin
copy_exec /sbin/fdisk /sbin
copy_exec /sbin/cryptsetup /sbin
And make it executable:
sudo chmod +x /etc/initramfs-tools/hooks/luks_hooks
Let’s ensure that our initramfs also bundles the required kernel modules, add the following to /etc/initramfs-tools/modules
:
algif_skcipher
xchacha20
adiantum
aes_arm64
sha256
nhpoly1305
dm-crypt
aes_generic
chacha_generic
nhpoly1350
xts
You can now create your initramfs:
sudo update-initramfs -c -k $(uname -r)
sudo mkinitramfs -o /boot/firmware/initramfs8 $(uname -r)
In /boot/firmware/config.txt
, append at the end of the [all]
section of the file:
auto_initramfs=1
In /boot/firmware/cmdline.txt
, we must remove references to the current unencrypted partition to point instead to the encrypted one we will prepare. It should look just like this:
console=serial0,115200 console=tty1 root=/dev/mapper/sdcard rootfstype=ext4 cryptdevice=/dev/mmcblk0p2:sdcard fsck.repair=yes rootwait fbcon=rotate:1 psi=1
In /etc/fstab
, remove the line mentioning the unencrypted partition, on my image it was this:
PARTUUID=cf8c8a4c-02 / ext4 defaults,noatime 0 1
Instead add this line:
/dev/mapper/sdcard / ext4 defaults,noatime 0 1
And at last in /etc/crypttab
, add the following line:
sdcard /dev/mmcblk0p2 none luks
Everything should be OK for a reboot. BUT initramfs will fail because the encrypted partition is not there yet. So let’s start by encrypting our partition. Plug the sdcard out of the uConsole and into your favorite Linux computer.
I use a SD-card to USB dongle, so my device is recognized as /dev/sda
, but it might be something else for you (/dev/mmcblk0
for instance). Just check with sudo dmesg
and fdisk -l
to get the proper identifier. I assume /dev/sda
from here.
We store the raw data of the root partition to a file on the computer :
sudo e2fsck -f /dev/sda2
sudo dd bs=4k if=/dev/sda2 of=./data.img status=progress
With that done, we can format our SD-card partition as LUKS encrypted:
sudo cryptsetup --type luks2 --cipher xchacha20,aes-adiantum-plain64 --hash sha256 --iter-time 5000 --key-size 256 --pbkdf argon2i luksFormat /dev/sda2
If you know what you are doing (or just RTFMing), you can very well change the parameters as you please. But keeping this cipher is probably best for performance on CM4.
sudo parted /dev/sda
Since I wanted to be sure that my backed-up data partition would fit in there, I resized it by extending it by 1Gb. In my case, the 2nd partition’s size is 26.5Gb, so I resized it with :
sudo parted /dev/sda
then :
resizepart 2 27.5GiB
quit
Adjust value depending on the size of your root partition (or maybe do a clever calculation instead of arbitrarily adding 1Gb like me :-p).
Let’s open our encrypted LUKS container:
sudo cryptsetup luksOpen /dev/sda2 sdcard
Then we copy back our data on the partition:
sudo dd bs=4k if=./data.img of=/dev/mapper/sdcard status=progress
Do a quick e2fsck
:
sudo e2fsck -f /dev/mapper/sdcard
And close the LUKS container:
sudo cryptsetup luksClose /dev/mapper/sdcard
That is it for encryption.
At boot, we expect it to fail and drop us an initramfs shell to decrypt the partition. However at this stage the built-in uconsole screen does not work. With @Rex bookworm image, we don’t have to alter anything to use an external HDMI display, so just do that.
Unplug the SD-card from your computer, plug it into your uConsole, connect a display to HDMI and boot it up.
So, the device boots up, the uConsole screen is powered on but blank, but the HDMI display should show you that it failed to find the root filesystem and drop you in initramfs shell to tell it what to do.
There, just open the LUKS container:
cryptsetup luksOpen /dev/mmcblk0p2 sdcard
It can take a few seconds to decrypt and open. Then exit the initramfs shell:
exit
And the uConsole boots up on our encrypted filesystem!
To ensure that we can boot without going to initramfs shell every time, let’s rebuild a final initramfs :
sudo update-initramfs -c -k $(uname -r)
sudo mkinitramfs -o /boot/firmware/initramfs8 $(uname -r)
From now, when starting the uConsole, the screen will be blank at this stage (cannot display initramfs shell, remember). So just wait 5-10 seconds before entering your passphrase + Enter.
Then you can wait again a good 10 seconds, decrypting the partition is not instantaneous.
Root filesystem is mounted, startup resumes and you can see the usual messages, then X11.
At last, if you want to expand your encrypted partition to take all the remaining space on your SD-card, you can follow these last steps.
Maybe you can do it directly from the uConsole but I figured it would be much simpler to plug again the SD-card in my trusty Linux computer.
Remember, I use a SD-card to USB dongle, so my SD-card device identifier will be /dev/sda
.
Let’s begin by resizing the hosting partition:
sudo parted /dev/sda
then :
print free
resizepart 2 100%
quit
Next let’s open and resize the encrypted partition:
sudo cryptsetup luksOpen /dev/sda2 sdcard
sudo cryptsetup resize sdcard
sudo e2fsck -f /dev/mapper/sdcard
sudo resize2fs -f /dev/mapper/sdcard
That was a very frustrating and fun journey, so I hope someone may also profit from this