【STM32】知识点介绍三:哈希算法详解
2026/5/27 17:15:00 网站建设 项目流程

文章目录

  • 一、简介
    • 1.哈希算法详解
    • 2.工作原理
  • 二、在可信固件更新中的应用
    • 1.固件完整性验证
    • 2.安全启动链
    • 3.防篡改机制
    • 4.恢复机制
    • 5.与其他哈希算法的比较
    • 6.SHA-256 在嵌入式系统中的优化
  • 三、SHA-256 的C语言实现
    • 1.sha256.h
    • 2.sha256.c
    • 3.嵌入式系统上的应用示例
    • 4.使用硬件加速器
  • 四、总结

一、简介

1.哈希算法详解

SHA-256 是密码学哈希函数家族 SHA-2 (Secure Hash Algorithm 2) 中的一员,由美国国家安全局 (NSA) 设计并由美国国家标准与技术研究院 (NIST) 在 2001 年发布。它是当今最广泛使用的哈希算法之一,尤其在数据完整性验证、数字签名和密码存储等安全应用中。

基本特性:

  1. 固定输出长度:无论输入数据大小如何,SHA-256 始终生成 256 位(32 字节)的哈希值
  2. 单向性:从哈希值反推原始数据在计算上是不可行的
  3. 抗碰撞性:找到两个产生相同哈希值的不同输入极其困难
  4. 雪崩效应:输入的微小变化会导致输出哈希值的显著变化
  5. 确定性:相同的输入总是产生相同的哈希值

2.工作原理

SHA-256 算法的工作原理可以分为以下几个主要步骤:

(1)预处理

1>填充消息
①将输入消息追加一个 ‘1’ 位
②再追加 K 个 ‘0’ 位,使得(消息长度 + 1 + K + 64)是 512 的倍数
③最后添加 64 位表示原始消息长度

2>解析消息
①将填充后的消息分割成多个 512 位(64 字节)的块
②每个块进一步分为 16 个 32 位字

(2)初始化哈希值
使用前 8 个质数(2 到 19)的平方根小数部分的前 32 位作为初始哈希值

h0 = 0x6a09e667
h1 = 0xbb67ae85
h2 = 0x3c6ef372
h3 = 0xa54ff53a
h4 = 0x510e527f
h5 = 0x9b05688c
h6 = 0x1f83d9ab
h7 = 0x5be0cd19

(3)压缩函数主循环
对于每个 512 位消息块,SHA-256 执行以下操作

1>准备消息调度
①从当前块创建 16 个初始字 W[0] 到 W[15]
②扩展这些字为 W[16] 到 W[63],每个新字是前面几个字的混合

公式: W[t]=σ₁(W[t-2])+W[t-7]+σ₀(W[t-15])+W[t-16]其中 σ₀ 和 σ₁ 是位运算函数: σ₀(x)=ROTR⁷(x)⊕ ROTR¹⁸(x)⊕ SHR³(x)σ₁(x)=ROTR¹⁷(x)⊕ ROTR¹⁹(x)⊕ SHR¹⁰(x)

2>初始化工作变量

a=h0,b=h1,c=h2,d=h3 e=h4,f=h5,g=h6,h=h7

3>主压缩循环
执行 64 轮,每轮使用一个常量 K[t] 和消息字 W[t]:

T1=h+Σ₁(e)+Ch(e,f,g)+K[t]+W[t]T2=Σ₀(a)+Maj(a,b,c)h=g g=f f=e e=d+T1 d=c c=b b=a a=T1+T2 其中的函数定义为: Σ₀(x)=ROTR²(x)⊕ ROTR¹³(x)⊕ ROTR²²(x)Σ₁(x)=ROTR⁶(x)⊕ ROTR¹¹(x)⊕ ROTR²⁵(x)Ch(x,y,z)=(x ∧ y)(¬x ∧ z)Maj(x,y,z)=(x ∧ y)(x ∧ z)(y ∧ z)

4>更新哈希值

h0=h0+a h1=h1+b h2=h2+c h3=h3+d h4=h4+e h5=h5+f h6=h6+g h7=h7+h

二、在可信固件更新中的应用

1.固件完整性验证

  • 计算固件的 SHA-256 哈希值
  • 将哈希值存储在固件头部或单独存储
  • 设备收到固件后,重新计算哈希值并与存储的哈希值比较

2.安全启动链

  • ROM 代码验证 Bootloader 的哈希值
  • Bootloader 验证应用程序的哈希值
  • 建立信任根,确保只有授权代码能够执行

3.防篡改机制

  • 任何对固件的修改都会导致完全不同的哈希值
  • 提供防止中间人攻击的保护

4.恢复机制

  • 在更新过程中,可以随时验证部分下载的固件哈希值
  • 确保在断电或连接中断后,仍能验证已下载部分的完整性

5.与其他哈希算法的比较

算法输出大小安全性性能应用场景
MD5128位已被破解非常快不建议用于安全场景
SHA-1160位已有碰撞攻击不建议用于新系统
SHA-256256位中等通用安全应用,嵌入式系统
SHA-384/512384/512位极高在64位系统上较快高安全性需求场景
SHA-3可变极高较慢特殊安全需求

6.SHA-256 在嵌入式系统中的优化

在资源受限的嵌入式系统中,SHA-256 的实现可以通过以下方式优化

方法功能
查表法使用预计算的表加速某些操作
循环展开减少循环开销
批处理一次处理多个数据块
并行计算利用多核处理器同时计算不同部分
SIMD指令使用ARM NEON等SIMD指令集加速位操作
硬件加速利用MCU内置的加密硬件单元
缓存优化调整数据结构以提高缓存命中率

三、SHA-256 的C语言实现

以下是一个适合嵌入式系统的轻量级SHA-256实现示例

1.sha256.h

#ifndefAPPLICATIONS_SYSTEM_INC_SHA256_H_#defineAPPLICATIONS_SYSTEM_INC_SHA256_H_#include"board.h"#include<stdint.h>#include<string.h>// SHA-256 常量定义#defineSHA256_BLOCK_SIZE64#defineSHA256_DIGEST_SIZE32#defineSHA256_BUFFER_SIZE1024// 循环右移#defineROTR(x,n)(((x)>>(n))|((x)<<(32-(n))))// SHA-256 压缩函数#defineCH(x,y,z)(((x)&(y))^(~(x)&(z)))#defineMAJ(x,y,z)(((x)&(y))^((x)&(z))^((y)&(z)))#defineEP0(x)(ROTR(x,2)^ROTR(x,13)^ROTR(x,22))#defineEP1(x)(ROTR(x,6)^ROTR(x,11)^ROTR(x,25))#defineSIG0(x)(ROTR(x,7)^ROTR(x,18)^((x)>>3))#defineSIG1(x)(ROTR(x,17)^ROTR(x,19)^((x)>>10))// SHA-256 上下文结构typedefstruct{uint8_tdata[64];// 当前处理的数据块uint32_tdatalen;// 当前块中的字节数uint64_tbitlen;// 已处理消息的总位数uint32_tstate[8];// 哈希状态值 h0-h7}SHA256_CTX;SHA256_CTX g_ctx;externvoidsha256_init(SHA256_CTX*ctx);externvoidsha256(constuint8_tdata[],size_tlen,uint8_thash[]);#endif

2.sha256.c

#include"sha256.h"// SHA-256 常量表staticconstuint32_tK[64]={0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2};/** * @brief 初始化SHA-256上下文 * @param ctx:上下文结构体 */voidsha256_init(SHA256_CTX*ctx){ctx->datalen=0;ctx->bitlen=0;ctx->state[0]=0x6a09e667;ctx->state[1]=0xbb67ae85;ctx->state[2]=0x3c6ef372;ctx->state[3]=0xa54ff53a;ctx->state[4]=0x510e527f;ctx->state[5]=0x9b05688c;ctx->state[6]=0x1f83d9ab;ctx->state[7]=0x5be0cd19;}/** * @brief SHA-256转换函数 - 处理一个完整的数据块 * @param ctx:上下文结构体 * @param data:数据 */staticvoidsha256_transform(SHA256_CTX*ctx,constuint8_tdata[]){uint32_ta,b,c,d,e,f,g,h,i,j,t1,t2,m[64];// 准备消息调度for(i=0,j=0;i<16;++i,j+=4)m[i]=(data[j]<<24)|(data[j+1]<<16)|(data[j+2]<<8)|(data[j+3]);for(;i<64;++i)m[i]=SIG1(m[i-2])+m[i-7]+SIG0(m[i-15])+m[i-16];a=ctx->state[0];b=ctx->state[1];c=ctx->state[2];d=ctx->state[3];e=ctx->state[4];f=ctx->state[5];g=ctx->state[6];h=ctx->state[7];// 主压缩循环for(i=0;i<64;++i){t1=h+EP1(e)+CH(e,f,g)+K[i]+m[i];t2=EP0(a)+MAJ(a,b,c);h=g;g=f;f=e;e=d+t1;d=c;c=b;b=a;a=t1+t2;}// 更新状态值ctx->state[0]+=a;ctx->state[1]+=b;ctx->state[2]+=c;ctx->state[3]+=d;ctx->state[4]+=e;ctx->state[5]+=f;ctx->state[6]+=g;ctx->state[7]+=h;}/** * @brief 向SHA-256上下文中添加数据 * @param ctx:上下文结构体 * @param data:数据 * @param len:数据长度 */staticvoidsha256_update(SHA256_CTX*ctx,constuint8_tdata[],size_tlen){size_ti;for(i=0;i<len;++i){ctx->data[ctx->datalen]=data[i];ctx->datalen++;if(ctx->datalen==64){sha256_transform(ctx,ctx->data);ctx->bitlen+=512;ctx->datalen=0;}}}/** * @brief 完成SHA-256计算并获取哈希值 * @param ctx:上下文结构体 * @param hash:哈希值 */staticvoidsha256_final(SHA256_CTX*ctx,uint8_thash[]){uint32_ti;// 处理最后不满一个块的数据i=ctx->datalen;// 填充1位if(ctx->datalen<56){ctx->data[i++]=0x80;// 10000000// 填充0位while(i<56)ctx->data[i++]=0x00;}else{ctx->data[i++]=0x80;// 填充0位while(i<64)ctx->data[i++]=0x00;sha256_transform(ctx,ctx->data);memset(ctx->data,0,56);}// 添加消息长度(以位为单位)ctx->bitlen+=ctx->datalen*8;ctx->data[63]=(uint8_t)ctx->bitlen;ctx->data[62]=(uint8_t)(ctx->bitlen>>8);ctx->data[61]=(uint8_t)(ctx->bitlen>>16);ctx->data[60]=(uint8_t)(ctx->bitlen>>24);ctx->data[59]=(uint8_t)(ctx->bitlen>>32);ctx->data[58]=(uint8_t)(ctx->bitlen>>40);ctx->data[57]=(uint8_t)(ctx->bitlen>>48);ctx->data[56]=(uint8_t)(ctx->bitlen>>56);sha256_transform(ctx,ctx->data);// 大端序输出哈希值for(i=0;i<8;++i){hash[i*4]=(ctx->state[i]>>24)&0xFF;hash[i*4+1]=(ctx->state[i]>>16)&0xFF;hash[i*4+2]=(ctx->state[i]>>8)&0xFF;hash[i*4+3]=ctx->state[i]&0xFF;}}

3.嵌入式系统上的应用示例

使用操作如下:
(1)在函数初始化的时候对哈希值进行初始化,直接调用函数:sha256_init();
(2)如果是对一片数据需要进行分段进行数据校验,可以直接调用函数进行哈希值的更新,调用函数:sha256_update(&g_ctx, data, len);
(3)最后进行哈希值的最终校验,调用函数:sha256_final(&g_ctx, hash);

/** * @brief 便捷函数:直接计算消息的SHA-256哈希值 * @param data:数据 * @param len:长度 * @param hash:哈希值 */voidsha256(constuint8_tdata[],size_tlen,uint8_thash[]){sha256_update(&g_ctx,data,len);if(g_esp32.endDataFlg==1){sha256_final(&g_ctx,hash);}}

4.使用硬件加速器

某些STM32型号(如STM32F415、F437、F479、H7系列等)内置了加密硬件加速器,可以显著提高SHA-256的性能

// 使用STM32 HAL库的硬件SHA加速voidhw_sha256_hash(constuint8_t*data,uint32_tlen,uint8_thash[32]){HASH_HandleTypeDef hhash;// 初始化HASH外设hhash.Init.DataType=HASH_DATATYPE_8B;HAL_HASH_Init(&hhash);// 选择SHA-256算法HAL_HASH_SHA256_Start(&hhash,(uint8_t*)data,len,hash,HAL_MAX_DELAY);// 或者分步处理大量数据:// HAL_HASH_SHA256_Accumulate(&hhash, data_part1, len1);// HAL_HASH_SHA256_Accumulate(&hhash, data_part2, len2);// HAL_HASH_SHA256_Finish(&hhash, hash, HAL_MAX_DELAY);}

四、总结

SHA-256作为一种强大的哈希算法,在嵌入式系统安全方面扮演着至关重要的角色。它为固件验证、安全启动和数据完整性提供了可靠保障,同时其相对较小的计算量使其适用于资源受限的微控制器。

在实际应用中,需要根据特定的安全需求和资源限制来平衡性能与安全性。对于要求极高安全性的场景,可以考虑使用SHA-384/512或SHA-3,而对于性能敏感的场景,则应充分利用硬件加速功能。

随着物联网设备数量的增加和安全威胁的演变,安全哈希算法在嵌入式系统中的应用将继续扩大,SHA-256凭借其出色的安全性能平衡,在可预见的未来仍将是首选方案之一。


需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询