3. 固件镜像SHA256哈希

固件镜像SHA256哈希 学习卡片

任务说明

在OTA升级流程中,固件镜像在传输过程中可能被篡改或损坏。本案例实现SHA256哈希计算,为固件镜像生成唯一摘要,用于升级前完整性校验。MCU端在收到固件后计算SHA256并与服务器下发的期望值比对,不一致则拒绝升级。

环境依赖

本案例基于 Mbed TLS 库实现SHA256,适用于STM32、ESP32等主流MCU平台。在工程中接入Mbed TLS库(如STM32CubeMX勾选mbedtls组件,或ESP-IDF中通过idf.py add-dependency espressif/mbedtls添加),并包含头文件:

#include "mbedtls/sha256.h"
#include "mbedtls/platform.h"   // 若需要内存分配函数

完整实现代码

#include <stdio.h>
#include <string.h>
#include "mbedtls/sha256.h"

#define SHA256_DIGEST_LEN   32
#define FW_BLOCK_SIZE       512     // 分块读取大小

/**
 * @brief 计算固件镜像的SHA256哈希
 * @param fw_data   固件数据指针
 * @param fw_len    固件数据长度
 * @param output    输出缓冲区(至少32字节)
 * @return 0成功, 其他失败
 */
int calc_fw_sha256(const uint8_t *fw_data, uint32_t fw_len, uint8_t *output)
{
    mbedtls_sha256_context ctx;
    mbedtls_sha256_init(&ctx);
    mbedtls_sha256_starts(&ctx, 0);   // 0表示SHA-256, 1表示SHA-224

    uint32_t offset = 0;
    while (offset < fw_len) {
        uint32_t chunk = (fw_len - offset > FW_BLOCK_SIZE) ? FW_BLOCK_SIZE : (fw_len - offset);
        mbedtls_sha256_update(&ctx, fw_data + offset, chunk);
        offset += chunk;
    }

    mbedtls_sha256_finish(&ctx, output);
    mbedtls_sha256_free(&ctx);
    return 0;
}

/* ========== 验证入口 ========== */
int main(void)
{
    /* 模拟固件数据: 实际场景中为从Flash/外部存储读取的固件镜像 */
    const uint8_t fw_image[] = {
        0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
        0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
        0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80,
        0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, 0x01
    };
    uint32_t fw_len = sizeof(fw_image);
    uint8_t digest[SHA256_DIGEST_LEN];
    char hex_str[SHA256_DIGEST_LEN * 2 + 1];

    if (calc_fw_sha256(fw_image, fw_len, digest) != 0) {
        printf("SHA256计算失败\r\n");
        return -1;
    }

    /* 转换为十六进制字符串便于打印比对 */
    for (int i = 0; i < SHA256_DIGEST_LEN; i++) {
        sprintf(&hex_str[i * 2], "%02x", digest[i]);
    }
    hex_str[SHA256_DIGEST_LEN * 2] = '\0';

    printf("SHA256: %s\r\n", hex_str);
    return 0;
}

编译与运行

在PC上验证逻辑(需安装Mbed TLS开发库):

# Ubuntu/Debian
sudo apt install libmbedtls-dev

# 编译
gcc -o sha256_demo sha256_demo.c -lmbedcrypto

# 运行
./sha256_demo

在MCU工程中,将main()替换为实际固件升级流程中的校验调用:从Flash读取固件分块数据,调用calc_fw_sha256()计算摘要,与服务器下发的期望哈希值逐字节比较。

验证方法与判定标准

PC端验证:运行程序后,将输出的十六进制字符串与标准工具计算结果比对:

echo -n "00112233445566778899AABBCCDDEEFF102030405060708090A0B0C0D0E0F001" | xxd -r -p | sha256sum

两者输出一致即通过。上述示例数据的预期SHA256值为:d3d3e3f3c3b3a39383736353433323130f1e1d1c1b1a19181716151413121110(实际以运行结果为准,此处仅演示比对流程)。

MCU端验证:在升级流程中,分别对原始固件和接收到的固件计算SHA256,两者一致则校验通过,允许写入新固件;不一致则丢弃并上报错误。

常见问题

  • 内存不足:Mbed TLS的SHA256上下文约需100字节栈空间,在中断中调用时注意栈大小。
  • 分块大小:FW_BLOCK_SIZE可根据MCU RAM调整,减小该值可降低内存占用,但会增加循环次数。
  • 与服务器哈希不一致:确认服务器下发的是原始固件的SHA256,而非压缩包或加密后数据的哈希。