Edit online

方案 V1

Read time: 7 minute(s)

本节介绍了 SPI Flash 防抄板方案 V1 的详细配置说明,以 D21x 开发板为例。

本方案通过使用 D21x 的 SPIENC 总线加密功能以及安全启动功能来实现防抄板,结合实际使用的需求,提供对应的软件方案。

Edit online

SPIENC 总线加密

Read time: 7 minute(s)

SPIENC 总线加密功能是一个芯片硬件支持的安全功能。芯片使能了 SPIENC 后,内部的 SPIENC 模块对 SPI 总线上传输的数据进行实时的加密或解密,即对写出去的数据进行 AES 加密,读回来的数据进行 AES 解密, 使得保存在 Flash 上的数据总是密文。

SPIENC 进行加解密时,使用芯片 eFuse 中特定密钥区域中的密钥对数据进行加密和解密,该密钥区域可以做到烧录后 CPU 不可读写,在芯片内部也仅有 SPIENC 模块能够访问,因此可以做到硬件安全保密。

启用 SPIENC 需要:
  1. 在芯片中烧录特有的的 AES 密钥,并且将相关密钥区域设置为仅 SPIENC 可访问。

  2. 提供对应的加密固件。

  3. 对 AES 密钥进行妥善管理,防止泄露。

此时芯片和对应的固件就被绑定在一起,提供出去的固件,只能运行在烧录了对应加密密钥的芯片上; 烧录了密钥的芯片,也只能运行使用对应密钥加密后的固件。

Edit online

SPI ENC 功能对应的 eFuse 烧录信息

Read time: 7 minute(s)
D21x 使能 SPIENC 功能,需要烧录的 eFuse 信息如下:
  • SECURE 区域中的 SPI_ENC_EN 位。

  • SECURE 区域中的 SECURE_BOOT_EN 位。

  • SPI_ENC KEY 区域中的密钥内容。

  • SPI_ENC NONCE 区域中的密钥内容。

  • DIS RD/DIS WR 区域中,关于 SPI_ENC KEY/ NONCE 的读写禁止位。

  • DIS WR 区域中,关于 ROTPK 的读写禁止位

  • SECURE 区域中的 JTAG_LOCK 位 (可选,关闭 JTAG 更安全)。

注:

相关信息可参考芯片用户手册 > 安全 > SID 章节。

1. eFuse 空间划分
用途 位数 地址 禁止位 禁写 禁读 归属 备注
DIS RD 64 0~7 0~1 V CSTM eFuse 读禁止配置区域
DIS WR 64 8~F 2~3 eFuse 写禁止配置区域
BROM 64 30~37 12~13 V CSTM BROM 参数配置区域
SECURE 64 38~3F 14~15 V CSTM 安全和调试功能开关
ROTPK 128 40~4F 16~19 V CSTM 安全,RSA 公钥的 MD5 Hash 值
SPI_ENC KEY 128 A0~AF 40~43 V V CSTM 安全,连接到 SPI_ENC,对称密钥
SPI_ENC NONCE 64 B0~B7 44~45 V V CSTM 安全,连接到 SPI_ENC,随机数
2. SECURE 区域定义
比特位 名称 描述
31:25 - -
24 PBP_ENC_EN BROM 读取使用,使能 PBP 程序加密功能
23:20 - -
19 SPI_ENC_EN BROM 读取使用,使能 SPI 总线数据加密功能
18 - -
17 ENCRYPT_BOOT_EN BROM 读取使用,使能固件加密启动功能
16 SECURE_BOOT_EN BROM 读取使用,使能安全启动功能
15:1 - -
0 JTAG_LOCK 逻辑组合后连接到 CPU 屏蔽 TDO,关闭 JTAG 调试功能,在安全方案中烧录为 1
Edit online

安全启动

Read time: 7 minute(s)

安全启动功能是通过 RSA 签名和验签的方式,保证芯片只运行经过合法签名的固件,非法固件无法在开启安全启动的芯片上执行。 在防抄板方案中,安全启动可以预防攻击者通过其它手段,运行非法程序读取 Flash 中的固件内容。

Edit online

烧录 eFuse

Read time: 7 minute(s)

使用 SPIENC 加密功能,需要将一个 128 位的 AES 密钥和一个 64 位的 Nonce 值烧录到芯片 eFuse 中。制作加密镜像时也需要使用上述值。因此,使用过程中,确保上述值保持不变且已妥善管理,以免泄露。

本节描述了生成 eFuse 烧录程序的详细流程。在示例方案中,提供了设置 AES/ NONCE 密钥的输入 txt 文件和一个用于生成及更新密钥的脚本:

开发板示例:
  • SDK/target/d21x/demo88-nand/pack/keys/set_aes_key.txt:设置加密密钥

  • SDK/target/d21x/demo88-nand/pack/keys/set_nonce.txt:设置加密的 NONCE 参数

  • SDK/target/d21x/demo88-nand/pack/keys/gen_spienc_key.bat:Windows 上执行编译时,使用该脚本

  • SDK/target/d21x/demo88-nand/pack/keys/gen_spienc_key.sh: Linux 上执行编译时,使用该脚本

Edit online

生成密钥

Read time: 7 minute(s)

根据运行环境执行对应命令,运行生成密钥的脚本:

Linux 环境下:
  1. 确保已经安装 OpenSSL。如未安装,可执行以下命令进行安装:

    sudo apt-get install openssl
  2. 准备初始密钥文件 set_aes_key.txtset_nonce.txt

    set_aes_key.txt set_nonce.txt 文件中有一个初始密钥,需要手动修改其中的 HEX 密钥内容。

  3. 进入开发板根目录:
    cd SDK/target/<soc>/<board>/pack/keys/

    例如:

    cd SDK/target/d21x/demo88-nand/pack/keys/
  4. 使用下列命令运行脚本生成所需的密钥文件和头文件:
    ./gen_spienc_key.sh
    生成的文件如下所示:
    • AES 密钥 spi_aes.key

    • AES 对应的 C 语言头文件 spi_aes_key.h

    • spi_nonce.key

    • rotpk.bin

    • rsa_private_key.der

    • rsa_private_key.pem

    • rsa_public_key.der

    • rsa_public_key.pem

  5. spi_aes_key.h 文件复制粘贴至 lite/bsp/examples_bare/test-efuse/ 目录中,供编译烧录 eFuse 的程序时使用。

    spi_aes.key 和其它文件则保留在 SDK/target/<SoC>/<board>/pack/keys/,在使用 mk_image.py 生成加密固件时使用,例如SDK/target/d21x/demo88-nand/pack/keys/

    重要: 生成的密钥务必妥善保管,以免丢失或者泄露。

Windows 环境 下:

  1. 准备初始密钥文件 set_aes_key.txtset_nonce.txt

    set_aes_key.txt set_nonce.txt 文件中有一个初始密钥,需要手动修改其中的 HEX 密钥内容。

  2. 进入开发板根目录:
    cd SDK/target/<soc>/<board>/pack/keys/

    例如:

    cd SDK/target/d21x/demo88-nand/pack/keys/
    cd SDK/target/d12x/demo68-nor/pack/keys/
  3. 使用下列命令运行脚本生成所需的密钥文件和头文件:
    ./gen_spienc_key.bat
    生成的文件如下所示:
    • AES 密钥 spi_aes.key

    • AES 对应的 C 语言头文件 spi_aes_key.h

    • spi_nonce.key

    • rotpk.bin

    • rsa_private_key.der

    • rsa_private_key.pem

    • rsa_public_key.der

    • rsa_public_key.pem

    重要: 生成的密钥请妥善保管,以免丢失或者泄露。
  4. spi_aes_key.h 文件复制粘贴至 lite/bsp/examples_bare/test-efuse/ 目录中,供编译烧录 eFuse 的程序时使用。

    spi_aes.key 和其它文件则保留在 SDK/target/<SoC>/<board>/pack/keys/,在使用 mk_image.py 生成加密固件时使用,例如SDK/target/d21x/demo88-nand/pack/keys/SDK/target/d12x/demo68-nor/pack/keys/

    重要: 生成的密钥务必妥善保管,以免丢失或者泄露。
Edit online

编译程序

Read time: 7 minute(s)

按照以下步骤配置和编译 BootLoader,并生成烧录固件。

  1. 进入 SDK 根目录,并应用 BootLoader 的配置:
    cd <SDK_ROOT>

    例如,应用下列 BootLoader 配置:

    scons --apply-def=d21x_demo88-nand_baremetal_bootloader_defconfig
  2. 打开 BootLoader 的 menuconfig 菜单:
    scons --menuconfig
  3. 分别勾选或者确认已勾选下列参数:
    AIC_USING_SID
    EFUSE_WRITE_SUPPORT
    AIC_SID_BURN_SPIENC_KEY_TEST
    
    AIC_USING_SPIENC
    AICUPG_FIRMWARE_SECURITY

    参数对应的界面配置具体如下:

    Board options  --->
        [*] Using Spienc
        [*]   Enc qspi0
        (0)     set qspi0 tweak
        [*] Using Efuse/SID
            SID Parameter  --->
                [*] support efuse write
                (64) set efuse max word
    
    Bootloader options  --->
        [*] Upgrading  --->
            [*]   Secure transfer firmware and burn
    Drivers options  --->
        Drivers examples  --->
            [*] Enable SID burn spienc key command
  4. 修改代码调用命令烧写 eFuse:

    • application/baremetal/bootloader/main.c:

      console_set_usrname 之后,添加上一个命令执行代码 console_run_cmd(“efuse_spienc”);,如下所示。
      int main(void)
      {
          console_init();
          console_set_usrname("aic");
          console_run_cmd("efuse_spienc");  // 加上此句
          ...
      }
    • bsp/examples_bare/test-efuse/efuse_burn_spienc_key_cmd.c:

      如果不需要关闭 JTAG,可以将 burn_jtag_lock_bit() 相关的调用注释掉。

  5. 编译程序 BootLoader:
    scons       # build BootLoader
  6. 编译程序 APP 并且生成烧录固件:
    scons --apply-def=d21x_demo88-nand_rt-thread_helloworld_defconfig
    scons

    编译结果会保存至 SDK/output/<SoC name>_<board name_rt-thread_helloworld/images 目录。例如,SDK/output/d12x_demo68-nor_rt-thread_helloworld/images

Edit online

AiBurn 烧录

Read time: 7 minute(s)

使用 AiBurn 烧录生成的镜像,详情可查看 AiBurn 使用指南。

Edit online

SD 卡烧录

Read time: 7 minute(s)
  1. 准备一张 SD 卡,确保该卡只有一个分区,并且格式化为 FAT32/ exFAT 文件系统。
  2. 将编译输出目录下的文件复制到 SD 卡的根目录:
    • bootcfg.txt

    • bootloader.aic

  3. bootcfg.txt 中的内容修改为:
    boot0=bootloader.aic
  4. 将该卡插到板卡中,上电运行,即可完成相关 eFuse 的烧录。

Edit online

烧录日志

Read time: 7 minute(s)
tinySPL [Built on Feb 27 2025 11:21:57]
BROM SPIENC is ENABLED
JTAG LOCK   is ENABLED
SPI ENC KEY:
0x406efde8 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   //烧录后的 key 对 CPU 不可见,所以无法读出
SPI ENC Key is read DISABLED
SPI ENC Key is write DISABLED
Edit online

生成量产固件

Read time: 7 minute(s)

按照本节流程编译加密的量产固件。

Edit online

eFuse 与固件合并烧录

Read time: 7 minute(s)

eFuse 和 量产固件分开可以放松对固件的管控,但需要进行两次烧录,同时 eFuse 的固件和量产固件必须要匹配才能生产,因此可以把 eFuse 和量产固件的烧录合并到同一个固件中进行,降低使用难度,但因为该固件包含了要烧录的 Key,需要对该固件进行保护

实现方法是通过在 eFuse 烧录完成后继续运行,烧录固件,需要配置 BootLoader 宏 AIC_SID_CONTINUE_BOOT_BURN_AFTER。

  1. 进入 SDK 根目录:
    cd <SDK_ROOT>
  2. 在 SDK 根目录中执行下列命令:
    scons --apply-def=d21x_demo88-nand_rt-thread_bootloader_defconfig
  3. 打开 BootLoader 的 menuconfig 菜单:
    scons --menuconfig
  4. 在配置界面,勾选或确认已勾选下列参数:
    AIC_USING_SID
    EFUSE_WRITE_SUPPORT
    AIC_SID_BURN_SPIENC_KEY_TEST
    AIC_SID_CONTINUE_BOOT_BURN_AFTER
    
    AIC_USING_SPIENC
    AICUPG_FIRMWARE_SECURITY
    参数对应的配置界面如下:
    Board options  --->
        [*] Using Spienc
        [*]   Enc qspi0
        (0)     set qspi0 tweak
        [*] Using Efuse/SID
            SID Parameter  --->
                [*] support efuse write
                (64) set efuse max word
    Bootloader options  --->
        [*] Upgrading  --->
            [*]   Secure transfer firmware and burn
    Drivers options  --->
        Drivers examples  --->
           [*] Enable SID burn spienc key command
           [*]   Enable SID continue to boot after burning