BLOG8
跳转至

固件加密与防护技术实战

概述

固件加密是保护嵌入式系统知识产权和防止恶意攻击的重要手段。通过对固件进行加密,即使攻击者获取了固件文件,也无法直接读取和分析其中的代码和数据。结合Flash读保护、防回滚机制和安全密钥管理,可以构建多层次的固件防护体系。

本教程将带你从零开始实现完整的固件加密和防护方案,包括:

  • 固件加密的基本原理和算法选择
  • AES加密算法的实现和应用
  • Flash读保护和写保护机制
  • 防回滚和版本控制
  • 密钥的安全生成、存储和管理
  • 加密固件的启动流程

完成本教程后,你将能够:

  • 理解固件加密的核心原理和重要性
  • 掌握AES加密算法的使用方法
  • 实现固件的加密和解密功能
  • 配置Flash保护机制防止固件泄露
  • 设计安全的密钥管理方案
  • 构建完整的固件防护系统

前置知识

在开始本教程之前,你需要:

  • 理解Bootloader的基本概念和工作原理
  • 熟悉C语言编程和指针操作
  • 了解基本的密码学概念(对称加密、非对称加密)
  • 掌握Flash存储器的操作方法
  • 了解安全启动的基本原理

学习目标

通过本教程,你将学会:

  1. 选择合适的加密算法保护固件
  2. 实现AES-128/256加密和解密
  3. 配置STM32的Flash读保护机制
  4. 实现防回滚和版本管理
  5. 安全地生成、存储和使用密钥
  6. 构建加密固件的完整启动流程

准备工作

硬件准备

  • STM32开发板(本教程使用STM32F407)
  • USB转串口模块(用于调试输出)
  • ST-Link调试器(用于固件烧录)
  • 杜邦线若干

软件准备

  • Keil MDK或STM32CubeIDE开发环境
  • STM32CubeMX配置工具
  • Python 3.x(用于固件加密工具)
  • pycryptodome库(Python加密库)
# 安装Python加密库
pip install pycryptodome

环境配置

  1. 安装并配置STM32开发环境
  2. 创建新的STM32项目
  3. 配置UART用于调试输出
  4. 配置系统时钟和基本外设

背景知识

为什么需要固件加密

在嵌入式系统中,固件包含了产品的核心算法和商业机密。如果固件被轻易读取,会带来严重后果:

常见威胁:

  1. 知识产权泄露:竞争对手可以逆向工程,窃取核心算法
  2. 产品克隆:攻击者可以复制固件,制造山寨产品
  3. 恶意篡改:修改固件植入后门或恶意代码
  4. 密钥泄露:固件中的密钥和证书被提取
  5. 调试信息泄露:符号表和调试信息暴露系统细节

固件加密的价值:

  • 保护知识产权:防止核心算法被窃取
  • 防止产品克隆:增加复制产品的难度
  • 提高安全性:即使固件被获取也无法直接使用
  • 满足合规要求:符合行业安全标准
  • 增强竞争力:保护技术优势

加密算法选择

选择合适的加密算法需要平衡安全性、性能和资源消耗:

算法 密钥长度 安全性 速度 资源消耗 适用场景
AES-128 128位 高 快 低 通用场景
AES-256 256位 很高 较快 中等 高安全要求
ChaCha20 256位 很高 很快 低 软件实现
SM4 128位 高 中等 中等 国密标准

推荐选择:

  • 资源受限设备:AES-128(硬件加速)
  • 高安全要求:AES-256
  • 纯软件实现:ChaCha20
  • 国密合规:SM4

AES加密原理

AES (Advanced Encryption Standard) 是目前最广泛使用的对称加密算法。

核心特性:

  • 分组加密:将数据分成128位(16字节)的块
  • 密钥长度:支持128、192、256位密钥
  • 加密轮数:AES-128为10轮,AES-256为14轮
  • 安全性高:目前没有有效的攻击方法

加密模式:

  1. ECB (Electronic Codebook):
  2. 最简单的模式
  3. 相同明文产生相同密文
  4. 不推荐使用(不安全)

  5. CBC (Cipher Block Chaining):

  6. 每个块与前一个密文块异或
  7. 需要初始化向量(IV)
  8. 适合加密大量数据

  9. CTR (Counter):

  10. 将块密码转换为流密码
  11. 可以并行加密
  12. 适合随机访问

  13. GCM (Galois/Counter Mode):

  14. 提供加密和认证
  15. 性能好,安全性高
  16. 推荐用于现代系统

核心内容

1. AES加密实现

我们首先实现AES加密的核心功能,使用mbedTLS库提供的AES接口。

AES加密基础函数

#include "mbedtls/aes.h"
#include "mbedtls/gcm.h"
#include <string.h>

// AES密钥长度
#define AES_KEY_SIZE 16  // 128位
#define AES_BLOCK_SIZE 16  // 128位块

/**
 * @brief AES-128 ECB模式加密
 * @param key 密钥(16字节)
 * @param input 输入数据(16字节)
 * @param output 输出数据(16字节)
 * @return 0成功,-1失败
 */
int AES_Encrypt_ECB(const uint8_t *key, const uint8_t *input, uint8_t *output) {
    mbedtls_aes_context aes_ctx;
    int ret;

    // 初始化AES上下文
    mbedtls_aes_init(&aes_ctx);

    // 设置加密密钥
    ret = mbedtls_aes_setkey_enc(&aes_ctx, key, AES_KEY_SIZE * 8);
    if (ret != 0) {
        mbedtls_aes_free(&aes_ctx);
        return -1;
    }

    // 加密一个块
    ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, input, output);

    // 释放资源
    mbedtls_aes_free(&aes_ctx);

    return (ret == 0) ? 0 : -1;
}

/**
 * @brief AES-128 ECB模式解密
 * @param key 密钥(16字节)
 * @param input 输入数据(16字节)
 * @param output 输出数据(16字节)
 * @return 0成功,-1失败
 */
int AES_Decrypt_ECB(const uint8_t *key, const uint8_t *input, uint8_t *output) {
    mbedtls_aes_context aes_ctx;
    int ret;

    // 初始化AES上下文
    mbedtls_aes_init(&aes_ctx);

    // 设置解密密钥
    ret = mbedtls_aes_setkey_dec(&aes_ctx, key, AES_KEY_SIZE * 8);
    if (ret != 0) {
        mbedtls_aes_free(&aes_ctx);
        return -1;
    }

    // 解密一个块
    ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_DECRYPT, input, output);

    // 释放资源
    mbedtls_aes_free(&aes_ctx);

    return (ret == 0) ? 0 : -1;
}

AES-CBC模式加密

CBC模式更安全,适合加密大量数据:

/**
 * @brief AES-128 CBC模式加密
 * @param key 密钥(16字节)
 * @param iv 初始化向量(16字节)
 * @param input 输入数据
 * @param input_len 输入数据长度(必须是16的倍数)
 * @param output 输出数据
 * @return 0成功,-1失败
 */
int AES_Encrypt_CBC(const uint8_t *key, const uint8_t *iv,
                    const uint8_t *input, size_t input_len,
                    uint8_t *output) {
    mbedtls_aes_context aes_ctx;
    uint8_t iv_copy[AES_BLOCK_SIZE];
    int ret;

    // 检查输入长度
    if (input_len % AES_BLOCK_SIZE != 0) {
        return -1;
    }

    // 复制IV(因为加密过程会修改它)
    memcpy(iv_copy, iv, AES_BLOCK_SIZE);

    // 初始化AES上下文
    mbedtls_aes_init(&aes_ctx);

    // 设置加密密钥
    ret = mbedtls_aes_setkey_enc(&aes_ctx, key, AES_KEY_SIZE * 8);
    if (ret != 0) {
        mbedtls_aes_free(&aes_ctx);
        return -1;
    }

    // CBC模式加密
    ret = mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_ENCRYPT,
                                input_len, iv_copy, input, output);

    // 释放资源
    mbedtls_aes_free(&aes_ctx);

    return (ret == 0) ? 0 : -1;
}

/**
 * @brief AES-128 CBC模式解密
 * @param key 密钥(16字节)
 * @param iv 初始化向量(16字节)
 * @param input 输入数据
 * @param input_len 输入数据长度(必须是16的倍数)
 * @param output 输出数据
 * @return 0成功,-1失败
 */
int AES_Decrypt_CBC(const uint8_t *key, const uint8_t *iv,
                    const uint8_t *input, size_t input_len,
                    uint8_t *output) {
    mbedtls_aes_context aes_ctx;
    uint8_t iv_copy[AES_BLOCK_SIZE];
    int ret;

    // 检查输入长度
    if (input_len % AES_BLOCK_SIZE != 0) {
        return -1;
    }

    // 复制IV
    memcpy(iv_copy, iv, AES_BLOCK_SIZE);

    // 初始化AES上下文
    mbedtls_aes_init(&aes_ctx);

    // 设置解密密钥
    ret = mbedtls_aes_setkey_dec(&aes_ctx, key, AES_KEY_SIZE * 8);
    if (ret != 0) {
        mbedtls_aes_free(&aes_ctx);
        return -1;
    }

    // CBC模式解密
    ret = mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT,
                                input_len, iv_copy, input, output);

    // 释放资源
    mbedtls_aes_free(&aes_ctx);

    return (ret == 0) ? 0 : -1;
}

数据填充处理

由于AES是分组加密,需要对不足16字节的数据进行填充:

/**
 * @brief PKCS7填充
 * @param data 数据缓冲区
 * @param data_len 实际数据长度
 * @param buffer_size 缓冲区大小
 * @return 填充后的长度
 */
size_t PKCS7_Pad(uint8_t *data, size_t data_len, size_t buffer_size) {
    // 计算需要填充的字节数
    size_t padding_len = AES_BLOCK_SIZE - (data_len % AES_BLOCK_SIZE);

    // 检查缓冲区是否足够
    if (data_len + padding_len > buffer_size) {
        return 0;
    }

    // 填充
    for (size_t i = 0; i < padding_len; i++) {
        data[data_len + i] = (uint8_t)padding_len;
    }

    return data_len + padding_len;
}

/**
 * @brief 移除PKCS7填充
 * @param data 数据缓冲区
 * @param data_len 数据长度
 * @return 移除填充后的实际数据长度
 */
size_t PKCS7_Unpad(uint8_t *data, size_t data_len) {
    if (data_len == 0 || data_len % AES_BLOCK_SIZE != 0) {
        return 0;
    }

    // 读取最后一个字节(填充长度)
    uint8_t padding_len = data[data_len - 1];

    // 验证填充
    if (padding_len == 0 || padding_len > AES_BLOCK_SIZE) {
        return 0;
    }

    // 检查所有填充字节是否正确
    for (size_t i = data_len - padding_len; i < data_len; i++) {
        if (data[i] != padding_len) {
            return 0;
        }
    }

    return data_len - padding_len;
}

2. 固件加密工具

创建一个Python工具用于加密固件文件:

#!/usr/bin/env python3
"""
固件加密工具
使用AES-128 CBC模式加密固件
"""

from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from Crypto.Util.Padding import pad, unpad
import struct
import sys
import os

class FirmwareEncryptor:
    def __init__(self, key=None, iv=None):
        """初始化加密器"""
        self.key = key if key else get_random_bytes(16)  # 128位密钥
        self.iv = iv if iv else get_random_bytes(16)  # 128位IV

    def save_key(self, key_path):
        """保存密钥到文件"""
        with open(key_path, 'wb') as f:
            f.write(self.key)
            f.write(self.iv)
        print(f"Key saved to {key_path}")

    def load_key(self, key_path):
        """从文件加载密钥"""
        with open(key_path, 'rb') as f:
            self.key = f.read(16)
            self.iv = f.read(16)
        print(f"Key loaded from {key_path}")

    def encrypt_firmware(self, firmware_path, output_path):
        """加密固件"""
        # 读取固件
        with open(firmware_path, 'rb') as f:
            firmware_data = f.read()

        print(f"Original firmware size: {len(firmware_data)} bytes")

        # PKCS7填充
        padded_data = pad(firmware_data, AES.block_size)
        print(f"Padded firmware size: {len(padded_data)} bytes")

        # 创建AES加密器
        cipher = AES.new(self.key, AES.MODE_CBC, self.iv)

        # 加密
        encrypted_data = cipher.encrypt(padded_data)

        # 构建加密固件格式
        # [魔数(4字节)][原始大小(4字节)][IV(16字节)][加密数据]
        encrypted_firmware = struct.pack('<I', 0x45435246)  # "FRCE"
        encrypted_firmware += struct.pack('<I', len(firmware_data))
        encrypted_firmware += self.iv
        encrypted_firmware += encrypted_data

        # 保存加密固件
        with open(output_path, 'wb') as f:
            f.write(encrypted_firmware)

        print(f"Encrypted firmware saved to {output_path}")
        print(f"Total size: {len(encrypted_firmware)} bytes")

        # 打印密钥和IV(用于嵌入Bootloader)
        print("\nKey (hex):")
        print(' '.join(f'0x{b:02X},' for b in self.key))
        print("\nIV (hex):")
        print(' '.join(f'0x{b:02X},' for b in self.iv))

    def decrypt_firmware(self, encrypted_path, output_path):
        """解密固件(用于验证)"""
        # 读取加密固件
        with open(encrypted_path, 'rb') as f:
            encrypted_firmware = f.read()

        # 解析格式
        magic = struct.unpack('<I', encrypted_firmware[0:4])[0]
        if magic != 0x45435246:
            print("Invalid encrypted firmware format")
            return False

        original_size = struct.unpack('<I', encrypted_firmware[4:8])[0]
        iv = encrypted_firmware[8:24]
        encrypted_data = encrypted_firmware[24:]

        print(f"Original size: {original_size} bytes")
        print(f"Encrypted size: {len(encrypted_data)} bytes")

        # 创建AES解密器
        cipher = AES.new(self.key, AES.MODE_CBC, iv)

        # 解密
        decrypted_data = cipher.decrypt(encrypted_data)

        # 移除填充
        firmware_data = unpad(decrypted_data, AES.block_size)

        # 验证大小
        if len(firmware_data) != original_size:
            print(f"Size mismatch: expected {original_size}, got {len(firmware_data)}")
            return False

        # 保存解密固件
        with open(output_path, 'wb') as f:
            f.write(firmware_data)

        print(f"Decrypted firmware saved to {output_path}")
        return True

# 使用示例
if __name__ == '__main__':
    if len(sys.argv) < 2:
        print("Usage:")
        print("  Encrypt: python firmware_encryptor.py encrypt <firmware.bin> <output.enc>")
        print("  Decrypt: python firmware_encryptor.py decrypt <firmware.enc> <output.bin>")
        sys.exit(1)

    command = sys.argv[1]

    if command == 'encrypt':
        if len(sys.argv) != 4:
            print("Usage: python firmware_encryptor.py encrypt <firmware.bin> <output.enc>")
            sys.exit(1)

        firmware_path = sys.argv[2]
        output_path = sys.argv[3]

        # 创建加密器
        encryptor = FirmwareEncryptor()

        # 加密固件
        encryptor.encrypt_firmware(firmware_path, output_path)

        # 保存密钥
        key_path = output_path + '.key'
        encryptor.save_key(key_path)

    elif command == 'decrypt':
        if len(sys.argv) != 5:
            print("Usage: python firmware_encryptor.py decrypt <firmware.enc> <key_file> <output.bin>")
            sys.exit(1)

        encrypted_path = sys.argv[2]
        key_path = sys.argv[3]
        output_path = sys.argv[4]

        # 创建解密器
        encryptor = FirmwareEncryptor()
        encryptor.load_key(key_path)

        # 解密固件
        encryptor.decrypt_firmware(encrypted_path, output_path)

    else:
        print(f"Unknown command: {command}")
        sys.exit(1)

使用方法:

# 加密固件
python firmware_encryptor.py encrypt application.bin application.enc

# 解密固件(验证)
python firmware_encryptor.py decrypt application.enc application.enc.key application_dec.bin

3. Bootloader固件解密

在Bootloader中实现固件解密功能:

#include "stm32f4xx.h"
#include "mbedtls/aes.h"
#include <string.h>

// 加密固件格式
#define ENCRYPTED_MAGIC 0x45435246  // "FRCE"

// 嵌入的AES密钥(由加密工具生成)
const uint8_t aes_key[16] = {
    0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
    0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C
};

// 加密固件信息
typedef struct {
    uint32_t magic;
    uint32_t original_size;
    uint8_t iv[16];
    uint8_t *encrypted_data;
    uint32_t encrypted_size;
} EncryptedFirmware_t;

/**
 * @brief 解析加密固件
 * @param address 加密固件地址
 * @param info 输出的固件信息
 * @return 0成功,-1失败
 */
int ParseEncryptedFirmware(uint32_t address, EncryptedFirmware_t *info) {
    uint8_t *data = (uint8_t*)address;

    // 读取魔数
    memcpy(&info->magic, data, 4);
    if (info->magic != ENCRYPTED_MAGIC) {
        printf("Invalid encrypted firmware magic: 0x%08X\r\n", info->magic);
        return -1;
    }

    // 读取原始大小
    memcpy(&info->original_size, data + 4, 4);

    // 读取IV
    memcpy(info->iv, data + 8, 16);

    // 加密数据指针
    info->encrypted_data = data + 24;

    // 计算加密数据大小(向上取整到16字节)
    info->encrypted_size = ((info->original_size + 15) / 16) * 16;

    printf("Encrypted firmware info:\r\n");
    printf("  Original size: %u bytes\r\n", info->original_size);
    printf("  Encrypted size: %u bytes\r\n", info->encrypted_size);

    return 0;
}

/**
 * @brief 解密固件到RAM
 * @param encrypted_info 加密固件信息
 * @param output_buffer 输出缓冲区
 * @param buffer_size 缓冲区大小
 * @return 0成功,-1失败
 */
int DecryptFirmware(EncryptedFirmware_t *encrypted_info,
                    uint8_t *output_buffer, uint32_t buffer_size) {
    // 检查缓冲区大小
    if (buffer_size < encrypted_info->encrypted_size) {
        printf("Output buffer too small\r\n");
        return -1;
    }

    printf("Decrypting firmware...\r\n");

    // 使用AES-CBC解密
    int ret = AES_Decrypt_CBC(
        aes_key,
        encrypted_info->iv,
        encrypted_info->encrypted_data,
        encrypted_info->encrypted_size,
        output_buffer
    );

    if (ret != 0) {
        printf("Decryption failed\r\n");
        return -1;
    }

    // 移除填充
    size_t actual_size = PKCS7_Unpad(output_buffer, encrypted_info->encrypted_size);
    if (actual_size != encrypted_info->original_size) {
        printf("Padding removal failed\r\n");
        return -1;
    }

    printf("Firmware decrypted successfully\r\n");
    return 0;
}

/**
 * @brief 就地解密固件(直接在Flash中解密)
 * @param encrypted_info 加密固件信息
 * @param output_address 输出地址(Flash)
 * @return 0成功,-1失败
 * @note 需要足够的RAM作为临时缓冲区
 */
int DecryptFirmwareInPlace(EncryptedFirmware_t *encrypted_info,
                           uint32_t output_address) {
    // 分配临时缓冲区(使用RAM)
    #define DECRYPT_BUFFER_SIZE (16 * 1024)  // 16KB缓冲区
    static uint8_t decrypt_buffer[DECRYPT_BUFFER_SIZE];

    uint32_t remaining = encrypted_info->encrypted_size;
    uint32_t offset = 0;

    // 解锁Flash
    FLASH_Unlock();

    // 擦除目标区域
    printf("Erasing target flash...\r\n");
    uint32_t erase_addr = output_address;
    uint32_t end_addr = output_address + encrypted_info->original_size;

    while (erase_addr < end_addr) {
        if (!FLASH_EraseSector(erase_addr)) {
            printf("Flash erase failed\r\n");
            FLASH_Lock();
            return -1;
        }

        // 移动到下一个扇区
        uint8_t sector = FLASH_GetSector(erase_addr);
        if (sector < 4) {
            erase_addr += 0x4000;  // 16KB
        } else if (sector == 4) {
            erase_addr += 0x10000;  // 64KB
        } else {
            erase_addr += 0x20000;  // 128KB
        }
    }

    // 分块解密并写入Flash
    printf("Decrypting and writing to flash...\r\n");

    while (remaining > 0) {
        uint32_t chunk_size = (remaining > DECRYPT_BUFFER_SIZE) ? 
                              DECRYPT_BUFFER_SIZE : remaining;

        // 解密一块数据
        int ret = AES_Decrypt_CBC(
            aes_key,
            encrypted_info->iv,
            encrypted_info->encrypted_data + offset,
            chunk_size,
            decrypt_buffer
        );

        if (ret != 0) {
            printf("Decryption failed at offset %u\r\n", offset);
            FLASH_Lock();
            return -1;
        }

        // 写入Flash
        uint32_t write_size = chunk_size;
        if (offset + chunk_size > encrypted_info->original_size) {
            // 最后一块,移除填充
            write_size = encrypted_info->original_size - offset;
        }

        if (!FLASH_WriteData(output_address + offset,
                            (uint32_t*)decrypt_buffer,
                            write_size / 4)) {
            printf("Flash write failed at offset %u\r\n", offset);
            FLASH_Lock();
            return -1;
        }

        offset += chunk_size;
        remaining -= chunk_size;

        // 打印进度
        uint8_t progress = (offset * 100) / encrypted_info->encrypted_size;
        printf("Progress: %u%%\r", progress);
    }

    printf("\nDecryption complete\r\n");

    // 锁定Flash
    FLASH_Lock();

    return 0;
}

4. Flash读保护机制

STM32提供了多级Flash读保护,防止固件被读取。

读保护级别

STM32 Flash读保护分为三个级别:

级别 说明 调试接口 Flash读取 可恢复性
Level 0 无保护 可用 可读 -
Level 1 调试保护 禁用 不可读 可恢复(擦除Flash)
Level 2 永久保护 禁用 不可读 不可恢复

注意:Level 2是不可逆的,一旦设置无法恢复,请谨慎使用!

读保护配置

#include "stm32f4xx.h"

/**
 * @brief 获取当前读保护级别
 * @return 0=Level0, 1=Level1, 2=Level2
 */
uint8_t FLASH_GetReadProtectionLevel(void) {
    uint8_t rdp = (FLASH->OPTCR & FLASH_OPTCR_RDP) >> 8;

    if (rdp == 0xAA) {
        return 0;  // Level 0
    } else if (rdp == 0xCC) {
        return 2;  // Level 2
    } else {
        return 1;  // Level 1
    }
}

/**
 * @brief 设置读保护级别1
 * @note 设置后需要复位才能生效
 * @warning 这会禁用调试接口!
 */
void FLASH_SetReadProtectionLevel1(void) {
    // 检查当前级别
    uint8_t current_level = FLASH_GetReadProtectionLevel();
    if (current_level == 1) {
        printf("Already at Level 1\r\n");
        return;
    }

    if (current_level == 2) {
        printf("Cannot change from Level 2\r\n");
        return;
    }

    printf("Setting read protection to Level 1...\r\n");

    // 解锁Flash和选项字节
    FLASH_Unlock();
    FLASH_OB_Unlock();

    // 等待操作完成
    while (FLASH->SR & FLASH_SR_BSY);

    // 设置RDP为Level 1(任何非0xAA和0xCC的值)
    FLASH->OPTCR &= ~FLASH_OPTCR_RDP;
    FLASH->OPTCR |= (0x33 << 8);  // Level 1

    // 启动选项字节编程
    FLASH->OPTCR |= FLASH_OPTCR_OPTSTRT;

    // 等待完成
    while (FLASH->SR & FLASH_SR_BSY);

    // 锁定
    FLASH_OB_Lock();
    FLASH_Lock();

    printf("Read protection Level 1 set\r\n");
    printf("System will reset to apply changes\r\n");

    HAL_Delay(1000);
    NVIC_SystemReset();
}

/**
 * @brief 移除读保护(Level 1 -> Level 0)
 * @warning 这会擦除整个Flash!
 */
void FLASH_RemoveReadProtection(void) {
    uint8_t current_level = FLASH_GetReadProtectionLevel();

    if (current_level == 0) {
        printf("Already at Level 0\r\n");
        return;
    }

    if (current_level == 2) {
        printf("Cannot remove Level 2 protection\r\n");
        return;
    }

    printf("WARNING: Removing read protection will erase all Flash!\r\n");
    printf("Press any key to continue or reset to cancel...\r\n");

    // 等待用户确认
    // ...

    // 解锁
    FLASH_Unlock();
    FLASH_OB_Unlock();

    // 设置RDP为Level 0
    FLASH->OPTCR &= ~FLASH_OPTCR_RDP;
    FLASH->OPTCR |= (0xAA << 8);

    // 启动选项字节编程
    FLASH->OPTCR |= FLASH_OPTCR_OPTSTRT;

    // 等待完成
    while (FLASH->SR & FLASH_SR_BSY);

    // 锁定
    FLASH_OB_Lock();
    FLASH_Lock();

    printf("Read protection removed\r\n");
    printf("Flash has been erased\r\n");

    HAL_Delay(1000);
    NVIC_SystemReset();
}

写保护配置

除了读保护,还可以配置写保护防止特定扇区被修改:

/**
 * @brief 启用Bootloader区域写保护
 * @note 保护Sector 0-1(Bootloader区域)
 */
void FLASH_EnableBootloaderWriteProtection(void) {
    printf("Enabling Bootloader write protection...\r\n");

    // 解锁
    FLASH_Unlock();
    FLASH_OB_Unlock();

    // 读取当前写保护状态
    uint32_t wrp = FLASH->OPTCR & 0x0FFF;

    // 设置Sector 0-1写保护
    wrp &= ~(FLASH_OPTCR_nWRP_0 | FLASH_OPTCR_nWRP_1);

    // 更新选项字节
    FLASH->OPTCR = (FLASH->OPTCR & ~0x0FFF) | wrp;

    // 启动选项字节编程
    FLASH->OPTCR |= FLASH_OPTCR_OPTSTRT;

    // 等待完成
    while (FLASH->SR & FLASH_SR_BSY);

    // 锁定
    FLASH_OB_Lock();
    FLASH_Lock();

    printf("Bootloader write protection enabled\r\n");
}

/**
 * @brief 检查扇区是否被写保护
 * @param sector 扇区号(0-11)
 * @return 1=受保护,0=未保护
 */
uint8_t FLASH_IsSectorWriteProtected(uint8_t sector) {
    if (sector > 11) {
        return 0;
    }

    uint32_t wrp = FLASH->OPTCR & 0x0FFF;
    return ((wrp & (1 << sector)) == 0) ? 1 : 0;
}

5. 密钥管理

密钥的安全管理是整个加密系统的关键。

密钥存储方案

方案1:嵌入Bootloader(最简单)

// 直接在代码中定义密钥
const uint8_t aes_key[16] = {
    0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
    0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C
};

优点:实现简单,无需额外存储 缺点:密钥固定,所有设备使用相同密钥

方案2:使用设备唯一ID派生密钥

#include "mbedtls/md.h"

/**
 * @brief 从设备唯一ID派生密钥
 * @param derived_key 输出的派生密钥(16字节)
 */
void DeriveKeyFromUID(uint8_t *derived_key) {
    // 读取STM32唯一ID(96位)
    uint32_t uid[3];
    uid[0] = *(uint32_t*)0x1FFF7A10;
    uid[1] = *(uint32_t*)0x1FFF7A14;
    uid[2] = *(uint32_t*)0x1FFF7A18;

    // 主密钥(存储在Bootloader中)
    const uint8_t master_key[16] = {
        0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
        0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C
    };

    // 使用HMAC-SHA256派生密钥
    mbedtls_md_context_t md_ctx;
    const mbedtls_md_info_t *md_info;

    mbedtls_md_init(&md_ctx);
    md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);

    mbedtls_md_setup(&md_ctx, md_info, 1);  // 1 = HMAC
    mbedtls_md_hmac_starts(&md_ctx, master_key, 16);
    mbedtls_md_hmac_update(&md_ctx, (uint8_t*)uid, 12);

    uint8_t hash[32];
    mbedtls_md_hmac_finish(&md_ctx, hash);
    mbedtls_md_free(&md_ctx);

    // 取前16字节作为派生密钥
    memcpy(derived_key, hash, 16);

    printf("Derived key from UID:\r\n");
    for (int i = 0; i < 16; i++) {
        printf("%02X ", derived_key[i]);
    }
    printf("\r\n");
}

优点:每个设备有唯一密钥 缺点:需要为每个设备生成专用固件

方案3:使用OTP区域存储密钥

// OTP区域地址(STM32F4)
#define OTP_BASE_ADDRESS 0x1FFF7800
#define OTP_KEY_OFFSET 0x00

/**
 * @brief 从OTP读取密钥
 * @param key 输出的密钥(16字节)
 * @return 0成功,-1失败
 */
int ReadKeyFromOTP(uint8_t *key) {
    uint32_t *otp_addr = (uint32_t*)(OTP_BASE_ADDRESS + OTP_KEY_OFFSET);

    // 读取4个32位字(16字节)
    for (int i = 0; i < 4; i++) {
        uint32_t word = otp_addr[i];
        key[i * 4 + 0] = (word >> 0) & 0xFF;
        key[i * 4 + 1] = (word >> 8) & 0xFF;
        key[i * 4 + 2] = (word >> 16) & 0xFF;
        key[i * 4 + 3] = (word >> 24) & 0xFF;
    }

    // 检查密钥是否为空(全0xFF表示未编程)
    uint8_t is_empty = 1;
    for (int i = 0; i < 16; i++) {
        if (key[i] != 0xFF) {
            is_empty = 0;
            break;
        }
    }

    if (is_empty) {
        printf("OTP key is empty\r\n");
        return -1;
    }

    printf("Key read from OTP\r\n");
    return 0;
}

/**
 * @brief 将密钥写入OTP
 * @param key 密钥(16字节)
 * @warning OTP只能写入一次,不可修改!
 */
void WriteKeyToOTP(const uint8_t *key) {
    printf("WARNING: Writing to OTP is irreversible!\r\n");
    printf("Press any key to continue or reset to cancel...\r\n");

    // 等待用户确认
    // ...

    // 解锁Flash
    FLASH_Unlock();

    uint32_t *otp_addr = (uint32_t*)(OTP_BASE_ADDRESS + OTP_KEY_OFFSET);

    // 写入4个32位字
    for (int i = 0; i < 4; i++) {
        uint32_t word = (key[i * 4 + 0] << 0) |
                       (key[i * 4 + 1] << 8) |
                       (key[i * 4 + 2] << 16) |
                       (key[i * 4 + 3] << 24);

        // 编程OTP
        *(__IO uint32_t*)(otp_addr + i) = word;

        // 等待完成
        while (FLASH->SR & FLASH_SR_BSY);
    }

    // 锁定Flash
    FLASH_Lock();

    printf("Key written to OTP\r\n");
}

优点:密钥安全存储,不易被读取 缺点:只能写入一次,无法更改

密钥轮换

为了提高安全性,可以实现密钥轮换机制:

// 密钥版本管理
typedef struct {
    uint8_t version;
    uint8_t key[16];
    uint32_t valid_from;  // 生效时间戳
    uint32_t valid_until;  // 失效时间戳
} KeyInfo_t;

// 存储多个密钥版本
#define MAX_KEY_VERSIONS 4
static KeyInfo_t key_store[MAX_KEY_VERSIONS];

/**
 * @brief 获取当前有效的密钥
 * @param current_time 当前时间戳
 * @return 密钥指针,NULL表示无有效密钥
 */
const uint8_t* GetCurrentKey(uint32_t current_time) {
    for (int i = 0; i < MAX_KEY_VERSIONS; i++) {
        if (key_store[i].valid_from <= current_time &&
            current_time < key_store[i].valid_until) {
            printf("Using key version %u\r\n", key_store[i].version);
            return key_store[i].key;
        }
    }

    printf("No valid key found\r\n");
    return NULL;
}

/**
 * @brief 添加新密钥版本
 * @param version 密钥版本号
 * @param key 密钥数据
 * @param valid_from 生效时间
 * @param valid_until 失效时间
 */
void AddKeyVersion(uint8_t version, const uint8_t *key,
                   uint32_t valid_from, uint32_t valid_until) {
    // 找到空闲槽位
    for (int i = 0; i < MAX_KEY_VERSIONS; i++) {
        if (key_store[i].version == 0) {
            key_store[i].version = version;
            memcpy(key_store[i].key, key, 16);
            key_store[i].valid_from = valid_from;
            key_store[i].valid_until = valid_until;

            printf("Key version %u added\r\n", version);
            return;
        }
    }

    printf("Key store full\r\n");
}

6. 防回滚机制

防回滚机制防止攻击者将固件降级到存在漏洞的旧版本。

版本号管理

// 固件版本信息
typedef struct {
    uint32_t magic;          // 魔数:0x56455253 ("VERS")
    uint16_t major;          // 主版本号
    uint16_t minor;          // 次版本号
    uint32_t build;          // 编译号
    uint32_t timestamp;      // 编译时间戳
    uint32_t security_version;  // 安全版本号(单调递增)
} FirmwareVersion_t;

// 最低安全版本存储地址
#define MIN_SECURITY_VERSION_ADDR 0x080FC000

/**
 * @brief 读取最低安全版本
 * @return 最低安全版本号
 */
uint32_t ReadMinSecurityVersion(void) {
    uint32_t min_version = *(__IO uint32_t*)MIN_SECURITY_VERSION_ADDR;

    // 如果是0xFFFFFFFF(未初始化),返回0
    if (min_version == 0xFFFFFFFF) {
        return 0;
    }

    return min_version;
}

/**
 * @brief 更新最低安全版本
 * @param new_version 新的最低版本
 * @return 0成功,-1失败
 */
int UpdateMinSecurityVersion(uint32_t new_version) {
    uint32_t current_min = ReadMinSecurityVersion();

    // 只能递增,不能降低
    if (new_version <= current_min) {
        printf("Cannot downgrade security version\r\n");
        return -1;
    }

    printf("Updating minimum security version: %u -> %u\r\n",
           current_min, new_version);

    // 解锁Flash
    FLASH_Unlock();

    // 擦除扇区
    if (!FLASH_EraseSector(MIN_SECURITY_VERSION_ADDR)) {
        FLASH_Lock();
        return -1;
    }

    // 写入新版本
    if (!FLASH_ProgramWord(MIN_SECURITY_VERSION_ADDR, new_version)) {
        FLASH_Lock();
        return -1;
    }

    // 锁定Flash
    FLASH_Lock();

    printf("Security version updated successfully\r\n");
    return 0;
}

/**
 * @brief 验证固件版本
 * @param firmware_version 固件版本信息
 * @return 0允许,-1拒绝
 */
int VerifyFirmwareVersion(FirmwareVersion_t *firmware_version) {
    // 检查魔数
    if (firmware_version->magic != 0x56455253) {
        printf("Invalid version magic\r\n");
        return -1;
    }

    // 读取最低安全版本
    uint32_t min_security_version = ReadMinSecurityVersion();

    printf("Firmware version: %u.%u.%u (security: %u)\r\n",
           firmware_version->major,
           firmware_version->minor,
           firmware_version->build,
           firmware_version->security_version);

    printf("Minimum security version: %u\r\n", min_security_version);

    // 检查安全版本
    if (firmware_version->security_version < min_security_version) {
        printf("Firmware security version too old\r\n");
        return -1;
    }

    printf("Firmware version check passed\r\n");
    return 0;
}

单调计数器

使用OTP区域实现真正的单调计数器:

// OTP单调计数器地址
#define OTP_COUNTER_BASE 0x1FFF7820
#define OTP_COUNTER_SIZE 32  // 32个字节,每个字节一个计数

/**
 * @brief 读取单调计数器
 * @return 当前计数值
 */
uint32_t ReadMonotonicCounter(void) {
    uint8_t *counter_addr = (uint8_t*)OTP_COUNTER_BASE;
    uint32_t count = 0;

    // 计算已编程的字节数
    for (int i = 0; i < OTP_COUNTER_SIZE; i++) {
        if (counter_addr[i] != 0xFF) {
            count++;
        } else {
            break;
        }
    }

    return count;
}

/**
 * @brief 递增单调计数器
 * @return 0成功,-1失败(计数器已满)
 */
int IncrementMonotonicCounter(void) {
    uint32_t current = ReadMonotonicCounter();

    if (current >= OTP_COUNTER_SIZE) {
        printf("Monotonic counter full\r\n");
        return -1;
    }

    // 解锁Flash
    FLASH_Unlock();

    // 编程下一个字节
    uint8_t *counter_addr = (uint8_t*)(OTP_COUNTER_BASE + current);
    *counter_addr = 0x00;  // 将0xFF变为0x00

    // 等待完成
    while (FLASH->SR & FLASH_SR_BSY);

    // 锁定Flash
    FLASH_Lock();

    printf("Monotonic counter incremented to %u\r\n", current + 1);
    return 0;
}

/**
 * @brief 验证固件的单调计数器
 * @param firmware_counter 固件中的计数器值
 * @return 0验证成功,-1验证失败
 */
int VerifyMonotonicCounter(uint32_t firmware_counter) {
    uint32_t device_counter = ReadMonotonicCounter();

    printf("Firmware counter: %u\r\n", firmware_counter);
    printf("Device counter: %u\r\n", device_counter);

    if (firmware_counter < device_counter) {
        printf("Firmware counter too old (rollback detected)\r\n");
        return -1;
    }

    // 如果固件计数器更新,递增设备计数器
    if (firmware_counter > device_counter) {
        printf("Updating device counter...\r\n");

        // 递增到固件计数器值
        while (ReadMonotonicCounter() < firmware_counter) {
            if (IncrementMonotonicCounter() != 0) {
                printf("Failed to update counter\r\n");
                return -1;
            }
        }
    }

    printf("Monotonic counter verification passed\r\n");
    return 0;
}

7. 完整的加密启动流程

将所有组件整合到完整的加密启动系统中:

#include "stm32f4xx.h"
#include "firmware_encryption.h"
#include "flash_protection.h"
#include "version_control.h"

// 加密固件地址
#define ENCRYPTED_FIRMWARE_ADDR 0x08010000
// 解密后的应用程序地址
#define DECRYPTED_APP_ADDR 0x08020000

/**
 * @brief 加密固件启动主流程
 * @return 0成功,-1失败
 */
int EncryptedBoot_Main(void) {
    EncryptedFirmware_t encrypted_info;
    FirmwareVersion_t firmware_version;
    int ret;

    printf("\r\n");
    printf("========================================\r\n");
    printf("  Encrypted Firmware Boot\r\n");
    printf("========================================\r\n");

    // 1. 检查Flash读保护状态
    uint8_t rdp_level = FLASH_GetReadProtectionLevel();
    printf("Read protection level: %u\r\n", rdp_level);

    if (rdp_level == 0) {
        printf("WARNING: Flash is not protected!\r\n");
        printf("Consider enabling read protection for production\r\n");
    }

    // 2. 解析加密固件
    printf("\r\nParsing encrypted firmware...\r\n");
    ret = ParseEncryptedFirmware(ENCRYPTED_FIRMWARE_ADDR, &encrypted_info);
    if (ret != 0) {
        printf("Failed to parse encrypted firmware\r\n");
        return -1;
    }

    // 3. 提取固件版本信息(假设在固件开头)
    memcpy(&firmware_version, encrypted_info.encrypted_data, 
           sizeof(FirmwareVersion_t));

    // 4. 验证固件版本
    printf("\r\nVerifying firmware version...\r\n");
    ret = VerifyFirmwareVersion(&firmware_version);
    if (ret != 0) {
        printf("Firmware version verification failed\r\n");
        return -1;
    }

    // 5. 验证单调计数器
    printf("\r\nVerifying monotonic counter...\r\n");
    ret = VerifyMonotonicCounter(firmware_version.security_version);
    if (ret != 0) {
        printf("Monotonic counter verification failed\r\n");
        return -1;
    }

    // 6. 解密固件
    printf("\r\nDecrypting firmware...\r\n");
    ret = DecryptFirmwareInPlace(&encrypted_info, DECRYPTED_APP_ADDR);
    if (ret != 0) {
        printf("Firmware decryption failed\r\n");
        return -1;
    }

    // 7. 验证解密后的固件(可选:CRC或签名)
    printf("\r\nVerifying decrypted firmware...\r\n");
    // ... CRC或签名验证代码 ...

    // 8. 更新最低安全版本
    if (firmware_version.security_version > ReadMinSecurityVersion()) {
        printf("\r\nUpdating minimum security version...\r\n");
        UpdateMinSecurityVersion(firmware_version.security_version);
    }

    printf("\r\n========================================\r\n");
    printf("  All security checks passed!\r\n");
    printf("  Jumping to application...\r\n");
    printf("========================================\r\n");

    return 0;
}

/**
 * @brief Bootloader主函数
 */
int main(void) {
    // 系统初始化
    SystemInit();
    HAL_Init();
    SystemClock_Config();

    // 初始化UART
    UART_Init();

    // 初始化LED
    LED_Init();

    printf("\r\n");
    printf("========================================\r\n");
    printf("  Secure Bootloader v1.0\r\n");
    printf("  Build: %s %s\r\n", __DATE__, __TIME__);
    printf("========================================\r\n");

    // LED快速闪烁表示Bootloader运行
    for (int i = 0; i < 3; i++) {
        LED_On();
        HAL_Delay(100);
        LED_Off();
        HAL_Delay(100);
    }

    // 执行加密固件启动
    int ret = EncryptedBoot_Main();

    if (ret == 0) {
        // 启动成功,LED常亮2秒
        LED_On();
        HAL_Delay(2000);
        LED_Off();

        // 跳转到解密后的应用程序
        JumpToApplication(DECRYPTED_APP_ADDR);
    } else {
        // 启动失败,LED快速闪烁表示错误
        printf("\r\nBoot failed! System halted.\r\n");

        while (1) {
            LED_Toggle();
            HAL_Delay(200);
        }
    }

    // 永远不会执行到这里
    while (1);
}

实践示例

示例1:完整的固件加密和部署流程

步骤1:编译应用程序

cd application
make clean
make

步骤2:加密固件

# 使用Python工具加密固件
python firmware_encryptor.py encrypt application.bin application.enc

# 输出:
# Original firmware size: 32768 bytes
# Padded firmware size: 32768 bytes
# Encrypted firmware saved to application.enc
# Total size: 32792 bytes
#
# Key (hex):
# 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
# 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C,
#
# IV (hex):
# 0x91, 0x28, 0x13, 0x40, 0x3A, 0x8C, 0x5F, 0x2D,
# 0xE7, 0xB1, 0x49, 0x9C, 0x73, 0x6A, 0x8E, 0x2F,

步骤3:将密钥嵌入Bootloader

// 在Bootloader代码中更新密钥
const uint8_t aes_key[16] = {
    0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
    0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C
};

步骤4:编译并烧录Bootloader

cd bootloader
make clean
make
st-flash write bootloader.bin 0x08000000

步骤5:烧录加密固件

st-flash write application.enc 0x08010000

步骤6:启用Flash读保护(生产环境)

// 在Bootloader中调用
FLASH_SetReadProtectionLevel1();

步骤7:测试启动

设备上电后,Bootloader会: 1. 解析加密固件 2. 验证版本号 3. 验证单调计数器 4. 解密固件到RAM或另一个Flash区域 5. 验证解密后的固件 6. 跳转到应用程序

示例2:使用硬件AES加速

STM32F4部分型号支持硬件AES加速,可以显著提高加密解密速度:

#include "stm32f4xx_hal.h"

// 硬件AES句柄
CRYP_HandleTypeDef hcryp;

/**
 * @brief 初始化硬件AES
 * @param key 密钥(16字节)
 * @param iv 初始化向量(16字节)
 * @return 0成功,-1失败
 */
int HW_AES_Init(const uint8_t *key, const uint8_t *iv) {
    // 使能AES时钟
    __HAL_RCC_CRYP_CLK_ENABLE();

    // 配置AES
    hcryp.Instance = CRYP;
    hcryp.Init.DataType = CRYP_DATATYPE_8B;
    hcryp.Init.KeySize = CRYP_KEYSIZE_128B;
    hcryp.Init.pKey = (uint32_t*)key;
    hcryp.Init.pInitVect = (uint32_t*)iv;
    hcryp.Init.Algorithm = CRYP_AES_CBC;
    hcryp.Init.DataWidthUnit = CRYP_DATAWIDTHUNIT_BYTE;

    if (HAL_CRYP_Init(&hcryp) != HAL_OK) {
        return -1;
    }

    return 0;
}

/**
 * @brief 硬件AES解密
 * @param input 输入数据
 * @param input_len 输入长度(必须是16的倍数)
 * @param output 输出数据
 * @return 0成功,-1失败
 */
int HW_AES_Decrypt(const uint8_t *input, uint32_t input_len, uint8_t *output) {
    if (input_len % 16 != 0) {
        return -1;
    }

    // 执行解密
    if (HAL_CRYP_Decrypt(&hcryp, (uint32_t*)input, input_len,
                         (uint32_t*)output, 5000) != HAL_OK) {
        return -1;
    }

    return 0;
}

/**
 * @brief 使用硬件AES解密固件
 * @param encrypted_info 加密固件信息
 * @param output_address 输出地址
 * @return 0成功,-1失败
 */
int DecryptFirmware_HW(EncryptedFirmware_t *encrypted_info,
                       uint32_t output_address) {
    // 初始化硬件AES
    if (HW_AES_Init(aes_key, encrypted_info->iv) != 0) {
        printf("Hardware AES init failed\r\n");
        return -1;
    }

    // 分配临时缓冲区
    #define HW_DECRYPT_BUFFER_SIZE (16 * 1024)
    static uint8_t decrypt_buffer[HW_DECRYPT_BUFFER_SIZE];

    uint32_t remaining = encrypted_info->encrypted_size;
    uint32_t offset = 0;

    // 解锁Flash
    FLASH_Unlock();

    // 擦除目标区域
    // ... 擦除代码 ...

    // 分块解密
    while (remaining > 0) {
        uint32_t chunk_size = (remaining > HW_DECRYPT_BUFFER_SIZE) ?
                              HW_DECRYPT_BUFFER_SIZE : remaining;

        // 硬件解密
        if (HW_AES_Decrypt(encrypted_info->encrypted_data + offset,
                          chunk_size, decrypt_buffer) != 0) {
            printf("Hardware decryption failed\r\n");
            FLASH_Lock();
            return -1;
        }

        // 写入Flash
        uint32_t write_size = chunk_size;
        if (offset + chunk_size > encrypted_info->original_size) {
            write_size = encrypted_info->original_size - offset;
        }

        if (!FLASH_WriteData(output_address + offset,
                            (uint32_t*)decrypt_buffer,
                            write_size / 4)) {
            FLASH_Lock();
            return -1;
        }

        offset += chunk_size;
        remaining -= chunk_size;

        printf("Progress: %u%%\r", (offset * 100) / encrypted_info->encrypted_size);
    }

    printf("\nHardware decryption complete\r\n");

    FLASH_Lock();
    return 0;
}

性能对比:

方法 解密速度 CPU占用 功耗
软件AES ~1 MB/s 100% 高
硬件AES ~10 MB/s <10% 低

示例3:混合加密方案

对于大型固件,可以使用混合加密方案:使用RSA加密AES密钥,使用AES加密固件:

/**
 * @brief 混合加密固件格式
 * [魔数(4字节)]
 * [原始大小(4字节)]
 * [加密的AES密钥(256字节,RSA-2048)]
 * [IV(16字节)]
 * [加密的固件数据]
 */

/**
 * @brief 解密AES密钥
 * @param encrypted_key 加密的AES密钥(256字节)
 * @param decrypted_key 输出的解密密钥(16字节)
 * @return 0成功,-1失败
 */
int DecryptAESKey(const uint8_t *encrypted_key, uint8_t *decrypted_key) {
    mbedtls_rsa_context rsa;
    int ret;

    // 初始化RSA上下文
    mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V15, 0);

    // 设置RSA私钥(存储在安全区域)
    // ... 设置私钥代码 ...

    // 解密AES密钥
    size_t olen;
    ret = mbedtls_rsa_pkcs1_decrypt(&rsa, NULL, NULL,
                                    MBEDTLS_RSA_PRIVATE,
                                    &olen, encrypted_key,
                                    decrypted_key, 16);

    mbedtls_rsa_free(&rsa);

    if (ret != 0 || olen != 16) {
        printf("Failed to decrypt AES key\r\n");
        return -1;
    }

    printf("AES key decrypted successfully\r\n");
    return 0;
}

/**
 * @brief 解密混合加密固件
 * @param firmware_address 固件地址
 * @param output_address 输出地址
 * @return 0成功,-1失败
 */
int DecryptHybridFirmware(uint32_t firmware_address, uint32_t output_address) {
    uint8_t *data = (uint8_t*)firmware_address;
    uint8_t aes_key[16];
    uint8_t iv[16];

    // 解析格式
    uint32_t magic = *(uint32_t*)data;
    if (magic != 0x48594252) {  // "HYBR"
        printf("Invalid hybrid firmware format\r\n");
        return -1;
    }

    uint32_t original_size = *(uint32_t*)(data + 4);
    uint8_t *encrypted_key = data + 8;
    memcpy(iv, data + 264, 16);
    uint8_t *encrypted_data = data + 280;

    // 1. 解密AES密钥
    printf("Decrypting AES key...\r\n");
    if (DecryptAESKey(encrypted_key, aes_key) != 0) {
        return -1;
    }

    // 2. 使用解密的AES密钥解密固件
    printf("Decrypting firmware...\r\n");
    EncryptedFirmware_t encrypted_info;
    encrypted_info.original_size = original_size;
    encrypted_info.encrypted_size = ((original_size + 15) / 16) * 16;
    memcpy(encrypted_info.iv, iv, 16);
    encrypted_info.encrypted_data = encrypted_data;

    // 使用解密的密钥
    const uint8_t *old_key = aes_key;  // 临时保存
    // ... 解密固件 ...

    return 0;
}

优点: - AES密钥每次可以不同(随机生成) - 即使AES密钥泄露,只影响单个固件 - 可以使用不同的RSA密钥对管理不同产品线

缺点: - 需要在设备中存储RSA私钥 - 解密过程更复杂 - 需要更多的存储空间

验证与测试

测试加密解密功能

/**
 * @brief 测试AES加密解密
 */
void Test_AES_Encryption(void) {
    printf("\r\n=== AES Encryption Test ===\r\n");

    // 测试数据
    const uint8_t key[16] = {
        0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
        0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C
    };

    const uint8_t iv[16] = {
        0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
        0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
    };

    const char *plaintext = "Hello, Encrypted World! This is a test message.";
    uint8_t encrypted[64];
    uint8_t decrypted[64];

    // 填充
    size_t padded_len = PKCS7_Pad((uint8_t*)plaintext, strlen(plaintext), 64);
    printf("Original length: %u\r\n", strlen(plaintext));
    printf("Padded length: %u\r\n", padded_len);

    // 加密
    if (AES_Encrypt_CBC(key, iv, (uint8_t*)plaintext, padded_len, encrypted) == 0) {
        printf("Encryption successful\r\n");

        // 打印密文
        printf("Encrypted data: ");
        for (size_t i = 0; i < padded_len; i++) {
            printf("%02X ", encrypted[i]);
        }
        printf("\r\n");
    } else {
        printf("Encryption failed\r\n");
        return;
    }

    // 解密
    if (AES_Decrypt_CBC(key, iv, encrypted, padded_len, decrypted) == 0) {
        printf("Decryption successful\r\n");

        // 移除填充
        size_t original_len = PKCS7_Unpad(decrypted, padded_len);
        decrypted[original_len] = '\0';

        // 打印明文
        printf("Decrypted data: %s\r\n", decrypted);

        // 验证
        if (memcmp(plaintext, decrypted, strlen(plaintext)) == 0) {
            printf("✓ Test PASSED\r\n");
        } else {
            printf("✗ Test FAILED\r\n");
        }
    } else {
        printf("Decryption failed\r\n");
    }
}

/**
 * @brief 测试Flash保护
 */
void Test_FlashProtection(void) {
    printf("\r\n=== Flash Protection Test ===\r\n");

    // 检查读保护级别
    uint8_t rdp_level = FLASH_GetReadProtectionLevel();
    printf("Current RDP level: %u\r\n", rdp_level);

    // 检查写保护
    for (uint8_t sector = 0; sector < 8; sector++) {
        uint8_t protected = FLASH_IsSectorWriteProtected(sector);
        printf("Sector %u: %s\r\n", sector,
               protected ? "Write Protected" : "Not Protected");
    }
}

/**
 * @brief 测试版本控制
 */
void Test_VersionControl(void) {
    printf("\r\n=== Version Control Test ===\r\n");

    // 读取当前最低版本
    uint32_t min_version = ReadMinSecurityVersion();
    printf("Current minimum security version: %u\r\n", min_version);

    // 测试版本验证
    FirmwareVersion_t test_version = {
        .magic = 0x56455253,
        .major = 1,
        .minor = 2,
        .build = 345,
        .timestamp = 1234567890,
        .security_version = min_version + 1
    };

    if (VerifyFirmwareVersion(&test_version) == 0) {
        printf("✓ Version verification PASSED\r\n");
    } else {
        printf("✗ Version verification FAILED\r\n");
    }

    // 测试单调计数器
    uint32_t counter = ReadMonotonicCounter();
    printf("Monotonic counter: %u\r\n", counter);
}

性能测试

/**
 * @brief 测试加密解密性能
 */
void Test_Performance(void) {
    printf("\r\n=== Performance Test ===\r\n");

    const uint8_t key[16] = {
        0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
        0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C
    };

    const uint8_t iv[16] = {0};

    // 测试不同大小的数据
    uint32_t test_sizes[] = {1024, 4096, 16384, 65536};

    for (int i = 0; i < 4; i++) {
        uint32_t size = test_sizes[i];
        uint8_t *data = malloc(size);
        uint8_t *encrypted = malloc(size);
        uint8_t *decrypted = malloc(size);

        if (!data || !encrypted || !decrypted) {
            printf("Memory allocation failed\r\n");
            continue;
        }

        // 填充测试数据
        for (uint32_t j = 0; j < size; j++) {
            data[j] = j & 0xFF;
        }

        // 测试加密
        uint32_t start_time = HAL_GetTick();
        AES_Encrypt_CBC(key, iv, data, size, encrypted);
        uint32_t encrypt_time = HAL_GetTick() - start_time;

        // 测试解密
        start_time = HAL_GetTick();
        AES_Decrypt_CBC(key, iv, encrypted, size, decrypted);
        uint32_t decrypt_time = HAL_GetTick() - start_time;

        // 计算速度
        float encrypt_speed = (float)size / encrypt_time;  // KB/s
        float decrypt_speed = (float)size / decrypt_time;  // KB/s

        printf("Size: %u bytes\r\n", size);
        printf("  Encrypt: %u ms (%.2f KB/s)\r\n", encrypt_time, encrypt_speed);
        printf("  Decrypt: %u ms (%.2f KB/s)\r\n", decrypt_time, decrypt_speed);

        // 验证
        if (memcmp(data, decrypted, size) == 0) {
            printf("  ✓ Verification PASSED\r\n");
        } else {
            printf("  ✗ Verification FAILED\r\n");
        }

        free(data);
        free(encrypted);
        free(decrypted);
    }
}

故障排除

常见问题

问题1:解密后的固件无法运行

可能原因: - 密钥不匹配 - IV不正确 - 填充处理错误 - Flash写入错误

解决方法:

// 添加详细的调试输出
printf("Encrypted data (first 32 bytes):\r\n");
for (int i = 0; i < 32; i++) {
    printf("%02X ", encrypted_data[i]);
}
printf("\r\n");

printf("Decrypted data (first 32 bytes):\r\n");
for (int i = 0; i < 32; i++) {
    printf("%02X ", decrypted_data[i]);
}
printf("\r\n");

// 验证解密后的栈指针
uint32_t sp = *(uint32_t*)decrypted_address;
printf("Stack pointer: 0x%08X\r\n", sp);
if ((sp & 0x2FFE0000) != 0x20000000) {
    printf("Invalid stack pointer!\r\n");
}

问题2:Flash读保护后无法调试

这是正常现象。解决方法: - 开发阶段不启用读保护 - 使用串口输出调试信息 - 预留调试命令接口 - 使用LED指示状态

问题3:单调计数器用完

OTP区域有限,计数器会用完。解决方法:

// 使用更大的计数器空间
#define OTP_COUNTER_SIZE 128  // 增加到128字节

// 或使用Flash模拟
#define COUNTER_FLASH_ADDR 0x080FC000
// 每次擦除扇区,重新写入递增的值

问题4:加密固件太大

加密会增加文件大小(填充)。解决方法: - 优化固件大小 - 使用压缩(先压缩后加密) - 分段加密 - 使用流密码模式(CTR)

总结

本教程介绍了固件加密与防护的完整技术体系:

  1. 加密算法:AES-128/256 CBC模式,平衡安全性和性能
  2. Flash保护:读保护和写保护,防止固件被读取和篡改
  3. 防回滚:版本号管理和单调计数器,防止降级攻击
  4. 密钥管理:多种密钥存储方案,确保密钥安全
  5. 完整流程:从固件加密到安全启动的完整实现

通过这些技术的组合使用,可以构建一个安全可靠的固件防护系统,有效保护知识产权和防止恶意攻击。

延伸阅读

下一步

学习完本教程后,建议继续学习:

  1. 双区升级技术,实现更可靠的固件更新
  2. OTA升级系统,实现远程固件管理
  3. 安全元件的使用,进一步提高系统安全性
  4. 密码学高级主题,如椭圆曲线加密、同态加密等