Edit online

方案 V1

本节介绍了 SPI Flash 防抄板方案 V1 的详细配置说明,适用于 D12x/ D13x,本节以 D13x 开发板为例。

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

Edit online

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

D13x 使能 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

烧录 eFuse

烧录 eFuse 主要在 BootLoader 中完成,这是因为:
  • Key 的加工在编译时完成

  • eFuse 的烧录在 BootLoader 中完成

  • AIC 固件包支持两级 BootLoader, 即一个烧录用,一个为量产用

Edit online

生成密钥

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

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

  • SDK/target/d13x/demo88-nor/pack/keys/set_aes_key.txt:设置加密密钥,16 Byte

  • SDK/target/d13x/demo88-nor/pack/keys/set_nonce.txt:设置加密的 NONCE 参数, 8 Byte

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

    脚本通用,可以直接从示例方案中复制。

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

    脚本通用,可以直接从示例方案中复制。

根据下列步骤流程,生成密钥:

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

    set_aes_key.txtset_nonce.txt 文件中有一个初始密钥,需要手动修改其中的 HEX 密钥内容。
    cat set_aes_key.txt
        0123456789abcdef0123456789abcdef
    cat set_nonce.txt
        0123456789abcdef
  2. 确保已经安装 OpenSSL。如未安装,可执行以下命令进行安装:
    sudo apt-get install openssl
  3. 进入开发板根目录:
    cd SDK/target/<soc>/<board>/pack/keys/

    例如:

    cd SDK/target/d13x/demo88-nand/pack/keys/
  4. 使用下列命令运行脚本生成所需的密钥文件和头文件:
    • 在 Linux 环境下:
      ./gen_spienc_key.sh
    • 在 Windows 环境下:
      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

  5. spi_aes_key.h 文件复制粘贴至下列目录中,供编译烧录 eFuse 的程序时使用:

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

    重要: 生成的密钥务必妥善保管,以免丢失或者泄露。
    目录下有 set_aes_key.txt 和 set_nonce.txt,里面有一个初始秘钥, 用户需要手动修改 txt 中的 HEX 秘钥内容,然后再运行脚本更新秘钥。
Edit online

编译程序

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

  1. 进入 SDK 根目录:
    cd <SDK_ROOT>
  2. 应用一个项目配置,例如:

    scons --apply-def=d13x_demo88-nand_baremetal_bootloader_defconfig
  3. 执行下列命令打开 menuconfig 菜单:
    scons --menuconfig
  4. 分别勾选或者确认已勾选下列参数:
    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
  5. 打开 BootLoader 的 eFuse DEBUG 模式:
    重要: DEBUG 模式仅供调试使用,用于校对秘钥是否正确。烧录过程会将秘钥写入 eFuse 中,但不会禁用其读写功能,秘钥还可以通过 CPU 读取出来。在确认秘钥都正确后,需关闭该配置来禁用 eFuse 对应的读写权限。确保量产时关闭 DEBUG 模式。
    AIC_SID_BURN_DEBUG_MODE
    对应配置项:
    Drivers options  --->
        Drivers examples  --->
            [*] Enable SID burn spienc key command
            [*]   Enable SID debug mode
  6. 勾选下列选项,打开 BootLoader 的 eFuse 模拟烧录:
    重要: 模拟烧录仅供调试使用,烧录过程将密钥通过串口直接打印出来,不会写入 eFuse 中,用于校对密钥是否正确,确认密钥都正确后,再关闭该配置进行 eFuse 的量产烧录。确保量产时关闭 eFuse 模拟烧录。
    AIC_SID_BURN_SIMULATED
    对应配置项:
    Drivers options  --->
        Drivers examples  --->
            [*] Enable SID burn spienc key command
            [*]   Enable SID simulated burning
  7. 添加代码来调用命令烧写 eFuse:

    SDK 默认不调用烧录 eFuse 命令,需要手动添加。

    • application/baremetal/bootloader/main.c:

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

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

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

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

Edit online

AiBurn 烧录

使用 AiBurn 烧录生成的镜像,可选择分区烧录只烧录 BootLoader。详情可查看 AiBurn 使用指南。

Edit online

SD 卡烧录

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

    • bootloader.aic

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

Edit online

烧录日志

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

生成量产固件

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

Edit online

配置 BootLoader

  1. 进入 SDK 根目录:
    cd <SDK_ROOT>
  2. 在 SDK 根目录中执行下列命令:
    scons --apply-def=d13x_demo88-nand_rt-thread_bootloader_defconfig
  3. 使用以下任意命令,打开 BootLoader 的 menuconfig 菜单:
    bm
    scons --menuconfig
  4. 在配置界面,勾选或确认已勾选下列参数:
    AIC_USING_SPIENC
    AICUPG_FIRMWARE_SECURITY
    参数对应的配置界面如下:
    Board options  --->
        [*] Using Spienc
        [*]   Enc qspi0
        (0)     set qspi0 tweak
        [*] Using Efuse/SID
            SID Parameter  --->
                (64) set efuse max word
    Bootloader options  --->
        [*] Upgrading  --->
            [*]   Secure transfer firmware and burn
    重要:

    编译量产固件时,需将编译烧录 eFuse 程序时的代码修改还原。

  5. 在正式发布的固件中,建议将下列参数选项去掉,防止攻击者通过控制台读出 Flash 中的数据,否则可跳过:
    AIC_BOOTLOADER_CMD_MTD
    AIC_MTD_BARE_TEST
    参数对应的功能配置界面如下:
    BootLoader options  --->
        Commands  --->
            [ ] mtd read/write
    
    Drivers options  --->
        Drivers examples  --->
            [ ] Enable MTD driver test command
Edit online

配置应用程序

  1. 进入 SDK 根目录:
    cd <SDK_ROOT>
  2. 在 SDK 根目录,执行下列命令:
    scons --apply-def=d13x_demo88-nand_rt-thread_helloworld_defconfig
  3. 使用以下任意命令,打开 Application 的 menuconfig 菜单:
    me
    scons --menuconfig
  4. 勾选或确认已勾选下列选项:
    AIC_USING_SPIENC
    对应的配置界面如下:
    Board options  --->
    
        [*] Using Spienc
        [*]   Enc qspi0
        (0)     set qspi0 tweak
  5. 在正式版本的固件中,建议删除 bsp/examples/test-spinor/test_sfud.c bsp/examples/test-spinor/test_fal.c bsp/examples/test-spinand/test_mtd.c 文件中的 sffalmtd_nand 命令,防攻击者通过控制台读出 Flash 中的数据,否则可跳过此步。

Edit online

配置生成签名的组件

SDK/target/<SoC>/<board>/pack/image_cfg.json 文件中进行配置并生成签名加密固件,例如 SDK/target/d13x/demo88-nand/pack/image_cfg.json

开启了安全启动后,需要对 BootLoader 进行签名。参考签名相关部分的内容进行修改:
{
    "spi-nand": {
        ...
    },
    "image": {
        ...
    },
    "info": { // Header information about image
        ...
    },
    "updater": { // Image writer which is downloaded to RAM by USB/UART
        ...
    },
    "target": { // Image components which will be burn to device's partitions
        ...
    },
    "pre-process": { // before v1.0.6 is the name "temporary"
        "aicimage": { // Create aic boot image
            "usbupg-ddr-init.aic": { // No loader, only PreBootProgram to initialize DDR
                "head_ver": "0x00010001",
                "resource": {
                    "private": "ddr_init.bin",
                    "pubkey": "keys/rsa_public_key.der",   // 签名相关
                    "pbp": "d13x.pbp",             
                },
                "signature": {
                     "algo": "rsa,2048",
                     "privkey": "keys/rsa_private_key.der",   // 签名相关
                },
            },
            "pbp_ext.aic": {
                "head_ver": "0x00010001",
                "resource": {
                    "pbp": "d13x.pbp",                 
                    "pubkey": "keys/rsa_public_key.der",   // 签名相关
                    "private": "pbp_cfg.bin",
                },
                "signature": {   // 签名相关
                     "algo": "rsa,2048",
                     "privkey": "keys/rsa_private_key.der",
                },
                // combine to use with loader.aic
                "with_ext": "true",
            },
            "loader.aic": {
                "head_ver": "0x00010001",
                "loader": {
                    "file": "bootloader.bin",
                    "load address": "CONFIG_AIC_BOOTLOADER_LOAD_BASE",
                    "entry point": "CONFIG_AIC_BOOTLOADER_TEXT_BASE", // 256 byte aic header
                },
                "resource": {
                    "private": "ddr_init.bin",
                    "pubkey": "keys/rsa_public_key.der",  // 签名相关
                },
                "signature": {  // 签名相关
                     "algo": "rsa,2048",
                     "privkey": "keys/rsa_private_key.der",
                },
            },
        },
    },
}
Edit online

加密生成签名的组件

注: 本节不适用于非烧录器量产的场景,如使用烧录器量产,可跳过此步并查看生成和加密烧录器量产固件

image_cfg.json 的 “temporary” 或 “pre-process” 对象的最后,添加 “data_crypt” 对象配置。

此处使用的 AES 加密密钥,即为../../../Chunk1161937705.html#section_in3_5rx_52c章节中SDK/target/<soc>/<board>/pack/keys/ 文件目录生成的密钥。

在下列示例中,配置了一组需要使用 “data_crypt” 工具进行加密的组件,其中生成 bootloader.aic.enc 组件的配置参数为:
  • algo: 加密的算法

  • file: 加密的源文件,此处为前面生成的 bootloader.aic 文件

  • key: 使用的加密密钥

  • nonce: 使用的加密 Nonce 值

  • tweak: 该值不需要配置,保持为 0 即可

{
    "spi-nand": {
        ...
    },
    "image": {
        ...
    },
    "info": { // Header information about image
        ...
    },
    "updater": { // Image writer which is downloaded to RAM by USB/UART
        ...
    },
    "target": { // Image components which will be burn to device's partitions
        ...
    },
    "pre-process": { // before v1.0.6 is the name "temporary"
        "data_crypt": {
            "bootloader.aic.enc": { //加密 bootloader 分区
                "algo": "spienc-aes-128-ecb",
                "file": "bootloader.aic", // File to be encrypted
                "key": "keys/spi_aes.key", // Keys the same in eFuse
                "nonce": "keys/spi_nonce.key", // Nonce the same in eFuse
                "tweak": "0",
            },
            "env.bin.enc": { //加密 env 分区,备份分区使用同一个组件
                "algo": "spienc-aes-128-ecb",
                "file": "env.bin", // File to be encrypted
                "key": "keys/spi_aes.key", // Keys the same in eFuse
                "nonce": "keys/spi_nonce.key", // Nonce the same in eFuse
                "tweak": "0",
            },
            "d13x_os.itb.enc": { //加密 os 分区
                "algo": "spienc-aes-128-ecb",
                "file": "d13x_os.itb", // File to be encrypted
                "key": "keys/spi_aes.key", // Keys the same in eFuse
                "nonce": "keys/spi_nonce.key", // Nonce the same in eFuse
                "tweak": "0",
            },
            "rodata.fatfs.enc": { //加密 rodata 分区
                "algo": "spienc-aes-128-ecb",
                "file": "rodata.fatfs", // File to be encrypted
                "key": "keys/spi_aes.key", // Keys the same in eFuse
                "nonce": "keys/spi_nonce.key", // Nonce the same in eFuse
                "tweak": "0",
            },
            "data.fatfs.enc": { //加密 data 分区
                "algo": "spienc-aes-128-ecb",
                "file": "data.fatfs.itb", // File to be encrypted
                "key": "keys/spi_aes.key", // Keys the same in eFuse
                "nonce": "keys/spi_nonce.key", // Nonce the same in eFuse
                "tweak": "0",
            },
            ...
        },
    },
}

对于一个或者多个需要进行加密的组件,都应按照上述方式进行配置。

mk_image.py 工具在读取 image_cfg.json 文件时,逐个处理放在 “data_crypt” 中的配置,生成对应的加密组件,然后再进行打包。

重要:

“data_crypt” 字段应放在 “temporary”/”pre-process” 的最后,因为处理 “data_crypt” 时,可能需要依赖前面配置生成的文件,比如 ”aicimage”。

Edit online

配置烧录加密组件

注: 本节不适用于非烧录器量产的场景,如使用烧录器量产,可跳过此步并查看生成和加密烧录器量产固件

image_cfg.json 中配置下列参数,打包加密组件,以适配烧录加密固件的要求:

  1. updater 中打包的程序,应为非加密程序

    updater 中配置的参数,都不是 .enc 结尾的组件

  2. target 中打包的程序和数据,应为加密后的程序

    target 中配置的参数,都是 .enc 结尾的组件

这是因为:
  • SD 卡启动时,首先运行 updater 中的程序,进入烧录模式。此时由于数据是从 SD 卡加载的,不能为加密程序,否则无法正常执行

  • target 中打包的程序是要烧录到 Flash 的数据,如果不加密,则无法起到保护的作用,因此需要打包加密后的组件

{ "image": {
        ...
    },
    "info": { // Header information about image
        ...
    },
    "updater": { // Image writer which is downloaded to RAM by USB/UART
        "ddr": {
            "file": "usbupg-ddr-init.aic",
            "attr": ["required", "run"],
            "ram": "0x00103000"
        },
        "spl": {
            "file": "bootloader.aic",
            "attr": ["required", "run"],
            "ram": "0x41000000"
        },
    },
    "target": { // Image components which will be burn to device's partitions
        "spl": {
            "file": "bootloader.aic.enc", //使用 enc 结尾的加密组件
            "attr": ["mtd", "required"],
            "part": ["spl"]
        },
        "os": {
            "file": "d13x_os.itb.enc",   //使用 enc 结尾的加密组件
            "attr": ["mtd", "required"],
            "part": ["os"]
        },
        "rodata": {
            "file": "rodata.fatfs.enc", //使用 enc 结尾的加密组件
            "attr": ["mtd", "optional"],
            "part": ["rodata"]
        },
        "data": {
            "file": "data.fatfs.enc", //使用 enc 结尾的加密组件
            "attr": ["mtd", "optional"],
            "part": ["data"]
        },
    },
    "pre-process": { // before v1.0.6 is the name "temporary"
        ...
    },
}
Edit online

生成和加密烧录器量产固件

注: 本节仅适用于使用烧录器进行量产的场景。
  1. 生成烧录器量产固件
    在 SDK 根目录执行 me 或者 scons --menuconfig 打开配置界面进行如下配置。
    Application options  --->
        [*] Generate burner format image

    配置完成后进行编译,编译完成后在编译输出目录 (images)/burner下找到烧录器烧录所使用到的镜像,例如 d13x_demo88-nor_page_2k_block_128k_v1.0.0.bin

  2. 对烧录器量产固件进行加密
    执行下列命令:
    tools/scripts/spienc --key spi_aes.key --nonce spi_nonce.key --tweak 0x0 --addr 0x0 --start 0x0 --input d13x_demo88-nor_page_2k_block_128k_v1.0.0.bin --output d13x_demo88-nor_page_2k_block_128k_v1.0.0.bin.enc
    • key: 使用的加密秘钥。

    • nonce: 使用的加密 Nonce 值。

    • tweak: 该值不需要配置,保持为 0 即可。

    • addr: 该值不需要配置,保持为 0 即可。

    • start: 该值不需要配置,保持为 0 即可。

    • input: 加密的源文件,此处为前面生成的量产烧录器固件 (d13x_demo88-nor_page_2k_block_128k_v1.0.0.bin) 文件。

    • output: 加密后的文件,此处为固件 (d13x_demo88-nor_page_2k_block_128k_v1.0.0.bin.enc)文件。

    注:

    此处使用的 AES 加密密钥,即为生成密钥章节中SDK/target/<soc>/<board>/pack/keys/ 文件目录生成的密钥。

Edit online

量产

本节介绍了不同量产方式的操作步骤。

USB 烧录

直接使用编译生成的镜像文件进行量产烧录即可。

SD 卡量产

  • 标准方式

    编译生成下列文件后,将其复制到 SD 卡 FAT32 文件系统的根目录中,等待平台重新上电即可进入烧录:

    • bootcfg.txt

    • 打包后的 img 文件,例如 d13x_demo88-nand_v1.0.0.img

  • Direct Mode

    修改 bootcfg.txt,并且将 bootcfg.txt 和使用到的组件复制到 SD 卡 FAT32 文件系统的根目录,等待平台重新上电即可进入烧录模式。

    bootcfg.txt 示例:

    boot0=bootloader.aic
    writetype=spi-nand
    writeintf=0
    write0=bootloader.aic.enc
    write1=d21x_os.itb.enc,0x40000
    write2=rodata.fatfs.enc,0x240000
    write3=data.fatfs.enc,0x840000
重要:

在修改 bootcfg.txt 文件后,确保使用 UNIX 格式的换行符,而非 DOS 格式的换行符,即 ‘\n’ 换行,而非 ‘\r\n’ 换行。

烧录器量产

使用加密后的烧录器量产固件 (例如,d13x_demo88-nand_page_2k_block_128k_v1.0.0.bin.enc) 完成烧录即可。

Edit online

合并烧录 eFuse 和固件

将 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