此篇文档记录 ESP32-S3 通过 Flash 下载工具 完成 Flash 加密 + Secure Boot V2 + NVS 加密 功能的实现。其中, NVS 加密 是 基于 Flash 加密的方案 来实现。
-
Flash 加密启动的验证代码:esp-idf/components/bootloader_support/src/flash_encrypt.c
-
Flash 加密测试例程:esp-idf/examples/security/flash_encryption
支持 Flash 加密
的产品
芯片型号 | 支持的密钥类型 |
---|---|
ESP32 | XTS_AES_128(256-bit 密钥) |
ESP32-S2 | XTS_AES_128(256-bit 密钥) & XTS_AES_256(有两个 256 bit 密钥块,共 512-bit ) |
ESP32-S3 | XTS_AES_128(256-bit 密钥) & XTS_AES_256(有两个 256 bit 密钥块,共 512-bit ) |
ESP32-C2 | SHA256(256-bit 密钥)& XTS_AES_128(256-bit 密钥) |
ESP32-C3 | XTS_AES_128(256-bit 密钥) |
ESP32-C6 | XTS_AES_128(256-bit 密钥) |
ESP32-H2 | XTS_AES_128(256-bit 密钥) |
支持 Secure Boot V2
的产品如下:
芯片型号 | Secure Boot 版本 |
---|---|
ESP32 ECO3 及以上版本 | Secure Boot V1 & Secure Boot V2 ( RSA-PSS) |
ESP32-S2 所有版本 | Secure Boot V2 ( RSA-PSS) |
ESP32-S3 所有版本 | Secure Boot V2 ( RSA-PSS) |
ESP32-C2 所有版本 | Secure Boot V2 ( ECDSA) |
ESP32-C3 ECO3 及以上版本 | Secure Boot V2 ( RSA-PSS) |
ESP32-C6 所有版本 | Secure Boot V2 (RSA-PSS or ECDSA) |
ESP32-H2 所有版本 | Secure Boot V2 (RSA-PSS or ECDSA) |
Flash 加密 概述
Flash 加密 功能用于加密与 ESP32 系列产品搭载使用的片外 Flash 芯片中的固件,可用于保护应用程序的安全。
分区表设置,例如:
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, , 0x4000,
otadata, data, ota, , 0x2000,
phy_init, data, phy, , 0x1000, encrypted
factory, app, factory, , 1M,
ota_0, app, ota_0, , 1M,
ota_1, app, ota_1, , 1M,
nvs_key, data, nvs_keys,, 0x1000, encrypted
# Custom NVS data partition
custom_nvs, data, nvs, , 0x6000,
storage, data, 0xff, , 0x1000, encrypted
如上分区表包含两个
NVS
分区,分别为默认的nvs
和 自定义的custom_nvs
分区。
默认的 nvs 分区
用于存储 WiFi 或 蓝牙连接信息,以及在软件中通过 nvs_set API 写入的数据,此nvs 分区
不需要在下载固件时下载对应的nvs.bin
。默认的 nvs 分区
是在 nvs_set API 启动时,边写数据到 nvs 分区边加密 (注意:nvs_get
(read)API不支持 nvs 加密
)- 自定义的
custom_nvs
分区用于存储通过custom_nvs.csv
文件来管理的多文件写入到custom_nvs
分区,支持被管理的文件类型参见:CSV 文件格式 说明。此custom_nvs.bin
需要使用nvs_key
进行加密,并下载到custom_nvs
分区。
- 使用 CSV 文件管理多文件的方式参见:如何实现 ESP 设备多证书管理?
开启 Flash 加密后,会默认加密以下类型的数据:
NVS 密钥分区 (nvs_key 分区)用于存放
nvs_key
,nvs_key
用于加密默认的nvs
分区 和 定义的custom_nvs
分区。
其他类型的数据将视情况进行加密:
基于 Flash 下载工具 完成 Flash 加密 功能,支持使用指定密钥
来加密固件。
ESP32S3 的 Flash 加密支持使用 AES-128(256 位密钥)
和 AES-256(512 位密钥)
。其中:
AES-128(256 位密钥)
只需占用一个 eFuse BLOCK;AES-256(512 位密钥)
需要占用两个
eFuse BLOCK。
用户可以根据需求自行选择 AES-128(256 位密钥)
和 AES-256(512 位密钥)
,详细说明参见参见 使用主机生成的密钥。另外,Flash 加密密钥存储在芯片的 eFuse BLOCK 中,但 ESP32-S3 的 Flash 加密密钥
和 Secure Boot 公钥的摘要
仅支持存储在 BLOCK_KEY0(BLOCK4)~ BLOCK_KEY4(BLOCK8)
中,参见 eFuse BLOCK 说明。如下:
如何获取不同类型的 Flash 加密密钥?
用户可以通过如下方式生成用于 Flash 加密 的密钥
espsecure.py generate_flash_encryption_key --keylen 128 flash_encryption_key.bin
【仅 ESP32-C2】
对于 SHA-256(128 位密钥)
会写入 eFuse BLOCK 的 LOW 128 bit
,如下:
espsecure.py generate_flash_encryption_key flash_encryption_key.bin
flash_encryption_key.bin
为生成的(自定义名称)的 Flash 加密密钥文件
当没有指定--keylen
参数时,默认生成AES-128(256 位密钥)
espsecure.py generate_flash_encryption_key --keylen 512 flash_encryption_key.bin
如何获取 Secure Boot V2 密钥?
基于 ESP32S3
芯片开启 Secure Boot V2 功能要求用户自行添加用于 Secure Boot V2 签名的私钥
,且 ESP32S3 Secure Boot V2 需要使用 rsa3072 类型的私钥
Key。
用户可以通过如下方式生成用于 Secure Boot V2 签名的私钥 Key
- 通过 esptool 工具,运行如下指令生成 Secure Boot V2 签名的
私钥
key
espsecure.py generate_signing_key secure_boot_signing_key.pem --version 2 --scheme rsa3072
secure_boot_signing_key.pem
为生成的(自定义名称)的 key file 文件--version 2
为选择secure boot V2
版本--scheme rsa3072
指定 Key 的类型
- 也可以安装 OpenSSL 环境,运行如下指令生成 RSA 3072 类型的指定 secure boot V2 签名的私钥 key
openssl genrsa -out my_secure_boot_signing_key.pem 3072
如何获取 Secure Boot V2 公钥的摘要?
使用 Secure Boot V2 私钥
Key 给固件进行签名时,会基于 Secure Boot V2 的私钥 Key 生成 公钥
和公钥的摘要
(public_key_digest.bin
)。
公钥
和公钥的摘要
会保存在签名块中,签名块写在bootloader.bin
和app.bin
的固件的末尾,即 Secure Boot V2 仅对bootloader.bin
和app.bin
的固件进行签名。- Secure Boot V2
公钥的摘要
会被写入芯片的eFuse
中,以此来验证固件里的签名块。
需要基于 Secure Boot V2 私钥 Key 生成 公钥的摘要
,参见:Enable Secure Boot V2 Externally
-
使用如下指令生成 Secure Boot V2 公钥的摘要
espsecure.py digest_rsa_public_key --keyfile secure_boot_signing_key.pem --output public_key_digest.bin
-
Secure Boot V2 功能开启后,在固件启动时,会检查 二级引导程序(
bootloader.bin
)是否被签名,然后被签名
的二级引导程序(bootloader.bin
)将用来验证被签名
的app.bin
, 验证通过,则固件会正常启动。
如何获取 NVS 密钥?
基于 Flash 加密 方案开启 NVS 加密 ,需要自行设置 nvs_key
分区。nvs_key
可由系统自动生成;也可以使用自定义生成的 nvs_key.bin
。
- 当系统检测到
nvs_key
分区为空时,系统会自动生成nvs_key.bin
, 并写进到nvs_key
分区。日志如下:
- 当使用自定义生成的
nvs_key.bin
时, 需要将nvs_key.bin
下载到nvs_key
分区。另外,需要使用nvs_key.bin
对custom_nvs.csv
文件进行加密,并将加密的encrypt_custom_nvs.bin
烧录到custom_nvs
分区。
可使用 nvs 分区工具:esp-idf/components/nvs_flash/nvs_partition_generator,通过运行如下 nvs_partition_gen.py
指令获取 nvs_key
文件
python E:\esp\Espressif\frameworks\esp-idf-5.2.1\esp-idf\components\nvs_flash\nvs_partition_generator\nvs_partition_gen.py generate-key --keyfile nvs_key.bin
然后使用 nvs_key.bin
来加密 custom_nvs.csv
文件,并获取加密的 encrypt_custom_nvs.bin
python E:\esp\Espressif\frameworks\esp-idf-5.2.1\esp-idf\components\nvs_flash\nvs_partition_generator\nvs_partition_gen.py encrypt custom_nvs.csv encrypt_custom_nvs.bin 0x6000 --inputkey keys\nvs_key.bin
0x6000
为encrypt_custom_nvs.bin
的固件大小
如果您正在使用 ESP32S3 系列的芯片,从量产生产环境的角度考虑,我们推荐使用 Flash 下载工具(最新版本)来完成 Flash 加密 + Secure Boot V2 + NVS 加密 过程。
通过 Flash 下载工具 完成 Flash 加密 + Secure Boot V2 + NVS 加密 功能的实现流程如下:
- 基于 Flash 下载工具 开启
Flash 加密
和Secure Boot V2
设置 - 基于 Flash 下载工具 导入
Flash 加密密钥
(可选)和 Secure Boot V2 的私钥 Key 生成的公钥的摘要
。 - 在下载固件过程直接将
Flash 加密的密钥
和 Secure Boot V2 Key 的公钥的摘要
写入芯片的eFuse BLOCK
中 - 同时写 eFuse 控制位(
FLASH_CRYPT_CNT
)来开启 Flash 加密 的功能;写 eFuse 控制位(ABS_DONE_1
)来开启 Secure Boot V2 的功能。
通过 Flash 下载工具 来完成 Flash 加密 + Secure Boot V2 + NVS 加密 功能,从操作流程上具有如下优点:
- 固件下载完成后,即完成了全部的安全、加密流程
- 芯片第一次上电启动时直接运行
密文固件
- 可规避在安全、加密流程中出现
掉电
或供电不稳
带来的风险
使用 Flash 下载工具(最新版本)完成 Flash 加密 + Secure Boot V2 + NVS 加密 的具体流程如下:
1. 按照如上获取秘钥方式,先获取对应所需要的密钥文件
- 获取 Flash 加密秘钥
由于 Flash 下载工具仅支持 AES-256
,因此推荐使用 AES-128(256 位密钥)
Flash 加密密钥。
espsecure.py generate_flash_encryption_key flash_encryption_key.bin
- 获取 Secure Boot V2 Key
espsecure.py generate_signing_key secure_boot_signing_key.pem --version 2 --scheme rsa3072
- 获取 Secure Boot V2 Key 的
公钥的摘要
在 Flash 下载工具中开启 Secure Boot V2 功能,需要导入 Secure Boot V2 公钥的摘要
,因此需要基于 Secure Boot V2 私钥 Key 生成 公钥的摘要
,参见:Enable Secure Boot V2 Externally
espsecure.py digest_rsa_public_key --keyfile secure_boot_signing_key.pem --output public_key_digest.bin
- 获取
nvs_key
, 并对custom_nvs
分区的custom_nvs.csv
文件进行加密
custom_nvs
分区使用custom_nvs.csv
文件管理所需存储的文件,参考:如何实现 ESP 设备多证书管理?
使用 nvs 分区工具:esp-idf/components/nvs_flash/nvs_partition_generator,通过如下指令获取 nvs_key
文件
python E:\esp\Espressif\frameworks\esp-idf-5.2.1\esp-idf\components\nvs_flash\nvs_partition_generator\nvs_partition_gen.py generate-key --keyfile nvs_key.bin
基于生成的 nvs_key.bin
对 custom_nvs
分区的 custom_nvs.csv
文件进行加密,生成被加密的 encrypt_custom_nvs.bin
python E:\esp\Espressif\frameworks\esp-idf-5.2.1\esp-idf\components\nvs_flash\nvs_partition_generator\nvs_partition_gen.py encrypt custom_nvs.csv encrypt_custom_nvs.bin 0x6000 --inputkey keys\nvs_key.bin
0x6000
为encrypt_custom_nvs.bin
的固件大小
2. 软件配置
-
在 esp-idf SDK 编译环境中,需要开启
Flash 加密
+Secure Boot V2
+NVS 加密
的软件配置
→ Security features
- 由于 Flash 下载工具
仅支持 AES-128(256 位密钥)
,因此推荐使用AES-128(256 位密钥)
Flash 加密密钥。在软件配置中注意选择Size of generated AES-XTS key (AES-128 (256-bit key))
的配置。 Enable usage mode
可以选择Release
模式或Development (NOT SECURE)
模式设置。-
当选择
Release 模式
时,会将SPI_BOOT_CRYPT_CNT
的 eFuse 控制位设置为0b111
;量产推荐选择Release
模式。 -
若设置为
Development (NOT SECURE)
模式,则将SPI_BOOT_CRYPT_CNT
的 eFuse 控制位设置为0b001
,开启Development
模式,支持提供一次
解除 Flash加密的机会。当开启 Flash 加密的Development (NOT SECURE)
模式后,若希望解除 Flash 加密的功能,可通过运行如下指令来解除 Flash 功能:espefuse.py -p port burn_efuse SPI_BOOT_CRYPT_CNT 0x3
-
- 由于 Flash 下载工具
-
开启 NVS 加密
→ Component config → NVS
-
同时,注意
UART ROM download mode
的设置,如果不希望禁用下载模式,推荐选择UART ROM download mode (Enabled (not recommended))
模式。不同下载模式的配置选项说明参见:CONFIG_SECURE_UART_ROM_DL_MODE→ Security features → UART ROM download mode
-
由于 Flash 加密 和 安全启动 功能将
加大 Bootloader
固件,因此需要增大分区表
的偏移地址的设置,如下:默认是
0x8000
, 可以调大为0xF000
idf.py menuconfig —> Partition Table
3. 然后编译工程,获取编译固件:
-
使用如下指令编译当前工程
idf.py build
-
编译完成后会生成如下固件:
- 未签名且未加密的
bootloader-unsigned.bin
- 未签名且未加密的
ota_data_initial.bin
- 不被签名且未加密的
blink-unsigned.bin
- 不被签名且未加密的
partition-table.bin
- 已被签名但未加密的
bootloader.bin
- 已被签名但未加密的
blink.bin
如下:
- 编译后的文件可以在本地路径下找到:
- 未签名且未加密的
-
通过编译完成的日志打印,可以看到需要下载的
固件
和对应的下载地址
如下:
-
需要在 Flash 工具中导入的固件和下载地址如下:
0x0
: bootloader.bin (被签名的bootloader.bin
)
0xf000
:partition-table.bin (不被签名的partition-table.bin
)
0x14000
:ota_data_initial.bin(不被签名的ota_data_initial.bin
)
0x20000
: blink.bin (被签名的blink.bin
)
0x320000
: nvs_key.bin ( NVS 加密密钥)
0x321000
: encrypt_custom_nvs.bin ( 被nvs_key.bin
加密的custom_nvs
分区的固件)
4. Flash 下载工具 配置
-
将
Flash 加密秘钥
和Secure boot V2 公钥的摘要
放到flash_download_tool\bin
目录下
-
在 Flash 下载工具 中的
configure\esp32s3\security.conf
配置文件中, 开启Flash 加密
和Secure Boot V2
的配置选项,如下:
具体修改的安全配置如下:[SECURE BOOT] secure_boot_en = True public_key_digest_path = .\bin\public_key_digest.bin public_key_digest_block_index = 0 [FLASH ENCRYPTION] flash_encryption_en = True reserved_burn_times = 0 flash_encrypt_key_block_index = 1 [SECURE OTHER CONFIG] flash_encryption_use_customer_key_enable = True flash_encryption_use_customer_key_path = .\bin\flash_encryption_key.bin flash_force_write_enable = True [FLASH ENCRYPTION KEYS LOCAL SAVE] keys_save_enable = False encrypt_keys_enable = False encrypt_keys_aeskey_path = [ESP32S3 EFUSE BIT CONFIG] dis_usb_jtag = True hard_dis_jtag = True soft_dis_jtag = 7 dis_usb_otg_download_mode = True dis_direct_boot = True dis_download_icache = True dis_download_dcache = True dis_download_manual_encrypt = True
-
[SECURE BOOT]
secure_boot_en = True
:开启 Secure Bootpublic_key_digest_path = .\bin\public_key_digest.bin
:指定 Secure boot V2 Key 的公钥的摘要。注意:此路径( .\bin\public_key_digest.bin)是基于 Flash 下载工具的路径为当前路径
public_key_digest_block_index = 0
:设置Secure Boot 公钥的摘要
的存储位置,仅适用于 ESP32-C 系列和 ESP32-S 系列,Secure Boot 公钥的摘要
的存储范围可选0~4
。即支持设置BLOCK_KEY0 ~ BLOCK_KEY4
,对应eFuse BLOCK4 ~ BLOCK8
。注:ESP32-C2
只可选0
。如下:
-
[FLASH ENCRYPTION]
flash_encryption_en = True
:开启 Flash 加密reserved_burn_times = 0
: 设置预留烧录次数,此设置若设置为0
,对应的SPI_BOOT_CRYPT_CNT
的 eFuse 控制位将写为0x7
;若设置为3
,对应的SPI_BOOT_CRYPT_CNT
的 eFuse 控制位将写为0x1
。当软件配置设置为Release 模式
时,则此参数应设置为0
。flash_encrypt_key_block_index = 1
: 设置 Flash 加密密钥的存储位置,仅适用于 ESP32-C 系列和 ESP32-S 系列,Flash 加密密钥的存储范围可选0~4
。即支持设置BLOCK_KEY0 ~ BLOCK_KEY4
,对应eFuse BLOCK4 ~ BLOCK8
。注:ESP32-C2
只可选0
。
-
[SECURE OTHER CONFIG]
flash_encryption_use_customer_key_enable = True
: 是否使用客户指定的 Flash 加密密钥flash_encryption_use_customer_key_path = .\bin\flash_encrypt_key.bin
: 设置 Flash 加密密钥的路径,注意:此路径( .\bin\flash_encrypt_key.bin)是基于 Flash 下载工具的路径为当前路径
flash_force_write_enable = False
: 配置烧录时是否跳过加密和安全启动检查。默认为False
,当设置为False
时,若对已经开启 Flash 加密或安全启动的产品烧录时会弹窗报错。当设置为True
时,在对未禁用下载模式,但已经开启Flash
加密或安全启动的产品烧录时,将不做安全检查。
5. 重新启动 Flash 下载工具
开启 Flash 下载工具 后 ,将会读取 configure\esp32s3\security.conf
配置文件信息,如下:
6. 导入所有待下载的固件
按照分区表的设置添加所有待下载的固件,并设置对应的下载地址,如下:
注意:不支持直接导入
合并的固件
bootloader.bin
和blink.bin
为已签名
的固件。nvs_key.bin
为 nvs 加密密钥encrypt_custom_nvs.bin
为加密的custom_nvs.bin
7. 烧写固件
- 固件将在下载过程中会将
Flash加密密钥
和Secure boot V2 公钥的摘要
写入芯片 eFuse BLOCK 中。 - 然后写
SPI_BOOT_CRYPT_CNT
eFuse 位 来启用Flash 加密
;写SECURE_BOOT_EN
eFuse 位 来启用Secure Boot V2
。 - 然后使能
configure\esp32s3\security.conf
文件中的[esp32s3 EFUSE BIT CONFIG]
配置选项
如下黑框日志:
test offset : 3276800 0x320000
case ok
test offset : 3280896 0x321000
case ok
.
Changing baud rate to 115200
Changed.
NO XMC flash detected!
ESP32 secure boot v2 skip generate key
burn secure key ...
Burn keys to blocks:
- BLOCK_KEY0 -> [ae ba 41 be 66 f5 00 35 7d 20 9e 62 5f f7 b4 3a 6a 3c 2a fd f8 3e ac cc 2b 00 bb ae a8 b8 79 5b]
'KEY_PURPOSE_0': 'USER' -> 'SECURE_BOOT_DIGEST0'.
Disabling write to 'KEY_PURPOSE_0'.
Disabling write to key block
Check all blocks for burn...
idx, BLOCK_NAME, Conclusion
[00] BLOCK0 is not empty
(written ): 0x00000000800000020040000040040000000f0c0201000200
(to write): 0x000000000000000000000000090000000000000000800100
(coding scheme = NONE)
[04] BLOCK_KEY0 is empty, will burn the new value
.
This is an irreversible operation!
BURN BLOCK4 - OK (write block == read block)
BURN BLOCK0 - OK (all write block bits are set)
Reading updated efuses...
Successful
The efuses to burn:
from BLOCK0
- SPI_BOOT_CRYPT_CNT
- SECURE_BOOT_EN
Burning efuses:
- 'SPI_BOOT_CRYPT_CNT' (Enables flash encryption when 1 or 3 bits are set and disabled otherwise) 0b001 -> 0b111
- 'SECURE_BOOT_EN' (Set this bit to enable secure boot) 0b0 -> 0b1
Check all blocks for burn...
idx, BLOCK_NAME, Conclusion
[00] BLOCK0 is not empty
(written ): 0x00000000800000020040000049040000000f0c0201800300
(to write): 0x000000000000000000100000001c00000000000000000000
(coding scheme = NONE)
.
This is an irreversible operation!
BURN BLOCK0 - OK (all write block bits are set)
Reading updated efuses...
Checking efuses...
Successful
WARNING: - compress and encrypt options are mutually exclusive
Will flash uncompressed
Took 0.43s to erase flash block
Took 0.05s to erase flash block
Took 0.08s to erase flash block
Took 1.23s to erase flash block
Took 0.05s to erase flash block
Took 0.24s to erase flash block
The efuses to burn:
from BLOCK0
- DIS_USB_JTAG
- DIS_PAD_JTAG
- SOFT_DIS_JTAG
- DIS_DIRECT_BOOT
- DIS_DOWNLOAD_ICACHE
- DIS_DOWNLOAD_DCACHE
- DIS_USB_OTG_DOWNLOAD_MODE
- DIS_DOWNLOAD_MANUAL_ENCRYPT
Burning efuses:
- 'DIS_USB_JTAG' (Set this bit to disable function of usb switch to jtag in module of usb device) 0b1 -> 0b1
The same value for DIS_USB_JTAG is already burned. Do not change the efuse.
- 'DIS_PAD_JTAG' (Set this bit to disable JTAG in the hard way. JTAG is disabled permanently) 0b1 -> 0b1
The same value for DIS_PAD_JTAG is already burned. Do not change the efuse.
- 'SOFT_DIS_JTAG' (Set these bits to disable JTAG in the soft way (odd number 1 means disable ). JTAG can be enabled in HMAC module) 0b111 -> 0b111
The same value for SOFT_DIS_JTAG is already burned. Do not change the efuse.
- 'DIS_DIRECT_BOOT' (Disable direct boot mode) 0b1 -> 0b1
The same value for DIS_DIRECT_BOOT is already burned. Do not change the efuse.
- 'DIS_DOWNLOAD_ICACHE' (Set this bit to disable Icache in download mode (boot_mode[3:0] is 0; 1; 2; 3; 6; 7)) 0b1 -> 0b1
The same value for DIS_DOWNLOAD_ICACHE is already burned. Do not change the efuse.
- 'DIS_DOWNLOAD_DCACHE' (Set this bit to disable Dcache in download mode ( boot_mode[3:0] is 0; 1; 2; 3; 6; 7)) 0b1 -> 0b1
The same value for DIS_DOWNLOAD_DCACHE is already burned. Do not change the efuse.
- 'DIS_DOWNLOAD_MANUAL_ENCRYPT' (Set this bit to disable flash encryption when in download boot modes) 0b0 -> 0b1
Check all blocks for burn...
idx, BLOCK_NAME, Conclusion
[00] BLOCK0 is not empty
(written ): 0x000000008000000200500000491c0000000f0c0201800300
(to write): 0x000000000000000000000000000000000010000000000000
(coding scheme = NONE)
.
This is an irreversible operation!
BURN BLOCK0 - OK (all write block bits are set)
Reading updated efuses...
Checking efuses...
Successful
固件下载过程会完成如下过程:
- 将 Secure Boot V2
公钥的摘要
写到芯片的BLOCK_KEY0 (KEY_PURPOSE_0)
中 - 将
Flash 加密密钥
写到芯片的eFuse BLOCK_KEY1 (KEY_PURPOSE_1)
中 - 将 eFuse 控制位
SPI_BOOT_CRYPT_CNT
写为 0b111 - 将 eFuse 控制位
SECURE_BOOT_EN
写为0b1
- 将 eFuse 控制位
DIS_USB_JTAG
写为0b1
- 将 eFuse 控制位
DIS_PAD_JTAG
写为0b1
- 将 eFuse 控制位
SOFT_DIS_JTAG
写为0b111
- 将 eFuse 控制位
DIS_DIRECT_BOOT
写为0b1
- 将 eFuse 控制位
DIS_DOWNLOAD_ICACHE
写为0b1
- 将 eFuse 控制位
DIS_DOWNLOAD_DCACHE
写为0b1
- 将 eFuse 控制位
DIS_USB_OTG_DOWNLOAD_MODE
写为0b1
- 将 eFuse 控制位
DIS_DOWNLOAD_MANUAL_ENCRYPT
写为0b1
固件下载完成后,整个 Flash 加密的流程也完成。
8. 运行固件:
固件将在第一次上电启动时:
- 检查
Secure Boot
功能是否被开启 - 检查
Flash 加密
功能是否被开启 - 然后验证被签名和被加密的固件
- 验证成功,则固件正常运行
运行日志如下:
ESP-ROM:esp32s3-20210327
Build:Mar 27 2021
rst:0x1 (POWERON),boot:0x8 (SPI_FAST_FLASH_BOOT)
SPIWP:0xee
mode:DIO, clock div:1
Valid secure boot key blocks: 0
secure boot verification succeeded
load:0x3fce3980,len:0x3a1c
load:0x403c9700,len:0x4
load:0x403c9704,len:0xcbc
load:0x403cc700,len:0x52bc
entry 0x403c9914
I (73) boot: ESP-IDF v5.2.1-dirty 2nd stage bootloader
I (73) boot: compile time Apr 25 2024 17:02:34
I (73) boot: Multicore bootloader
I (77) boot: chip revision: v0.1
I (81) boot.esp32s3: Boot SPI Speed : 80MHz
I (85) boot.esp32s3: SPI Mode : DIO
I (90) boot.esp32s3: SPI Flash Size : 8MB
I (95) boot: Enabling RNG early entropy source...
I (100) boot: Partition Table:
I (104) boot: ## Label Usage Type ST Offset Length
I (111) boot: 0 nvs WiFi data 01 02 00010000 00004000
I (119) boot: 1 otadata OTA data 01 00 00014000 00002000
I (126) boot: 2 phy_init RF data 01 01 00016000 00001000
I (134) boot: 3 factory factory app 00 00 00020000 00100000
I (141) boot: 4 ota_0 OTA app 00 10 00120000 00100000
I (149) boot: 5 ota_1 OTA app 00 11 00220000 00100000
I (157) boot: 6 nvs_key NVS keys 01 04 00320000 00001000
I (164) boot: 7 custom_nvs WiFi data 01 02 00321000 00006000
I (172) boot: End of partition table
I (176) boot: Defaulting to factory image
I (181) esp_image: segment 0: paddr=00020020 vaddr=3c020020 size=0e158h ( 57688) map
I (201) esp_image: segment 1: paddr=0002e180 vaddr=3fc92400 size=01e98h ( 7832) load
I (203) esp_image: segment 2: paddr=00030020 vaddr=42000020 size=1adech (110060) map
I (228) esp_image: segment 3: paddr=0004ae14 vaddr=3fc94298 size=00bc0h ( 3008) load
I (229) esp_image: segment 4: paddr=0004b9dc vaddr=40374000 size=0e398h ( 58264) load
I (248) esp_image: segment 5: paddr=00059d7c vaddr=00000000 size=06254h ( 25172)
I (253) esp_image: Verifying image signature...
I (254) secure_boot_v2: Verifying with RSA-PSS...
I (258) secure_boot_v2: Signature verified successfully!
I (267) boot: Loaded app from partition at offset 0x20000
I (268) secure_boot_v2: enabling secure boot v2...
I (273) secure_boot_v2: secure boot v2 is already enabled, continuing..
I (280) boot: Checking flash encryption...
I (285) flash_encrypt: flash encryption is enabled (0 plaintext flashes left)
I (293) boot: Disabling RNG early entropy source...
I (310) cpu_start: Multicore app
I (319) cpu_start: Pro cpu start user code
I (319) cpu_start: cpu freq: 160000000 Hz
I (320) cpu_start: Application information:
I (322) cpu_start: Project name: blink
I (327) cpu_start: App version: v5.2.1-dirty
I (333) cpu_start: Compile time: Apr 25 2024 17:02:27
I (339) cpu_start: ELF file SHA256: 974df8541...
I (344) cpu_start: ESP-IDF: v5.2.1-dirty
I (349) cpu_start: Min chip rev: v0.0
I (354) cpu_start: Max chip rev: v0.99
I (359) cpu_start: Chip rev: v0.1
I (364) heap_init: Initializing. RAM available for dynamic allocation:
I (371) heap_init: At 3FC958A8 len 00053E68 (335 KiB): RAM
I (377) heap_init: At 3FCE9710 len 00005724 (21 KiB): RAM
I (383) heap_init: At 3FCF0000 len 00008000 (32 KiB): DRAM
I (389) heap_init: At 600FE010 len 00001FD8 (7 KiB): RTCRAM
I (397) spi_flash: detected chip: generic
I (400) spi_flash: flash io: dio
I (404) flash_encrypt: Flash encryption mode is RELEASE
I (411) efuse: Batch mode of writing fields is enabled
W (416) secure_boot: Unused SECURE_BOOT_DIGEST1 should be revoked. Fixing..
W (424) secure_boot: Unused SECURE_BOOT_DIGEST2 should be revoked. Fixing..
I (431) efuse: BURN BLOCK0
I (436) efuse: BURN BLOCK0 - OK (all write block bits are set)
I (441) efuse: Batch mode. Prepared fields are committed
I (447) secure_boot: Fixed
I (451) nvs_sec_provider: NVS Encryption - Registering Flash encryption-based scheme...
I (460) sleep: Configure to isolate all GPIO pins in sleep state
I (466) sleep: Enable automatic switching of GPIO sleep configuration
I (473) main_task: Started on CPU0
I (483) main_task: Calling app_main()
I (483) example: Example configured to blink GPIO LED!
I (483) gpio: GPIO[48]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (493) example: Turning the LED OFF!
I (1503) example: Turning the LED ON!
I (2503) example: Turning the LED OFF!
9. 检查 eFuse 信息
使用 esptool 工具运行如下指令来获取芯片的 eFuse 信息
espefuse.py -p COM4 summary
- 获取的芯片安全信息如下:
Security fuses:
DIS_DOWNLOAD_ICACHE (BLOCK0) Set this bit to disable Icache in download mode (b = True R/W (0b1)
oot_mode[3:0] is 0; 1; 2; 3; 6; 7)
DIS_DOWNLOAD_DCACHE (BLOCK0) Set this bit to disable Dcache in download mode ( = True R/W (0b1)
boot_mode[3:0] is 0; 1; 2; 3; 6; 7)
DIS_FORCE_DOWNLOAD (BLOCK0) Set this bit to disable the function that forces c = False R/W (0b0)
hip into download mode
DIS_DOWNLOAD_MANUAL_ENCRYPT (BLOCK0) Set this bit to disable flash encryption when in d = True R/W (0b1)
ownload boot modes
SPI_BOOT_CRYPT_CNT (BLOCK0) Enables flash encryption when 1 or 3 bits are set = Enable R/W (0b111)
and disabled otherwise
SECURE_BOOT_KEY_REVOKE0 (BLOCK0) Revoke 1st secure boot key = False R/W (0b0)
SECURE_BOOT_KEY_REVOKE1 (BLOCK0) Revoke 2nd secure boot key = True R/W (0b1)
SECURE_BOOT_KEY_REVOKE2 (BLOCK0) Revoke 3rd secure boot key = True R/W (0b1)
KEY_PURPOSE_0 (BLOCK0) Purpose of Key0 = SECURE_BOOT_DIGEST0 R/- (0x9)
KEY_PURPOSE_1 (BLOCK0) Purpose of Key1 = XTS_AES_128_KEY R/- (0x4)
KEY_PURPOSE_2 (BLOCK0) Purpose of Key2 = USER R/W (0x0)
KEY_PURPOSE_3 (BLOCK0) Purpose of Key3 = USER R/W (0x0)
KEY_PURPOSE_4 (BLOCK0) Purpose of Key4 = USER R/W (0x0)
KEY_PURPOSE_5 (BLOCK0) Purpose of Key5 = USER R/W (0x0)
SECURE_BOOT_EN (BLOCK0) Set this bit to enable secure boot = True R/W (0b1)
SECURE_BOOT_AGGRESSIVE_REVOKE (BLOCK0) Set this bit to enable revoking aggressive secure = False R/W (0b0)
boot
DIS_DOWNLOAD_MODE (BLOCK0) Set this bit to disable download mode (boot_mode[3 = False R/W (0b0)
:0] = 0; 1; 2; 3; 6; 7)
ENABLE_SECURITY_DOWNLOAD (BLOCK0) Set this bit to enable secure UART download mode = False R/W (0b0)
SECURE_VERSION (BLOCK0) Secure version (used by ESP-IDF anti-rollback feat = 0 R/W (0x0000)
ure)
BLOCK_KEY0 (BLOCK4)
Purpose: SECURE_BOOT_DIGEST0
Key0 or user data
= ae ba 41 be 66 f5 00 35 7d 20 9e 62 5f f7 b4 3a 6a 3c 2a fd f8 3e ac cc 2b 00 bb ae a8 b8 79 5b R/-
BLOCK_KEY1 (BLOCK5)
Purpose: XTS_AES_128_KEY
Key1 or user data
= ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? -/-
BLOCK_KEY2 (BLOCK6)
Purpose: USER
Key2 or user data
= 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 R/W
- 也可以使用如下指令读取芯片的安全信息
esptool.py -p PORT get_security_info
说明
-
只要没有禁用下载模式就支持读取芯片 eFuse 信息和重新下载固件。
-
Flash 下载工具的默认配置会校验 eFuse 信息,当芯片开启
Flash 加密
或Secure boot
功能后,若使用默认配置则不支持重烧固件。若芯片没有关闭下载模式,并希望在开启Flash 加密
或Secure boot
功能后也支持重新烧录密文固件或签名固件,则需要修改 Flash 下载工具里的默认配置,以 ESP32S3 为例:-
修改
esp32s3 > security.conf
文件里的默认配置将
flash_force_write_enable = False
改为flash_force_write_enable = True
-
修改
esp32s3 > spi_download.conf
文件里的默认配置将
no_stub = False
改为no_stub = True
-
-
若使用
esptool
工具,则可以通过如下指令重烧签名固件或加密的固件:
esptool.py --chip esp32s3 -p COM4 -b 460800 --before=default_reset --after=no_reset --no-stub write_flash --force --flash_mode dio --flash_freq 80m --flash_size keep 0x0 encrypt_bootloader.bin 0xF000 encrypt_partition.bin 0x20000 encrypt_blink.bin
-
Flash 加密的
Release 模式
与Develop 模式
的主要区别就是SPI_BOOT_CRYPT_CNT
控制位的值不同,Develop 模式
(0x1
)支持一次
机会来解除 Flash 加密功能;Release 模式
(0x111
)不支持解除 Flash 加密功能。 -
使用
Flash 加密密钥
给明文固件进行加密的指令:espsecure.py encrypt_flash_data --keyfile flash_encryption_key.bin --address 0x0 --output bootloader-encrypted.bin bootloader.bin
-
使用
Flash 加密密钥
对加密的固件进行解密
的指令:espsecure.py decrypt_flash_data --keyfile flash_encryption_key.bin --address 0x0 --output decrypt_bootloader.bin bootloader-encrypted.bin