当前页面为 开发中 版本,查看特定版本的文档,请在页面左下角的下拉菜单中进行选择。

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 例程演示说明

  1. 通过 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,二者不一致,所以报了警告

  2. 断开 JLink 与芯片的连接,然后将 PanLink 连接至芯片(可能需要将芯片从 EVB 底板取下),打开 PanLink 上位机工具,使能 “加密信息配置”,并同时选择载入以下两个文件:

    1. 本例程生成的加密配置信息文件(Images\encrypt_info_enc.bin

    2. 本例程生成的未加密固件(Images\fw_encryption.binImages\fw_encryption.hex

    image

    PanLink 载入加密配置信息文件和未加密固件完成

    具体操作步骤请参考 PanLink 上位机工具文档。

  3. 点击 “下载” 按钮,即可将本工程的加密配置信息(包括加密使能开关、防注入保护使能开关、加密 Flash 区域配置、加密秘钥等)和明文固件分别烧录到芯片 eFuse 和 Flash 中:

    image

    PanLink 烧录加密配置信息文件和未加密固件成功

  4. 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 中的程序是明文程序,因此经过解密操作后反而会出错。

  5. 重新配置 Panlink,此时我们取消勾选 “加密信息配置”,并且在 “下载程序配置” 中,指定烧录的 Image 为 Images\fw_encryption_enc.binImages\fw_encryption_enc.hex 文件,然后点击 “下载” 按钮,将加密后的 Image 烧录至芯片:

    image

    PanLink 烧录加密固件

  6. 再次复位芯片,可以看到此时程序又可以正常执行:

    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 开发者说明

本工程相比与其他的普通工程(如蓝牙例程)有如下区别:

  1. 在 Keil 工程目录下新增了加密信息配置文件(encrypt_info.yaml):

    image

    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 的地址是否有效

    警告

    1. 本文件中包含明文的加密秘钥(encrypt_key),一定要妥善保管,不可随意外传,以防密钥泄露!

    2. 在编译过程中,Keil 的 After Build 流程会基于本文件生成一个二次加密后的 encrypt_info_enc.bin 文件,此文件中会对秘钥添加扰码,因此在 PanLink 载入加密信息的过程中建议使用此文件,而不是明文的 yaml 文件。

  2. 在 SDK Config 配置(configuration\sdk_config.h)文件中,使能了固件加密功能,并配置了 Flash 加密区域:

    image

    SDK Config File

    :此处配置的 Encrypt Flash Offset 值一定要与 encrypt_info.yaml 文件中配置的 encrypt_flash_offset 值相同!

  3. 在程序代码中,将需要加密的函数添加 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 字节),因此在实际项目中应当选取一个重要且简短的函数作为加密函数段。