一、概览
本教程目标:
使用 OEM Key + 对称密钥生成 EKS(Encrypted Key Blob),
配置安全引导 (Secure Boot) + LUKS 加密 RootFS,
并在 QSPI 与 NVMe 间建立安全启动链。
核心流程如下:
阶段 |
关键命令 |
目的 |
1️⃣ 密钥与 EKS 生成 |
|
生成安全引导所需密钥 |
2️⃣ 构建 QSPI 环境 |
|
准备分区和配置 |
3️⃣ 刷写 QSPI (bootloader + EKS) |
|
写入启动镜像到 QSPI |
4️⃣ 加密并刷写 NVMe RootFS |
|
写入并加密系统镜像 |
启动流程如下:
BootROM → MB1 → MB2 → UEFI → OP-TEE (TOS) → LUKS RootFS (NVMe)
QSPI:保存 Bootloader 与 EKS 密钥;
EKS (Encrypted Key Store):安全地存放加密密钥;
NVMe RootFS:通过 LUKS 加密,防止数据泄露;
TEE (Trusted Execution Environment):启动时解密 RootFS。
1.1启动流程
以下是设备从启动到加载 LUKS 加密根文件系统的流程:
BootROM:设备在上电时首先执行的固件,通常是硬件自带的,提供最基本的初始化。
MB1 (Bootloader):MB1 是启动引导程序的第一阶段,负责初始化硬件并加载后续的引导程序。
MB2:第二阶段的 Bootloader,负责引导更高级别的启动程序。
UEFI (Unified Extensible Firmware Interface):提供标准化的引导接口,加载操作系统内核。
OP-TEE (Trusted Execution Environment):OP-TEE 提供受信执行环境,用于执行敏感操作,如解密存储在 NVMe 中的 LUKS 根文件系统。
LUKS RootFS:通过 OP-TEE 解密并加载加密的根文件系统,最后启动系统。
1.2 什么是EKS(Encrypted Key Store)
EKS 是一个加密存储容器,用于存储密钥,通常是安全引导的一部分。它确保在系统启动过程中,密钥等敏感信息不会被泄露。
1.2.1 EKS 的作用:
生成 EKS 目的是确保根文件系统的解密密钥在启动时受到保护,只有通过认证的硬件或引导过程才能访问这些密钥。
1.2.2 核心概念:
OEM Key(原厂密钥):由硬件制造商提供的密钥,用于加密其他密钥。在该流程中,通过如
gen_ekb.py的 Python 脚本生成 EKS。对称密钥:对称加密方式(如 AES)使用相同的密钥进行加密和解密。在此过程中,OEM 密钥与对称密钥结合生成 EKS,将密钥加密存储。
1.3 什么是QSPI
QSPI(Quad Serial Peripheral Interface) 是一种高速存储接口,常用于嵌入式设备,通常用于存储启动加载器(Bootloader)和其他启动文件。
1.3.1 QSPI 的作用:
存储 Bootloader 和 EKS 密钥,确保系统能够安全地启动。
QSPI 环境的配置:需要通过特定命令来配置 QSPI 存储的分区、文件系统等,以确保 QSPI 工作正常。
1.3.2 核心命令:
使用
--no-flash参数来跳过闪存操作,只准备 QSPI 存储环境。
1.3.3 核心概念:
QSPI 存储设备为嵌入式系统提供高速存储,尤其适用于启动过程中的关键数据存储,如 Bootloader 和密钥。
1.4 什么是 LUKS(Linux Unified Key Setup)
LUKS(Linux Unified Key Setup,Linux统一密钥设置) 是一种加密格式和标准,用于加密硬盘分区或文件系统。LUKS 提供强大的加密保护,防止数据在存储介质中泄露。
LUKS 的作用:
加密根文件系统:通过 LUKS 加密技术,对 NVMe 根文件系统 进行加密,确保存储在磁盘上的数据无法被未授权访问。
与 OP-TEE 集成:使用 OP-TEE(受信执行环境)来解密存储在 NVMe 中的 LUKS 加密文件系统。
1.5 什么OP-TEE(Trusted Execution Environment)
OP-TEE(Open Portable Trusted Execution Environment,开源便携受信执行环境) 是一个开源项目,旨在提供一个安全的执行环境,用于执行敏感操作,如密钥管理和加密解密操作。
OP-TEE 的作用:
提供一个隔离的环境,确保在设备启动时,只有经过授权的操作可以执行,如解密根文件系统中的数据。
它在 安全引导 过程中与 LUKS 配合使用,解密并加载加密的根文件系统(RootFS)。
二、环境与工具准备
2.1安装 SDK Manager
在主机 Ubuntu 系统(建议 20.04 或 22.04)中执行:
sudo apt update sudo apt install -y wget python3 python3-pip python3-cryptography openssl usbutils
从 NVIDIA 官网下载安装包(需登录 NVIDIA Developer 账号):
👉 https://developer.nvidia.com/nvidia-sdk-manager
下载 .deb 后执行安装:
sudo apt install ./sdkmanager_*_amd64.deb
启动 SDK Manager:
sdkmanager
登录后选择:
Product Category: Jetson
Hardware Configuration: Jetson AGX Orin
Target Operating System: Linux
Target Version: 36.3.x (例如 JetPack 6.0 DP)
在安装界面:
✅ 勾选 “Download now, install later”
⚠️ 不要点击 “Flash Now”。
2.2查找并解压 JetPack 文件
SDK Manager 会把下载的压缩包放在:
~/Downloads/nvidia/sdkm_downloads/
可以看到:
Jetson_Linux_R36.4.4_aarch64.tbz2 Tegra_Linux_Sample-Root-Filesystem_R36.4.4_aarch64.tbz2
解压步骤:
cd ~ mkdir Linux_for_Tegra cd Linux_for_Tegra # 解压 L4T 系统包 sudo tar -xvf ~/Downloads/nvidia/sdkm_downloads/Jetson_Linux_R36.4.4_aarch64.tbz2 # 解压 rootfs cd Linux_for_Tegra/rootfs sudo tar -xvf ~/Downloads/nvidia/sdkm_downloads/Tegra_Linux_Sample-Root-Filesystem_R36.4.4_aarch64.tbz2 cd .. # 应用 NVIDIA 二进制文件 sudo ./apply_binaries.sh
成功后出现:
Successfully applied binaries.
以上步骤以后,我们是缺少一个 EKB 工具包,需要我们手动下载,上面对应版本的下载地址如下:
👉 https://developer.nvidia.com/embedded/jetson-linux
找到Driver Package (BSP) Sources
cd ~/Downloads tar xf public_sources.tbz2 -C ~/Linux_for_Tegra/source/
工具就在Linux_for_Tegra/source/optee/samples/hwkey-agent/host/tool/gen_ekb/ 里面
这一步完成后,你的 Linux_for_Tegra/ 目录就是刷机基础环境。
三、生成密钥与 EKS(Encrypted Key Store)
3.1进入生成脚本目录:
cd ~/Linux_for_Tegra/source/optee/samples/hwkey-agent/host/tool/gen_ekb/
3.2生成密钥:
# OEM K1,未熔丝可使用全0 printf '0000000000000000000000000000000000000000000000000000000000000000' > oem_k1.key wc -c oem_k1.key # 输出 64 # 生成主对称密钥 openssl rand -hex 32 > sym_t234.key wc -c sym_t234.key # 输出 64 # 生成第二对称密钥(用于 LUKS,加密 rootfs) openssl rand -hex 16 > sym2_t234.key wc -c sym2_t234.key # 输出 32
3.3要点说明:
sym_t234.key:用于普通安全服务;sym2_t234.key:必须是 16 字节(32 个十六进制字符);
它与 gen_luks_passphrase.py 中 load_file_check_size(size=16) 一致。
3.4生成 EKS 镜像:
python3 gen_ekb.py \ -chip t234 \ -oem_k1_key oem_k1.key \ -in_sym_key sym_t234.key \ -in_sym_key2 sym2_t234.key \ -out eks_t234.img
3.5完成后复制eks_t234.img与sym2_t234.key:
cp eks_t234.img ~/Linux_for_Tegra/bootloader/ cp sym2_t234.key ~/Linux_for_Tegra/
3.6知识点讲解:EKS 是什么?
EKS(Encrypted Key Store)是一个安全密钥容器。
它被写入 QSPI,存放加密后的对称密钥。
BootROM 启动时会解密 EKS → 将密钥注入 OP-TEE → 再派生 RootFS 解密 Key。
即使别人复制你整块 NVMe,也无法解密系统内容。
四、构建 QSPI 环境并刷写内部存储
4.1 构建 flash 环境(仅一次)
sudo ./tools/kernel_flash/l4t_initrd_flash.sh --network usb0 --no-flash -p "-c bootloader/generic/cfg/flash_t234_qspi_nvme.xml" jetson-agx-orin-devkit internal
说明:
--no-flash:只生成 initrd 环境;这一步不会刷写,仅做配置准备;
可在此修改分区配置或 XML 文件。
4.2 刷写 QSPI(Bootloader + EKS)
sudo ./tools/kernel_flash/l4t_initrd_flash.sh --network usb0 --flash-only jetson-agx-orin-devkit interna
这个步骤在RCM模式下进行,大概执行十秒钟后需要根据屏幕提示拔插设备,刷完后日志中应出现:
Successfully flashed the QSPI. Flash is successful
如果中间报错过、或者外部刷失败过:
sudo ./tools/kernel_flash/l4t_initrd_flash.sh --network usb0 --erase-all jetson-agx-orin-devkit internal
然后再重新执行上面的刷写命令:
sudo ./tools/kernel_flash/l4t_initrd_flash.sh --network usb0 --flash-only jetson-agx-orin-devkit internal
4.3 知识点讲解:QSPI 的作用
区域 |
内容 |
作用 |
MB1/MB2 |
启动引导阶段代码 |
初始化内存、加载引导链 |
UEFI |
提供 EFI 引导接口 |
启动 Linux |
TOS |
Trusted OS (OP-TEE) |
解密与安全服务 |
EKS |
Encrypted Key Store |
存放 RootFS 密钥 |
五、刷写加密 RootFS 到 NVMe SSD
5.1 nvme刷机参数计算
在进行刷机配置时,EXT_NUM_SECTORS 和 APP_ENC_SIZE 是两个关键的参数,它们需要根据存储设备的实际情况计算。这两个值分别表示设备的扇区数量和加密分区(例如 APP_ENC)的大小。
5.1.11 EXT_NUM_SECTORS(硬盘总扇区数)
EXT_NUM_SECTORS 是硬盘的总扇区数。硬盘的大小通常以字节为单位,但是硬盘的读写操作通常是以扇区(sector)为单位的,每个扇区通常是 512 字节或 4KB(具体视硬盘而定)。因此,扇区数就是硬盘的总大小除以每个扇区的大小。
计算步骤:
确定硬盘的总容量:首先需要知道硬盘的总大小(通常以字节为单位)。例如,如果硬盘是 2TB(即
2 * 1024 * 1024 * 1024 * 1024字节),那么硬盘的大小是2 * 1024^4字节。确定每个扇区的大小:硬盘的扇区大小通常是 512 字节,或者在某些情况下可能是 4KB。可以通过
fdisk或lsblk命令查看硬盘信息,确认扇区大小。计算扇区数:将硬盘的总大小除以每个扇区的大小。例如,如果硬盘是 2TB(即
2 * 1024^4字节)并且每个扇区大小是 512 字节,则扇区数可以通过以下公式计算:
EXT_NUM_SECTORS计算示例:
假设硬盘为 2TB,每个扇区大小为 512 字节:
5.1.2 APP_ENC_SIZE(加密分区大小)
APP_ENC_SIZE 表示加密分区的大小,例如 APP_ENC 分区的大小。加密分区的大小通常是根据硬盘的实际大小或需要分配给某个分区的空间来设置的。
计算步骤:
确定加密分区的大小:加密分区的大小通常会设定为硬盘总大小的一个比例,或者根据需求手动指定。举例来说,如果硬盘大小是 2TB,而你希望给加密分区分配 1TB,那么加密分区的大小就是
1 * 1024^4字节。根据需要调整:如果你的硬盘大小较大(例如 2TB),你可能需要为加密分区分配较大的空间(例如 1TB 或更大)。你可以根据具体的需求来调整这个大小。
计算分配的字节数:将你选择的加密分区大小(例如 1TB)转换为字节数。可以使用以下公式:
APP_ENC_SIZE计算示例:
假设加密分区的大小是 2TB(即 2 * 1024^4 字节):
5.2 在终端中设置环境变量
export EXT_NUM_SECTORS=4000797360 export APP_ENC_SIZE=1986422374400
5.3 执行刷机命令
sudo ROOTFS_ENC=1 ./tools/kernel_flash/l4t_initrd_flash.sh --network usb0 --external-device nvme0n1 -i sym2_t234.key -c ./tools/kernel_flash/flash_l4t_nvme_rootfs_enc.xml -S 1850GiB --flash-only jetson-agx-orin-devkit external
参数解释:
参数 |
含义 |
|
启用加密 rootfs 模式 |
|
指定 LUKS 密钥 |
|
设置 2TB SSD 可用空间 |
|
执行实际刷写 |
|
目标设备是 NVMe |
5.4 知识点讲解:RootFS 加密机制
在刷机时:
主机调用
gen_luks_passphrase.py使用sym2_t234.key派生 passphrase;在目标机上,TEE 读取 EKS;
通过 NIST SP800-108 KDF 算法生成相同密钥;
用以自动解密 RootFS。
🟩 优势:
无需输入密码;
密钥不离开安全环境;
即使整盘拷贝,仍无法解密。
六、启动验证
拔掉 USB;
板卡上电;
HDMI 出现 NVIDIA LOGO;
自动进入 Ubuntu;
运行:
lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT
恭喜,看到nvme0n1p1 -> luks-rootfs 就说明成功了
七、关于熔丝的扩展延伸
熔丝(Fuses)是一种硬件配置技术,用于在设备制造过程中设置固定的、不可修改的参数。熔丝的原理与电子设备中的“永久”配置有关,通常它们被设计为一旦写入就不能改变,或者只能在极少数情况下修改。熔丝的不可逆性主要来源于硬件的设计和物理原理。下面详细解释熔丝的原理及为什么它不可逆。
7.1 熔丝的工作原理
熔丝的工作原理可以类比为“物理开关”或“保险丝”,但它们通常是通过微电子电路实现的。它们在芯片或电路板上负责存储特定的配置信息。一旦写入这些信息,熔丝就会在物理层面上发生改变,无法再次修改。以下是熔丝的几个关键原理:
物理连接: 熔丝通过电流在物理电路中创建可被配置的开关或短路。在某些情况下,它们通过烧毁小的电子组件(例如熔断电路或金属连接)来永久地改变某些电路的连接状态。
非易失性: 熔丝通常是非易失性的,这意味着一旦写入,它们的值不会因为断电而丢失。熔丝的这种特性使得它们适合存储像安全密钥、启动配置等敏感或关键的硬件设置。
设定值: 一旦熔丝被设置,它们就固定为某种状态,不能被修改。它们可以表示“开”或“关”状态,或者代表特定的数字值(如加密密钥、启动模式等)。
7.2 为什么熔丝是不可逆的
熔丝不可逆的原因主要归结为以下几点:
7.2.1 物理烧毁
某些熔丝的设计基于物理烧毁技术。例如,熔丝可能由一个微小的金属线或薄层材料组成,在写入时,这个材料会通过一个高电流被熔断或烧毁,形成永久性的断路或开路。这个过程一旦完成,金属连接就无法恢复,从而使熔丝不可逆。常见的有电熔丝、激光熔丝等。
7.2.2 不可擦除的存储
熔丝通常是存储在设备内部的硬件区域(如片上存储器、特定的非易失性存储区域等)。一旦写入数据,这些数据在物理上就固定在存储介质中。即使没有物理损坏,存储器中的信息也无法擦除或重新写入。这种不可擦除特性使得熔丝具有高安全性,尤其在存储关键配置如加密密钥或启动模式时。
7.2.3 硬件设计
设计时,熔丝的不可逆性通常是为了增强设备的安全性和防篡改能力。例如,某些熔丝用于控制加密功能、安全启动、硬件锁定等重要功能,确保设备一旦出厂,就无法更改这些设置,从而防止非法修改或安全漏洞。
7.2.4 防止篡改
熔丝的不可逆性也用于防止设备被非法篡改。例如,某些设备的启动模式可能通过熔丝来锁定(如从特定存储介质启动)。这保证了设备启动时只会执行由厂商验证过的安全代码,从而防止恶意软件通过篡改启动配置来攻击设备。
7.3 熔丝在嵌入式系统中的应用
在嵌入式系统,尤其是在像NVIDIA Jetson这样的平台中,熔丝具有广泛应用。它们通常用于以下几种场景:
7.3.1 加密与安全
熔丝可以用于控制设备是否启用加密功能。例如,在一些设备中,启用硬件加密和安全启动可能需要将某些熔丝设置为特定值,以防止未经授权的操作。
安全启动:通过熔丝设置设备在启动时是否使用特定的密钥或验证代码。只要熔丝被设置,设备就只能使用特定的启动路径,从而确保启动过程中不被篡改。
加密密钥存储:设备的加密密钥、证书等敏感信息可以存储在熔丝中,确保这些密钥不会被提取或篡改。
7.3.2 启动模式
在许多嵌入式设备中,熔丝用于配置设备的启动顺序或启动设备。例如,可以使用熔丝来指定是否从SD卡、eMMC、USB、或NVMe设备启动。一旦写入,熔丝会限制设备只能按照指定的启动方式启动。
7.3.3 硬件锁定
熔丝也用于锁定硬件配置,防止硬件被不当修改。例如,某些嵌入式设备会在出厂时写入熔丝来锁定硬件区域,使得该区域不能被修改或覆盖。
7.4 为什么熔丝不可逆是一个安全特性
熔丝不可逆性的一个关键优点就是防篡改性。例如,在设备的安全配置、加密密钥、启动方式等方面,如果熔丝可以被修改,那么恶意攻击者可能会通过重新编程熔丝来绕过安全措施。而一旦熔丝被设置,它们不能被修改,就极大地提高了设备的安全性。
7.5 总结
熔丝的作用就是硬件加密的不可逆设置,它确保了设备的安全性,不会被恶意篡改或绕过。而通过 EKB 生成工具(gen_ekb.py),生成的密钥块将永远与硬件设备绑定,并通过熔丝确保其不可变性。这样一来,设备即使被盗,数据也不能被解密或访问,从而提供了强大的物理安全保护。
这种方法不仅防止了软件级别的攻击,还确保了物理攻击无法绕过安全机制,是现代高安全设备量产的标准配置。
PonyTechLab