Jetson Nano – Rootfs Encryption

Jetson Nano

This article explains how to encrypt rootfs on Jetson Nano, if you want to keep your code and data secret in rootfs, please consider rootfs encryption. As explained in the Secure Boot Sequence article, since Secure Boot is already performed up to u-boot, if u-boot is modified to verify the initrd and kernel signatures, and if the kernel can decrypt and mount the rootfs, the data stored in the rootfs will be invisible to prying eyes. We also propose a way to safely hide the encryption key of the rootfs.

plan

This article introduces standard LUKS (cryptsetup) for encrypting Linux filesystems. We will introduce LUKS into the initrd, which is the in-memory file system used before mounting the rootfs, so that the initrd can decrypt and mount the rootfs.

loading initrd and kernel by u-boot

The default behavior of u-boot is to load the initrd and kernel from the partition where the rootfs is stored, so if the rootfs is encrypted, the initrd and kernel cannot be loaded. Therefore, we will place the initrd and kernel on separate partitions and modify u-boot so that the initrd and kernel can be loaded from those separate partitions.

prerequisite

The latest version of Jetson Linux, currently supported for Jetson Nano, is 32.7.2, so we will proceed with the following work using this version. The host PC is assumed to have Ubuntu 20.04 installed and the setup described in this article.

Introducing LUKS into the initrd

Run the following on the Jetson Nano to install LUKS (cryptsetup) into initrd.

sudo sed -i 's/MODULES=most/MODULES=dep/g' /etc/initramfs-tools/initramfs.conf
cat << EOS > cryptsetup
export KEYMAP=y
export BUSYBOX=y
export FRAMEBUFFER=y
export CRYPTSETUP=y
EOS
sudo cp cryptsetup /etc/initramfs-tools/conf.d/
sudo apt update
sudo apt install -y cryptsetupCode language: Bash (bash)

In line 1, modify /etc/initramfs-tools/initramfs.conf. This prevents kernel boot failure due to initrd oversizing. Please refer to this page for details.

After running the above command, confirm that /boot/initrd.img is specified for INITRD in /boot/extlinux/extlinux.conf instead of /boot/initrd. If it appears as follows, there is no problem. (The # at the beginning is commented out, so please ignore that line.)

$ grep INITRD /boot/extlinux/extlinux.conf
      INITRD /boot/initrd.img
#    INITRD /boot/initrdCode language: PHP (php)

rootfs encryption

The encryption process for the rootfs image is performed on the host PC. The following operations are performed in the Linux_for_Tegra directory described in this article.

Connect the SD card of the Jetson Nano with LUKS installed in the initrd to the host PC and mount it as follows

sudo mkdir /mnt/jetson-nano-app
sudo mount /dev/sdx1 /mnt/jetson-nano-appCode language: Bash (bash)

/dev/sdx1 is the device name of the SD Card on the host PC. Please read it correctly according to your environment.

Create an encrypted rootfs image in LUKS format.

$ dd if=/dev/zero of=bootloader/system.img.raw.crypt bs=1G count=14
$ sudo losetup -f bootloader/system.img.raw.crypt
$ losetup | grep system.img.raw.crypt
/dev/loop??...
$ sudo cryptsetup luksFormat --type luks1 /dev/loop?? 
Are you sure? (Type uppercase yes): YES
Enter passphrase for /path/to/Linux_for_Tegra/bootloader/system.img.raw.crypt: supersecret
Verify passphrase: supersecret
$ sudo cryptsetup luksOpen /dev/loop?? luks
Enter passphrase for /path/to/Linux_for_Tegra/bootloader/system.img.raw.crypt: supersecret
$ ls /dev/mapper/
control  luks
$ sudo mkfs.ext4 /dev/mapper/luks
$ mkdir luks
$ sudo mount /dev/mapper/luks luks
# NOTE: `/mnt/jetson-nano-app/` should end with `/`
$ sudo rsync -axHAWX --numeric-ids --info=progress2 /mnt/jetson-nano-app/ luks
$ sudo umount luks
$ sudo cryptsetup luksClose /dev/mapper/luks
$ sudo losetup -d /dev/loop??
$ sudo bootloader/mksparse -v -fillpattern=0 bootloader/system.img.raw.crypt bootloader/system.imgCode language: Bash (bash)

/dev/loop? are different for each host PC. Please read it correctly according to your environment.

cryptsetup luksFormat –type luks1 is specified, since Jetson Nano uses luks1, so it must be specified explicitly on the host PC.

With the above work, bootloader/system.img.raw.crypt will be encrypted with the passphrase supersecret.

Create initrd and kernel partitions and partition images

Create a partition to place the initrd and kernel by modifying bootloader/t210ref/cfg/flash_l4t_t210_max-spi_sd_p3448.xml as follows.

@@ -255,6 +255,20 @@
               can be accessed as the fixed known special device `/dev/mmcblk0p1`. </description>
         </partition>
 
+        <partition name="BOOTPART" id="2" type="data">
+            <allocation_policy> sequential </allocation_policy>
+            <filesystem_type> basic </filesystem_type>
+            <size> 134217728 </size>
+            <file_system_attribute> 0 </file_system_attribute>
+            <allocation_attribute> 0x8 </allocation_attribute>
+            <percent_reserved> 0 </percent_reserved>
+            <align_boundary> 4096 </align_boundary>
+            <filename> bootpart.img </filename>
+            <description> **Optional.** Contains the copy of /boot in rootfs. This partition must be defined after
+              `primary_GPT` so that it can be accessed as the fixed known special device
+              `/dev/mmcblk0p2`. </description>
+        </partition>
+
         <partition name="GPT" type="GPT">
             <allocation_policy> sequential </allocation_policy>
             <filesystem_type> basic </filesystem_type>Code language: Diff (diff)

Next, create an image of the partition. As you can see above, create an image named bootpart.img.

First, copy the /boot directory from the SD Card.

dd if=/dev/zero of=bootloader/bootpart.img bs=1M count=128
mkfs.ext4 bootloader/bootpart.img
mkdir bootpart
sudo mount bootloader/bootpart.img bootpart
# NOTE: `/mnt/jetson-nano-app/boot` should not end with `/`
sudo rsync -axHAWX --numeric-ids /mnt/jetson-nano-app/boot bootpartCode language: Bash (bash)

Add a script key.sh to the initrd to output the rootfs passphrase.

sudo unmkinitramfs bootpart/boot/initrd.img initrd
sudo tee initrd/scripts/key.sh << EOS > /dev/null
#!/bin/sh

echo -n "supersecret"
EOS
sudo chmod +x initrd/scripts/key.sh
(
cd initrd
sudo bash -c "find . | cpio --quiet -H newc -o | gzip -9 -n > ../bootpart/boot/initrd.img"
)Code language: JavaScript (javascript)

Modify bootpart/boot/extlinux/extlinux.conf. Especially, delete the description of root=/dev/mmcblk0p1 because it specifies non-encrypted rootfs.

@@ -7,7 +7,7 @@
       MENU LABEL primary kernel
       LINUX /boot/Image
       INITRD /boot/initrd.img
-      APPEND ${cbootargs} quiet root=/dev/mmcblk0p1 rw rootwait rootfstype=ext4 console=ttyS0,115200n8 console=tty0 fbcon=map:0 net.ifnames=0 
+      APPEND ${cbootargs}
 
 # When testing a custom kernel, it is recommended that you create a backup of
 # the original kernel and add a new entry to this file so that the device canCode language: PHP (php)

u-boot modification

How to customize u-boot, see this article.

Reference