Enabling full disk encryption on Jetson Nano Orin

Hi there I am trying to follow the documentation to enable FDE on Jetson Orin Nano hosted on a ConnectTech Hadron GMSL. In particular I have been trying with this script

export LDK_DIR=/home/user/nvidia/nvidia_sdk/JetPack_6.2.1_Linux_JETSON_ORIN_NANO_TARGETS/Linux_for_Tegra
cd $LDK_DIR

sudo $LDK_DIR/tools/l4t_create_default_user.sh
-u nvidia
-p nvidia
-n tegra-ubuntu
–accept-license

source cti/orin-nano/hadron-gmsl/base.conf

Generate the keys

cd optee/samples/hwkey-agent/host/tool/gen_ekb/
./example.sh

Copy the keys into Linux_for_tegra

cd -

cp ./optee/samples/hwkey-agent/host/tool/gen_ekb/sym2_t234.key ./sym2_t234.key
rm -f ./bootloader/eks_t234.img
cp ./optee/samples/hwkey-agent/host/tool/gen_ekb/eks_t234.img ./bootloader/eks_t234.img

Generate a new sign/encrypt file (eks_t234_sigheader.img.encrypt)

sudo ./flash.sh --no-flash -k A_eks -i “sym2_t234.key” cti/orin-nano/hadron-gmsl/base nvme0n1p1

Generate images for QSPI

sudo ./tools/kernel_flash/l4t_initrd_flash.sh --showlogs -p “-c bootloader/generic/cfg/flash_t234_qspi.xml” --no-flash --network usb0 cti/orin-nano/hadron-gmsl/base internal

Generate images for external storage device

sudo cp ./bootloader/eks_t234_sigheader.img.encrypt ./tools/kernel_flash/images/internal/eks_t234_sigheader.img.encrypt
sudo ROOTFS_ENC=1 ./tools/kernel_flash/l4t_initrd_flash.sh
–showlogs
–no-flash
–external-device nvme0n1p1
-i ./sym2_t234.key
-c ./tools/kernel_flash/flash_l4t_t234_nvme_rootfs_enc.xml
–external-only
–append
–network usb0
cti/orin-nano/hadron-gmsl/base
external

Flash the encrypted EKS

sudo ./tools/kernel_flash/l4t_initrd_flash.sh -k A_eks --flash-only --showlogs

Flash all images into the both storage devices

sudo ./tools/kernel_flash/l4t_initrd_flash.sh --network usb0 --showlogs --flash-only

Flashing process is ok but when booting the board i end up in a kernel panik because the system couldnt unlock the encrypted disk.

[ 18.071090] ERROR: fail to unlock the encrypted dev /dev/nvme0n1p2.
[ 18.073379] Kernel panic - not syncing

To debug further I have tried to flash a non encrypted disk image flashing the QSPI with the EKB and then trying to access.

To test oem_k2 values without reflashing the full rootfs, we wrote a script (eks_test.sh) that: 1. Regenerates the EKS with gen_ekb.py (no USB). 2. Signs the EKS image with flash.sh --no-flash -k A_eks. 3. Flashes only A_eks in QSPI with l4t_initrd_flash.sh -k A_eks --flash-only.

Step 3 consistently fails with:

[ 0.0274 ] BR_CID: 0x80012344705E00851400000009FE8240
[ 0.0411 ] Sending bct_br
[ 0.0537 ] ERROR: might be timeout in USB write.
Error: Return value 3

Root cause:

flash.sh, even with --no-flash, calls get_fuse_level() at startup because FUSELEVEL is not preset in the CTI BSP config (cti-orin-nx.conf.common). This function internally ru ns:

tegrarcm_v2 --new_session --chip 0x23 - -uid

On T234, --new_session initiates a secure RCM handshake. The process reads the BR_CID and exits, leaving the RCM session open and in an inconsistent state. When l4t_initrd_flash.sh --flash-only subsequently tries to open a new RCM session, the board is in a corrupted state and the mb1 transfer times out.

Attempted workaround — not effective:

We attempted to pre-set FUSELEVEL and FAB to prevent flash.sh --no-flash from opening an RCM s ession:

sudo FUSELEVEL=fuselevel_production FAB=A00 \
./flash.sh --no-flash -k A_eks -i “sym2_t234.key” \
cti/orin-nano/hadron-gmsl/base n vme0n1p1

This was expected to bypass get_fuse_level() and get_board_version(), leaving only a local signing step. However, the USB write timeout on the subsequent l4t_initrd_flash.sh -k A_eks --flash-only persisted. The EKS-only re-flash via --flash-only remains blocked.

Could you help to troubleshoot these two issue issues?

— 🤖 This is an automated AI response. I’m here to help, but please verify important details! —

Based on the provided context, I’ll address the two issues you’re experiencing with enabling full disk encryption on Jetson Orin NX.

Issue 1: Kernel panic due to failure to unlock the encrypted disk

The error message [ 18.071090] ERROR: fail to unlock the encrypted dev /dev/nvme0n1p2. suggests that the system is unable to unlock the encrypted disk. This could be due to an incorrect or missing encryption key.

To troubleshoot this issue, you can try the following:

  1. Verify that the encryption key is correctly generated and stored in the sym2_t234.key file.
  2. Check that the eks_t234_sigheader.img.encrypt file is correctly generated and flashed to the QSPI.
  3. Ensure that the ROOTFS_ENC=1 flag is set when generating the images for the external storage device.

Issue 2: Failure to flash only A_eks in QSPI with l4t_initrd_flash.sh -k A_eks --flash-only

The error message [ 0.0274 ] BR_CID: 0x80012344705E00851400000009FE8240 [ 0.0411 ] Sending bct_br [ 0.0537 ] ERROR: might be timeout in USB write. Error: Return value 3 suggests that there is a timeout issue when trying to flash only A_eks in QSPI.

To troubleshoot this issue, you can try the following:

  1. Verify that the FUSELEVEL and FAB variables are set correctly before running flash.sh --no-flash.
  2. Try setting FUSELEVEL=fuselevel_production and FAB=A00 before running flash.sh --no-flash to bypass the RCM handshake.
  3. If the issue persists, try using a different USB port or cable to rule out any hardware issues.

I hope this helps you troubleshoot and resolve the issues you’re experiencing with enabling full disk encryption on Jetson Orin NX.

— We support team will also look into your issue to have further suggestions soon. please stay tuned. —

Verify that the encryption key is correctly generated and stored in the sym2_t234.key file.
How can i check this if i cannot boot into the system?

Check that the eks_t234_sigheader.img.encrypt file is correctly generated and flashed to the QSPI.

the command ‘sudo ./flash.sh --no-flash -k A_eks -i “sym2_t234.key” cti/orin-nano/hadron-gmsl/base nvme0n1p1’ is successful

Ensure that the ROOTFS_ENC=1 flag is set when generating the images for the external storage device.

I already specified that in the command posted, ‘sudo ROOTFS_ENC=1 ./tools/kernel_flash/l4t_initrd_flash.sh
–showlogs
–no-flash
–external-device nvme0n1p1
-i ./sym2_t234.key
-c ./tools/kernel_flash/flash_l4t_t234_nvme_rootfs_enc.xml
–external-only
–append
–network usb0
cti/orin-nano/hadron-gmsl/base
external’

Verify that the FUSELEVEL and FAB variables are set correctly before running flash.sh --no-flash.

this is specified in the post as well ‘sudo FUSELEVEL=fuselevel_production FAB=A00 \
./flash.sh --no-flash -k A_eks -i “sym2_t234.key” \
cti/orin-nano/hadron-gmsl/base n vme0n1p1
’

If the issue persists, try using a different USB port or cable to rule out any hardware issues.

the cable works fine since I can flash the board with all the command already specified

Update: I have successfully flashed the QSPI with the command above. I can’t access to the TEE yet, the error is the same as before. Here are some details from the new attempt. Let me know if you need further information

Hardware/Software

SoC Jetson Orin Nano (T234, 0x23)
Carrier ConnectTech Hadron GMSL (NGX018)
JetPack 6.2.1 / L4T 36.4.4, CTI BSP V005
BR_CID 0x80012344705E00851400000009FE8240
Fuse state fuselevel_production, bootauth = NS (no PKC/SBK fused)
OP-TEE 4.2 (d78bc5fa)

Problem

FDE flash completes successfully. At boot, the initrd fails to unlock the rootfs:

ERROR: fail to unlock the encrypted dev /dev/nvme0n1p2.
Kernel panic - not syncing

Booting into a plain rootfs and running nvhwkey-app directly:

TEE_IOC_OPEN_SESSION  uuid=b83d14a8-...  ret=0        ✓
TEE_IOC_INVOKE        func=1             ret=0xFFFF0001  TEEC_ORIGIN_TRUSTED_APP  ✗

Root cause analysis (from OP-TEE source)

Reading jetson_user_key_pta.c from nvidia-jetson-optee-source.tbz2, the init sequence is:

// hwkey_derivation_process(), line 265:
se_aes_keyslot_t fuse_key_for_ekb = SE_AES_KEYSLOT_OEM_K2;  // T234 path

tegra_se_aes_ecb_kdf(ekb_rk, fv_for_ekb, SE_AES_KEYSLOT_OEM_K2);
// → ekb_rk = AES-128-ECB(oem_k2_hardware, fv_ekb)

// ekb_extraction_process(), line 232:
if (memcmp(ekb_cmac, ekb_cmac_verify, ...))
    return TEE_ERROR_CIPHERTEXT_INVALID;

// jetson_user_key_pta_init(), line 699 — on failure:
jetson_service_flag &= !PTA_SRV_FLAG;

// invoke_command(), line 572 — any subsequent call:
if (!(jetson_service_flag & PTA_SRV_FLAG))
    return TEE_ERROR_ACCESS_DENIED;  // ← the 0xFFFF0001 we observe

TEE_ERROR_ACCESS_DENIED is not the primary error — it is the consequence of the PTA self-disabling at boot because EKB CMAC verification fails.

The fixed vector fv_for_ekb = bad66eb4484983684b992fe54a648bb8 is confirmed correct (hardcoded in the PTA source, also found at offset 0x1c8f8c in the shipped tos-optee_t234.img).

EKS values tested

For each test, the EKS was regenerated offline with gen_ekb.py, then only the A_eks QSPI partition was reflashed (without touching the rootfs) using l4t_initrd_flash.sh -k A_eks. The board was then booted into a plain (non-encrypted) rootfs and nvhwkey-app was used to probe OP-TEE directly.

EKS generation (same for both tests):

# sym_t234.key  = 010203040506070809a0b0c0d0e0f001
# sym2_t234.key = f0e0d0c0b0a001020304050607080900
# fv_ekb_t234   = bad66eb4484983684b992fe54a648bb8

python3 gen_ekb.py -chip t234 \
    -oem_k2_key oem_k2.key \
    -fv fv_ekb_t234 \
    -in_sym_key sym_t234.key \
    -in_sym_key2 sym2_t234.key \
    -out bootloader/eks_t234.img

A_eks flash (same for both tests):

sudo ./tools/kernel_flash/l4t_initrd_flash.sh \
    -k A_eks \
    --showlogs \
    --network usb0 \
    cti/orin-nano/hadron-gmsl/base internal

Verification on target (plain rootfs, UEFI Secure Boot active):

sudo systemctl start nv-tee-supplicant.service
echo 'test' > /tmp/plain.txt
sudo nvhwkey-app -e -i /tmp/plain.txt -o /tmp/enc.bin
oem_k2 value Result
0000000000000000000000000000000000000000000000000000000000000000 (64 zeroes, default in example.sh) TEEC_InvokeCommand failed 0xffff0001 origin 0x4 ✗
432646294a404e635266556a586e3272357538782f413f442a472d4b61506453 (commented-out alternative in example.sh) TEEC_InvokeCommand failed 0xffff0001 origin 0x4 ✗

Both values documented in example.sh for non-fused boards fail.

Hypothesis

On this board, SE_AES_KEYSLOT_OEM_K2 is loaded by the BootROM with a non-zero value, even though no OEM_K2 fuse is explicitly burned. The board is in fuselevel_production / NS state (ECID production bit 0x8 set, no signing keys fused). We suspect the SE keyslot may be initialized to a chip-specific non-zero value in this fuse state, different from fuselevel_nofuse.

Question: What is the expected value of SE_AES_KEYSLOT_OEM_K2 on a T234 in fuselevel_production / NS state with no OEM_K2 fuse burned? Is there a documented procedure to determine or set this value before generating the EKS image?

hello alessandro.chiesi,

it still the same failure of incorrect disk encryption key within your EKS image.
please double check you’ve re-generate EKS image, and updating it correctly.
see-also Topic 331866 for reference.

Hello JerryChang, thanks for your response. I think that the post you pointed me at does not apply to my setup. The author says “Note : I’ve already implemented secure boot and fused keys into hardware. I’m facing these errors after encrypting the rootfs and UEFI secure boot.”. I’m working on a non-fused board, and I’m trying to achieve FDE without secure boot for now.

hello alessandro.chiesi,

I did aware you’re working on a non-fused board,
you still need to have EKS image update, which has corresponding disk encrypted key included.

Ok isn’t that described in my first post as in:

and then:

Is there something I’m missing?

hello alessandro.chiesi,

see-also Disk Encryption on Orin NX NVMe Not working - #22 by JerryChang.
please have another try to built from scratch to enable disk encryption.

Hello JerryChang, I followed your suggestion and had another try from scratch. Here is the script I used, based on the post you linked at the previous reply

LDK_DIR="$(cd "$(dirname "$0")" && pwd)"
GEN_EKB_DIR="${LDK_DIR}/optee/samples/hwkey-agent/host/tool/gen_ekb"

# regenerate eks and update images
cd "$GEN_EKB_DIR"
bash example.sh
cd "$LDK_DIR"
cp "${GEN_EKB_DIR}/eks_t234.img" bootloader/eks_t234.img

# create new user
sudo tools/l4t_create_default_user.sh \
    -u nvidia -p nvidia -n tegra-ubuntu --accept-license


source cti/orin-nano/hadron-gmsl/base.conf
# launch flash command
sudo ROOTFS_ENC=1 tools/kernel_flash/l4t_initrd_flash.sh \
    --external-device nvme0n1p1 \
    -c tools/kernel_flash/flash_l4t_t234_nvme_rootfs_enc.xml \
    -p "-c bootloader/generic/cfg/${EMMC_CFG}" \
    --uefi-keys uefi_keys/uefi_keys.conf \
    -i "${GEN_EKB_DIR}/sym2_t234.key" \
    --showlogs --network usb0 \
    cti/orin-nano/hadron-gmsl/base internal



Unfortunately the result stays the same flash is ok

but when I boot the board I get the same error as before

[   18.883711] ERROR: fail to unlock the encrypted dev /dev/nvme0n1p2.
[   18.886120] Kernel panic - not syncing:
[   18.886124] Attempted to kill init! exitcode=0x00007f00

I had previously isolated the issue at the OP-TEE level by booting a plain (non-encrypted) rootfs and running nvhwkey-app directly:

TEE_IOC_OPEN_SESSION  uuid=b83d14a8-...  ret=0        ✓
TEE_IOC_INVOKE        func=1             ret=0xFFFF0001  TEEC_ORIGIN_TRUSTED_APP  ✗

I tested two oem_k2 values with this method:

oem_k2 Result
0000...0000 (64 zeroes, example.sh default) 0xFFFF0001 ACCESS_DENIED
432646294a404e635266556a586e3272357538782f413f442a472d4b61506453 (commented alternative in example.sh) 0xFFFF0001 ACCESS_DENIED

From reading jetson_user_key_pta.c in the OP-TEE sources, ACCESS_DENIED is a secondary error. This, if I’m not wrong, means ekb_extraction_process failed at init (CMAC mismatch), so the PTA self-disabled. The root cause should be that SE_AES_KEYSLOT_OEM_K2 on this board holds a value different from both tested keys.

Here you have my board details

  • BR_CID: 0x80012344705E00851400000009FE8240
  • Fuse state: fuselevel_production, bootauth = NS (no PKC/SBK burned)
  • OP-TEE: 4.2 (d78bc5fa), JetPack 6.2.1 / L4T 36.4.4
  • Carrier: ConnectTech Hadron GMSL (NGX018)

Is SE_AES_KEYSLOT_OEM_K2 expected to be non-zero on a T234 in fuselevel_production / NS state even with no OEM_K2 fuse explicitly burned? If so, how do I determine or derive the correct value to pass to gen_ekb.py -oem_k2_key?

hello alessandro.chiesi,

here’re the likely failures.
– sym2_t234.key passed with -i is not exactly the disk key embedded in eks_t234.img.
– eks_t234.img was regenerated, but the signed/encrypted eks_t234_sigheader.img.encrypt or kernel_flash images/internal/A_eks copy is stale.
– EKS was generated with the wrong OEM_K1/OEM_K2/FV for the OP-TEE binary actually running on the board.
– For custom FV/OEM key changes, TOS/OP-TEE must match; updating only EKS is not enough.