3. 固件镜像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,而非压缩包或加密后数据的哈希。