Disk Encryption in NVIDIA Jetson platforms




NVIDIA partner logo NXP partner logo






This wiki shows how to implement Disk Encryption for NVIDIA Jetson Platforms and will also guide you through how to flash the encrypted partition. This tutorial was tested with a Jetson Orin Nano module running JetPack 6; keep in mind that for other versions of JetPack, some steps may vary slightly. It is assumed that JetPack sources were already installed and contained in a directory used to initially flash the target board.

Implementation

In order to enable Disk Encryption for your Jetson module you are going to need a host machine where you have previously installed the JetPack sources and contains a directory you initially used to flash your board. As a first step for the implementation, you need to install the following packages:

sudo apt-get install python3-cryptography python3-cffi-backend libxml2-utils

sudo apt-get install cryptsetup python3-pycryptodome python3-crypto

Partition layout

When you have the packages ready, the next step is to define your partition layout. By default, your original build uses the partition layout defined in Linux_for_Tegra/‌bootloader/‌generic/cfg/flash_t234_qspi_sdmmc.xml, which you can use as a template to define the partition layout you want. Here is an snippet so you can see how a partition is defined:

<partition name="APP" type="data">
    <allocation_policy> sequential </allocation_policy>
    <filesystem_type> basic </filesystem_type>
    <size> APPSIZE </size>
    <file_system_attribute> 0 </file_system_attribute>
    <allocation_attribute> 0x808 </allocation_attribute>
    <align_boundary> 16384 </align_boundary>
    <percent_reserved> 0 </percent_reserved>
    <unique_guid> APPUUID </unique_guid>
    <filename> APPFILE </filename>
    <description> **Required.** Contains the rootfs. This partition must be assigned
        the "1" for id as it is physically put to the end of the device, so that it
        can be accessed as the fixed known special device `/dev/mmcblk0p1`. </description>
</partition>

In order to create an encrypted partition, you need to set its encrypted attribute, which is done by adding the option encrypted="true". JetPack sources include an example of a partition layout which includes an encrypted partition called APP_ENC, this example is located in Linux_for_Tegra/‌bootloader/generic/cfg/flash_t234_qspi_sdmmc_enc_rfs.xml. This tutorial uses the example partition layout with the encrypted APP_ENC partition. Here is a snipped of the file where the encrypted partition is defined:

<partition name="APP" id="1" type="data">
    <allocation_policy> sequential </allocation_policy>
    <filesystem_type> basic </filesystem_type>
    <size> 419430400 </size>
    <file_system_attribute> 0 </file_system_attribute>
    <allocation_attribute> 0x8 </allocation_attribute>
    <percent_reserved> 0 </percent_reserved>
    <align_boundary> 16384 </align_boundary>
    <unique_guid> APPUUID </unique_guid>
    <filename> system_boot.img </filename>
    <description> **Required.** Contains the boot partition. This partition must be defined
        after `primary_GPT` so that it can be accessed as the fixed known special device
        `/dev/mmcblk0p1`. </description>
    </partition>

    <partition name="APP_ENC" id="2" type="data" encrypted="true" reencrypt="false">
    <allocation_policy> sequential </allocation_policy>
    <filesystem_type> basic </filesystem_type>
    <size> APP_ENC_SIZE </size>
    <file_system_attribute> 0 </file_system_attribute>
    <allocation_attribute> 0x8 </allocation_attribute>
    <percent_reserved> 0 </percent_reserved>
    <align_boundary> 16384 </align_boundary>
    <unique_guid> APP_ENC_UUID </unique_guid>
    <filename> system_root_encrypted.img </filename>
    <description> **Required.** Contains the encrypted root partition("/"). </description>
</partition>

Generating the EKS image

After this, you need to generate your disk encryption key and generate the EKS image that must be flashed to the board. In order to do this we are going to use the gen_ekb.py utility. This utility is part of the OP-TEE source package, so you need to obtain it, to do so you can check our OP-TEE Guide for NVIDIA Jetson, also keep in mind that OP-TEE is required for Disk Encryption to work in Jetson platforms. After obtaining the sources go to the following path:

cd optee/samples/hwkey-agent/host/tool/gen_ekb/

Here you will find the gen_ekb.py utility and an example.sh script. This script will show you how to use the utility or generate the EKS image for you. Regardless of which option you prefer, you need to generate the required keys. It is important to keep in mind that if you had previously burned the OEM_K1 fuse in your board, you need to use the same key to generate the EKS image or your board will not boot. If you have not burned the fuse you will need to generate the key. It is not necessary to burn the fuse in order to enable disk encryption, but if you prefer to do so as an extra layer of security, you can check our Secure Boot section.

Generating keys

To generate the required keys run the following commands:

openssl rand -rand /dev/urandom -hex 32 > oem_k1.key #OEM K1 key

openssl rand -rand /dev/urandom -hex 32 > sym_t234.key    # kernel/kernel-dtb encryption key

openssl rand -rand /dev/urandom -hex 16 > sym2_t234.key   # disk encryption key

openssl rand -rand /dev/urandom -hex 16 > auth_t234.key   # uefi variables authentication key

Remember to keep these keys stored securely. After generating the keys use the example.sh script to generate the EKS image:

./example.sh

After executing the script you will have a eks_t234.img file for Orin platforms. In order to use the new image the next time you flash the board you need to copy the file to the Linux_for_Tegra/bootloader path. After this, copy your disk encryption key to the Linux_for_Tegra/ directory. With the steps of the tutorial, the disk encryption key is in the sym2_t234.key file.

Flashing the board

The next step is to flash the board. For this, the board needs to be in recovery mode. In the case of the Jetson Orin Nano Devkit, you can set it to recovery mode by shorting pins 9 and 10 in the J14 header, the pins are labeled as FC_REC and GND respectively. After shorting the pins, you can plug the power adapter into the board and connect the board to your host machine using the USB C port. Proceed to flash the board:

cd Linux_for_Tegra/

sudo ROOTFS_ENC=1 ./flash.sh -i "./disk_enc.key" <board> <rootdev>

# Example for the Jetson Orin Nano using an SD card:
sudo ROOTFS_ENC=1 ./flash.sh -i "./sym2_t234.key" jetson-orin-nano-devkit mmcblk0p1

The ROOTFS_ENC=1 option will enable disk encryption for the created image in the selected storage device. After the flashing process is completed your board will have disk encryption enabled.

Testing the integration

After flashing the board, you can verify that disk encryption was enabled correcly by using the lsblk command. If you are using the example flash_t234_qspi_sdmmc_enc_rfs.xml partition layout the output will look like the following:

lsblk 

# Output
NAME           MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINTS
loop0            7:0    0    16M  1 loop  
mmcblk0        179:0    0  59.4G  0 disk  
├─mmcblk0p1    179:1    0   400M  0 part  /boot
├─mmcblk0p2    179:2    0  54.6G  0 part  
│ └─crypt_root 253:0    0  54.6G  0 crypt /
├─mmcblk0p3    179:3    0   128M  0 part  
├─mmcblk0p4    179:4    0   768K  0 part  
├─mmcblk0p5    179:5    0  31.6M  0 part  
├─mmcblk0p6    179:6    0   128M  0 part  
├─mmcblk0p7    179:7    0   768K  0 part  
├─mmcblk0p8    179:8    0  31.6M  0 part  
├─mmcblk0p9    179:9    0    80M  0 part  
├─mmcblk0p10   179:10   0   512K  0 part  
├─mmcblk0p11   179:11   0    64M  0 part  /boot/efi
├─mmcblk0p12   179:12   0    80M  0 part  
├─mmcblk0p13   179:13   0   512K  0 part  
├─mmcblk0p14   179:14   0    64M  0 part  
├─mmcblk0p15   179:15   0   400M  0 part  
│ └─crypt_UDA  253:1    0   384M  0 crypt /mnt/crypt_UDA
└─mmcblk0p16   179:16   0 479.5M  0 part  
zram0          252:0    0   635M  0 disk  [SWAP]
zram1          252:1    0   635M  0 disk  [SWAP]
zram2          252:2    0   635M  0 disk  [SWAP]
zram3          252:3    0   635M  0 disk  [SWAP]
zram4          252:4    0   635M  0 disk  [SWAP]
zram5          252:5    0   635M  0 disk  [SWAP]

You can also verify that the encryption works as expected by flashing the board with a different encryption key that the one you used to create the eks_t234.img. If the key you used at the moment of flashing the board whith using the ./flash.sh script is different to the one you used when creating the eks_t234.img with the ./example.sh script or the gen_ekb.py tool, the board will be flashed successfully but it will get stuck at boot time. If you have access to a monitor or a serial conector, you will be able to see that the board is unable to unlock the storage device and a message similar to the following is shown:

No key available with this passphrase

ERROR: failed to unlock the encrypted dev /dev/mmcblk0p2

Then, if you flash the board using the correct key it will boot successfully.

Creating Encrypted Partitions Dynamically

Once you have enabled disk encryption in your board it is also possible to create encrypted partitions at run time. Keep in mind that this only applies if you previously enabled disk encryption following the steps in the previous section. Also, it is important to know that the encrypted partition will be created based on an already existed partition, this partition will be formatted so any data stored in that partition will be lost if not backed up.

First, you need to select which partition are you going to use to create the new encrypted partition. You can check information on the existing partitions by running the following command:

sudo blkid

# Example output
/dev/mmcblk0p12: PARTLABEL="recovery_alt" PARTUUID="1d0b754f-7542-46d2-b84e-95439c28a221"

After selecting the partition to be used, create the encrypted partition with the gen_luks.sh tool:

sudo gen_luks.sh <partition> <encrypted partition name>

# Example
sudo gen_luks.sh /dev/mmcblk0p12 crypt_DATA

Wen you execute the previous command the tool will be started, first you are going to get the following message: </syntaxhighlight>

After selecting the partition to be used, create the encrypted partition with the gen_luks.sh tool:

All data on /dev/mmcblk0p12 will be wiped out after luks disk is created. Reply YES to continue:

You must enter "YES" to continue, or "No" if you want to cancel the process. Then it will ask you about the file system type you want:

Do you want to format encrypted partition crypt_DATA into ext4? Reply YES or No:

By default the ext4 type is used, so if you input "YES" the partition will be created with this format. If you enter "No" you can select which file system type you want after rebooting the device. To finish the process it is necessary to reboot the device, so the tool will ask you if you want to reboot now:

Do you want to reboot the device to create encrypted partition? Reply YES or No:

If you select "YES" the device will reboot, if you select "No" the device will not reboot at the moment but the encrypted partition will be created only after you reboot the board. After rebooting the encrypted partition is created at /dev/mapper/crypt_DATA and mounted at /mnt/crypt_DATA. You check this with the lsblk command:

lsblk

# Output
NAME           MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINTS
loop0            7:0    0    16M  1 loop  
mmcblk0        179:0    0  59,4G  0 disk  
├─mmcblk0p1    179:1    0   400M  0 part  /boot
├─mmcblk0p2    179:2    0  54,6G  0 part  
│ └─crypt_root 253:0    0  54,6G  0 crypt /
├─mmcblk0p3    179:3    0   128M  0 part  
├─mmcblk0p4    179:4    0   768K  0 part  
├─mmcblk0p5    179:5    0  31,6M  0 part  
├─mmcblk0p6    179:6    0   128M  0 part  
├─mmcblk0p7    179:7    0   768K  0 part  
├─mmcblk0p8    179:8    0  31,6M  0 part  
├─mmcblk0p9    179:9    0    80M  0 part  
├─mmcblk0p10   179:10   0   512K  0 part  
├─mmcblk0p11   179:11   0    64M  0 part  /boot/efi
├─mmcblk0p12   179:12   0    80M  0 part  
│ └─crypt_DATA 253:2    0    64M  0 crypt /mnt/crypt_DATA
├─mmcblk0p13   179:13   0   512K  0 part  
├─mmcblk0p14   179:14   0    64M  0 part  
├─mmcblk0p15   179:15   0   400M  0 part  
│ └─crypt_UDA  253:1    0   384M  0 crypt /mnt/crypt_UDA
└─mmcblk0p16   179:16   0 479,5M  0 part  
zram0          252:0    0   635M  0 disk  [SWAP]
zram1          252:1    0   635M  0 disk  [SWAP]
zram2          252:2    0   635M  0 disk  [SWAP]
zram3          252:3    0   635M  0 disk  [SWAP]
zram4          252:4    0   635M  0 disk  [SWAP]
zram5          252:5    0   635M  0 disk  [SWAP]