Firmware Encryption¶
1 功能概述¶
本例程演示芯片通过固件加密、硬件解密的机制保护 Flash 关键代码的方法。
重要
本功能需要用到 PanLink 量产烧录工具,为正常演示本例程,请确保您的 PanLink 上位机工具版本不低于 v0.0.005
。
警告
本功能需要通过 PanLink 工具烧录芯片 eFuse 的特定地址,eFuse 的物理特性是同一地址只可烧录一次,无法还原,因此当某颗芯片使能加密功能后,其将只能正常运行加密后的固件,无法再正常运行普通的明文固件!
2 环境准备¶
硬件设备与线材:
PAN107X EVB 核心板与底板各一块
JLink 仿真器(用于烧录例程明文程序)
PanLink 量产烧录工具(用于烧录固件加密信息至芯片 eFuse,以及烧录例程加密程序至芯片 Flash)
USB-TypeC 线一条(用于底板供电和查看串口打印 Log)
杜邦线数根或跳线帽数个(用于连接各个硬件设备)
硬件接线:
将 EVB 核心板插到底板上
使用 USB-TypeC 线,将 PC USB 插口与 EVB 底板 USB->UART 插口相连
使用杜邦线将 EVB 底板上的 TX 引脚接至核心板 P16,RX 引脚接至核心板 P17
根据情况将 PanLink 或 Jlink 仿真器连接至芯片
PC 软件:
串口调试助手(UartAssist)或终端工具(SecureCRT),波特率 921600(用于接收串口打印 Log)
PanLink 上位机工具
3 编译和烧录¶
例程位置:<PAN10XX-NDK>\01_SDK\nimble\samples\security\fw_encryption\keil_107x
双击 Keil Project 文件打开工程,编译成功后,使用 Keil - Flash Download 按钮,向未使能加密功能的芯片中烧录明文程序。
4 例程演示说明¶
通过 Keil 将明文程序烧录至芯片后,可以看到程序正常执行:
Try to load HW calibration data.. DONE. - Chip Info : 0x1 - Chip CP Version : 255 - Chip FT Version : 6 - Chip MAC Address : E11000001012 - Chip UID : 250001465454455354 - Chip Flash UID : 4250315A3538380B005B474356033C78 - Chip Flash Size : 512 KB (Inc. 4KB Panchip Info Area) - Current Flash Map : +-------------------------+ <- Addr: 0x00000 | App Partition | | (480 KB) | +-------------------------+ <- Addr: 0x78000 | KVStore Partition | | ( 16 KB) | +-------------------------+ <- Addr: 0x7C000 | User Custom Partition | | ( 12 KB) | +-------------------------+ <- Addr: 0x7F000 | Panchip Info Area | | (4 KB, Hidden) | +-------------------------+ <- End : 0x80000 (512 KB) The RCL clock frequency (after calibrate) is 31993 Hz [I] App started.. Dump eFuse content after reset: FW Encryption AES Key in eFuse: Addr:Data Addr:Data Addr:Data Addr:Data 0x00:0x00(OK) 0x01:0x00(OK) 0x02:0x00(OK) 0x03:0x00(OK) 0x04:0x00(OK) 0x05:0x00(OK) 0x06:0x00(OK) 0x07:0x00(OK) 0x08:0x00(OK) 0x09:0x00(OK) 0x0a:0x00(OK) 0x0b:0x00(OK) 0x0c:0x00(OK) 0x0d:0x00(OK) 0x0e:0x00(OK) 0x0f:0x00(OK) FW Encryption Flash Offset in eFuse (Address 0x18 ~ 0x1A): 0x000000 Secure Enable Control Flag in eFuse (Address 0x1B): 0x00 Note: - BIT0: FW Encryption Enable Ctrl - BIT1: Anti-injection Enable Ctrl - BIT2: Debug Protection Enable Ctrl [W] The CONFIG_ENCRYPT_FLASH_OFFSET value of current program is not corresponding with FW Encryption Flash Offset in eFuse! [W] -> CONFIG_ENCRYPT_FLASH_OFFSET = 0x000001 [W] -> FW Encryption Flash Offset in eFuse = 0x000000 Done. [ENC] Hello from encrypted_test_function! [I] Secret calcucation result: 0x4905b510
从上述 Log 信息可以看到:
芯片 eFuse 中的加密保护相关位置都是没有被写入过的,读出值均为 0
由于工程配置中使能了加密功能,且加密 Flash Offset 配置为 0x1,而程序运行过程中读到 eFuse 中的实际加密 Flash Offset 为 0,二者不一致,所以报了警告
断开 JLink 与芯片的连接,然后将 PanLink 连接至芯片(可能需要将芯片从 EVB 底板取下),打开 PanLink 上位机工具,使能 “加密信息配置”,并同时选择载入以下两个文件:
本例程生成的加密配置信息文件(
Images\encrypt_info_enc.bin
)本例程生成的未加密固件(
Images\fw_encryption.bin
或Images\fw_encryption.hex
)
PanLink 载入加密配置信息文件和未加密固件完成¶
具体操作步骤请参考 PanLink 上位机工具文档。
点击 “下载” 按钮,即可将本工程的加密配置信息(包括加密使能开关、防注入保护使能开关、加密 Flash 区域配置、加密秘钥等)和明文固件分别烧录到芯片 eFuse 和 Flash 中:
PanLink 烧录加密配置信息文件和未加密固件成功¶
eFuse 烧录成功后,复位芯片,可以看到刚才可以正常执行的程序,此时出现了 Hardfault,并且 eFuse 中的加密开关为使能状态:
Try to load HW calibration data.. DONE. - Chip Info : 0x1 - Chip CP Version : 255 - Chip FT Version : 6 - Chip MAC Address : E11000001012 - Chip UID : 250001465454455354 - Chip Flash UID : 4250315A3538380B005B474356033C78 - Chip Flash Size : 512 KB (Inc. 4KB Panchip Info Area) - Current Flash Map : +-------------------------+ <- Addr: 0x00000 | App Partition | | (480 KB) | +-------------------------+ <- Addr: 0x78000 | KVStore Partition | | ( 16 KB) | +-------------------------+ <- Addr: 0x7C000 | User Custom Partition | | ( 12 KB) | +-------------------------+ <- Addr: 0x7F000 | Panchip Info Area | | (4 KB, Hidden) | +-------------------------+ <- End : 0x80000 (512 KB) The RCL clock frequency (after calibrate) is 31997 Hz [I] App started.. Dump eFuse content after reset: FW Encryption AES Key in eFuse: Addr:Data Addr:Data Addr:Data Addr:Data 0x00:0x00(N/A) 0x01:0x00(N/A) 0x02:0x00(N/A) 0x03:0x00(N/A) 0x04:0x00(N/A) 0x05:0x00(N/A) 0x06:0x00(N/A) 0x07:0x00(N/A) 0x08:0x00(N/A) 0x09:0x00(N/A) 0x0a:0x00(N/A) 0x0b:0x00(N/A) 0x0c:0x00(N/A) 0x0d:0x00(N/A) 0x0e:0x00(N/A) 0x0f:0x00(N/A) FW Encryption Flash Offset in eFuse (Address 0x18 ~ 0x1A): 0x000001 Secure Enable Control Flag in eFuse (Address 0x1B): 0x03 Note: - BIT0: FW Encryption Enable Ctrl - BIT1: Anti-injection Enable Ctrl - BIT2: Debug Protection Enable Ctrl Done. In Hard Fault Handler r0 = 0x20000db0 r1 = 0x40003000 r2 = 0x0 r3 = 0x2085 r12 = 0xffffffff lr = 0x208b pc = 0x100 psr = 0x41000000
这是因为芯片此时已经开启了加密使能,当程序执行到 eFuse 中配置的 Flash 加密区域后,会使用秘钥先将程序解密后运行,而此时由于 Flash 中的程序是明文程序,因此经过解密操作后反而会出错。
重新配置 Panlink,此时我们取消勾选 “加密信息配置”,并且在 “下载程序配置” 中,指定烧录的 Image 为
Images\fw_encryption_enc.bin
或Images\fw_encryption_enc.hex
文件,然后点击 “下载” 按钮,将加密后的 Image 烧录至芯片:PanLink 烧录加密固件¶
再次复位芯片,可以看到此时程序又可以正常执行:
Try to load HW calibration data.. DONE. - Chip Info : 0x1 - Chip CP Version : 255 - Chip FT Version : 6 - Chip MAC Address : E11000001012 - Chip UID : 250001465454455354 - Chip Flash UID : 4250315A3538380B005B474356033C78 - Chip Flash Size : 512 KB (Inc. 4KB Panchip Info Area) - Current Flash Map : +-------------------------+ <- Addr: 0x00000 | App Partition | | (480 KB) | +-------------------------+ <- Addr: 0x78000 | KVStore Partition | | ( 16 KB) | +-------------------------+ <- Addr: 0x7C000 | User Custom Partition | | ( 12 KB) | +-------------------------+ <- Addr: 0x7F000 | Panchip Info Area | | (4 KB, Hidden) | +-------------------------+ <- End : 0x80000 (512 KB) The RCL clock frequency (after calibrate) is 31998 Hz [I] App started.. Dump eFuse content after reset: FW Encryption AES Key in eFuse: Addr:Data Addr:Data Addr:Data Addr:Data 0x00:0x00(N/A) 0x01:0x00(N/A) 0x02:0x00(N/A) 0x03:0x00(N/A) 0x04:0x00(N/A) 0x05:0x00(N/A) 0x06:0x00(N/A) 0x07:0x00(N/A) 0x08:0x00(N/A) 0x09:0x00(N/A) 0x0a:0x00(N/A) 0x0b:0x00(N/A) 0x0c:0x00(N/A) 0x0d:0x00(N/A) 0x0e:0x00(N/A) 0x0f:0x00(N/A) FW Encryption Flash Offset in eFuse (Address 0x18 ~ 0x1A): 0x000001 Secure Enable Control Flag in eFuse (Address 0x1B): 0x03 Note: - BIT0: FW Encryption Enable Ctrl - BIT1: Anti-injection Enable Ctrl - BIT2: Debug Protection Enable Ctrl Done. [ENC] Hello from encrypted_test_function! [I] Secret calcucation result: 0x4905b510
由上述 Log 信息可以看到:
eFuse 中存放固件加密秘钥(AES Key)的地方已经无法正常读取(虽然显示为0,但实际上此处已经通过 PanLink 工具烧写过)
eFuse 中配置的加密 Flash Offset 为 0x1,与 App 工程配置一致
eFuse 中固件加密功能的控制位(即 eFuse 0x1B 地址的 BIT0/BIT1)均已经被置1,表示固件加密使能和防注入保护功能均已开启
5 开发者说明¶
本工程相比与其他的普通工程(如蓝牙例程)有如下区别:
在 Keil 工程目录下新增了加密信息配置文件(
encrypt_info.yaml
):Encrypt Info File¶
其中各个 item 解释如下:
secure_enable: true
:使能固件加密功能anti_injection_enable: true
:使能防注入保护功能,与固件加密功能结合使用,作用是防止通过 SWD Debug 的方式获取到加密 Flash 区域的明文信息encrypt_flash_offset: 0x1
:配置加密 Flash 的第几个 Page(大小 256 字节),如 0x1 表示加密 Flash 的第 1 个 Page,对应 Flash 绝对地址为 0x100;注意此处配置的值一定要与 sdk_config.h 中配置的 Encrypt Flash Offset 值相同!encrypt_key: '4c68384139f574d836bcf34e9dfb01bf'
:配置加密秘钥(AES-128)debug_protect_enable: false
:不使能 SWD Debug Protect 功能debug_key: ''
:不配置 SWD Debug Protect 秘钥expected_start_addr: 0x0
:配置当前 Image 固件的起始地址为 0x0,用于 encrypt tool 交叉验证输入 Image 的地址是否有效
警告
本文件中包含明文的加密秘钥(encrypt_key),一定要妥善保管,不可随意外传,以防密钥泄露!
在编译过程中,Keil 的 After Build 流程会基于本文件生成一个二次加密后的
encrypt_info_enc.bin
文件,此文件中会对秘钥添加扰码,因此在 PanLink 载入加密信息的过程中建议使用此文件,而不是明文的 yaml 文件。
在 SDK Config 配置(
configuration\sdk_config.h
)文件中,使能了固件加密功能,并配置了 Flash 加密区域:SDK Config File¶
注:此处配置的
Encrypt Flash Offset
值一定要与 encrypt_info.yaml 文件中配置的encrypt_flash_offset
值相同!在程序代码中,将需要加密的函数添加
ENCRYPT_SECTION
前缀以将函数编译到 Flash 加密区域:/* * !!ATTENTION!! * Do not try to call an out-of-encrypt-section function but pass a Literal DATA which * stores in the encrypted section if the Anti-injection Feature is enabled. * For example, please don't try to print log in encrypted functions like this: * printf("Enter Encrypt Function\n"); * Use the following form instead: * static const char EncFuncEnterLog[] = "Enter Encrypt Function\n"; * printf(EncFuncEnterLog); */ ENCRYPT_SECTION void encrypted_test_function(uint32_t *calculation) { /* * Do some secret operations/calculations here, and pass the result out. */ *calculation = *(uint32_t *)((uint32_t)(&encrypted_test_function) & 0xFFFFFFFE); /* Define a static const char array (string), and linker would put it into the global RO-DATA area which resides out of the flash encrypt section, so that the out-of-encrypt-section function 'printf' could access this string. */ static const char EncFuncHelloLog[] = "[ENC] Hello from %s!\n\n"; printf(EncFuncHelloLog, __func__); }
注:芯片支持加密的 Flash 大小仅为一个 Page(256 字节),因此在实际项目中应当选取一个重要且简短的函数作为加密函数段。