ESP32的代码是存在外部Flash中,如果不加密,很容易被窃取代码。
ESP32的secure boot和flash加密是两个功能,但是要配合一起使用,其加密效果才好。
一、初次加密。
这里只写可重复烧写的加密方式,其加密步骤如下:
1、进入menuconfig配置secure boot和flash加密。
make menuconfig
这里Secure bootloader mode选择Reflashable。配置后要与下图完全一致。
2、生成私钥,即pem文件。
python $IDF_PATH/components/esptool_py/esptool/espsecure.py generate_signing_key secure_boot_signing_key.pem
3、生成flash的加密的key文件。
python $IDF_PATH/components/esptool_py/esptool/espsecure.py generate_flash_encryption_key flash_encryption_key.bin
4、编译分区表和用户代码。由于配置了secure boot,所以这里不再编译bootloader。
make
5、单独编译bootloader。
make bootloader
6、烧写secure boot的熔丝(仅烧写一次),执行该命令后,需要手动输入BURN,回车,才能烧写。
python $IDF_PATH/components/esptool_py/esptool/espefuse.py burn_key secure_boot build/bootloader/secure-bootloader-key-256.bin
7、烧写flash加密的熔丝(仅烧写一次),执行该命令后,需要手动输入BURN,回车,才能烧写。
python $IDF_PATH/components/esptool_py/esptool/espefuse.py burn_key flash_encryption flash_encryption_key.bin
8、利用flash的key文件,对bootloader、分区表、用户代码进行加密。
注意:这里加密的是有摘要的bootloader,即:bootloader-reflash-digest.bin。
各文件的地址,要核对清楚。
python $IDF_PATH/components/esptool_py/esptool/espsecure.py encrypt_flash_data --keyfile flash_encryption_key.bin --address 0x0 -o build/bootloader/bootloader_digest_encrypt.bin build/bootloader/bootloader-reflash-digest.bin
python $IDF_PATH/components/esptool_py/esptool/espsecure.py encrypt_flash_data --keyfile flash_encryption_key.bin --address 0xf000 -o build/partitions_encrypt.bin build/partitions.bin
python $IDF_PATH/components/esptool_py/esptool/espsecure.py encrypt_flash_data --keyfile flash_encryption_key.bin --address 0x10000 -o build/user_app_encrypt.bin build/user_app.bin
9、烧写加密后的文件。各文件的地址,要核对清楚。
python $IDF_PATH/components/esptool_py/esptool/esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 600000 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x0 build/bootloader/bootloader_digest_encrypt.bin
python $IDF_PATH/components/esptool_py/esptool/esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 600000 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0xf000 build/partitions_encrypt.bin
python $IDF_PATH/components/esptool_py/esptool/esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 600000 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x10000 build/user_app_encrypt.bin
10、对以下熔丝的寄存器进行烧写(仅烧写一次)。
python $IDF_PATH/components/esptool_py/esptool/espefuse.py burn_efuse ABS_DONE_0
python $IDF_PATH/components/esptool_py/esptool/espefuse.py burn_efuse FLASH_CRYPT_CNT
python $IDF_PATH/components/esptool_py/esptool/espefuse.py burn_efuse FLASH_CRYPT_CONFIG 0xf
python $IDF_PATH/components/esptool_py/esptool/espefuse.py burn_efuse DISABLE_DL_ENCRYPT
python $IDF_PATH/components/esptool_py/esptool/espefuse.py burn_efuse DISABLE_DL_DECRYPT
python $IDF_PATH/components/esptool_py/esptool/espefuse.py burn_efuse DISABLE_DL_CACHE
二、对已加密的芯片进行更新代码。
只需要重新编译用户代码,加密,再烧写加密后的bin文件。
make apppython $IDF_PATH/components/esptool_py/esptool/espsecure.py encrypt_flash_data --keyfile flash_encryption_key.bin --address 0x10000 -o build/user_app_encrypt.bin build/user_app.binpython $IDF_PATH/components/esptool_py/esptool/esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 600000 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x10000 build/user_app_encrypt.bin
三、批量加密。
只需要烧写熔丝,再烧写bootloader、分区表、用户代码。
python $IDF_PATH/components/esptool_py/esptool/espefuse.py burn_key secure_boot /home/ai-thinker/webserver-esp/examples/single_chip/camera_web_server/build/bootloader/secure-bootloader-key-256.binpython $IDF_PATH/components/esptool_py/esptool/espefuse.py burn_key flash_encryption flash_encryption_key.binpython $IDF_PATH/components/esptool_py/esptool/esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 600000 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x0 build/bootloader/bootloader_digest_encrypt.bin
python $IDF_PATH/components/esptool_py/esptool/esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 600000 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0xf000 build/partitions_encrypt.bin
python $IDF_PATH/components/esptool_py/esptool/esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 600000 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq 40m --flash_size detect 0x10000 build/user_app_encrypt.binpython $IDF_PATH/components/esptool_py/esptool/espefuse.py burn_efuse ABS_DONE_0
python $IDF_PATH/components/esptool_py/esptool/espefuse.py burn_efuse FLASH_CRYPT_CNT
python $IDF_PATH/components/esptool_py/esptool/espefuse.py burn_efuse FLASH_CRYPT_CONFIG 0xf
python $IDF_PATH/components/esptool_py/esptool/espefuse.py burn_efuse DISABLE_DL_ENCRYPT
python $IDF_PATH/components/esptool_py/esptool/espefuse.py burn_efuse DISABLE_DL_DECRYPT
python $IDF_PATH/components/esptool_py/esptool/espefuse.py burn_efuse DISABLE_DL_CACHE
四、其它问题。
1、私钥pem文件。
建议一套产品生成一个pem文件,要对pem文件进行备份,防止不能更新代码。(重新生成pem文件可能密钥不相同,导入无法更新已加密的芯片)。
2、烧写的地址。
加密前,bootloader存在0x1000地址,分区表存在0x8000地址,用户代码存在0x10000地址。
加密后,bootloader存在0x0地址,分区表存在0xf000地址,用户代码存在0x10000地址。
加密后的bootloader要存在0x0地址,否则不能启动。这里把分区表放在0xf000,是因为secure boot会让bootloader的体积变大,可能会影响代码存储。
分区表的地址,可以在这里修改。
3、可能会用到的指令。
查看芯片的寄存器
python $IDF_PATH/components/esptool_py/esptool/espefuse.py --port /dev/ttyUSB0 summary擦除整个flash
python $IDF_PATH/components/esptool_py/esptool/esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 600000 erase_flash对文件进行签名
python $IDF_PATH/components/esptool_py/esptool/espsecure.py sign_data --version 1 --keyfile secure_boot_signing_key.pem --output ./build/partitions-signed.bin ./build/partitions-unsigned.bin
4、版本。
secure boot有V1和V2两个版本。
在make menuconfig可以查看到,这里是V1版本(version 1)。
5、用户代码。
这里的指令用的是user_app.bin,这里user_app要针对自己编译出来的bin文件名来修改。
6、环境配置。
这里使用ESP32-S模块,linux系统下,要安装好python和配置环境变量$IDF_PATH。
这里的波特率设置到600000,如果烧写不成功,可以降低波特率。