【STM32】知识点介绍三:哈希算法详解 文章目录一、简介1.哈希算法详解2.工作原理二、在可信固件更新中的应用1.固件完整性验证2.安全启动链3.防篡改机制4.恢复机制5.与其他哈希算法的比较6.SHA-256 在嵌入式系统中的优化三、SHA-256 的C语言实现1.sha256.h2.sha256.c3.嵌入式系统上的应用示例4.使用硬件加速器四、总结一、简介1.哈希算法详解SHA-256 是密码学哈希函数家族 SHA-2 (Secure Hash Algorithm 2) 中的一员由美国国家安全局 (NSA) 设计并由美国国家标准与技术研究院 (NIST) 在 2001 年发布。它是当今最广泛使用的哈希算法之一尤其在数据完整性验证、数字签名和密码存储等安全应用中。基本特性固定输出长度无论输入数据大小如何SHA-256 始终生成 256 位32 字节的哈希值单向性从哈希值反推原始数据在计算上是不可行的抗碰撞性找到两个产生相同哈希值的不同输入极其困难雪崩效应输入的微小变化会导致输出哈希值的显著变化确定性相同的输入总是产生相同的哈希值2.工作原理SHA-256 算法的工作原理可以分为以下几个主要步骤1预处理1填充消息①将输入消息追加一个 ‘1’ 位②再追加 K 个 ‘0’ 位使得(消息长度 1 K 64)是 512 的倍数③最后添加 64 位表示原始消息长度2解析消息①将填充后的消息分割成多个 512 位(64 字节)的块②每个块进一步分为 16 个 32 位字2初始化哈希值使用前 8 个质数(2 到 19)的平方根小数部分的前 32 位作为初始哈希值h0 0x6a09e667h1 0xbb67ae85h2 0x3c6ef372h3 0xa54ff53ah4 0x510e527fh5 0x9b05688ch6 0x1f83d9abh7 0x5be0cd193压缩函数主循环对于每个 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初始化工作变量ah0,bh1,ch2,dh3 eh4,fh5,gh6,hh73主压缩循环执行 64 轮每轮使用一个常量 K[t] 和消息字 W[t]T1hΣ₁(e)Ch(e,f,g)K[t]W[t]T2Σ₀(a)Maj(a,b,c)hg gf fe edT1 dc cb ba aT1T2 其中的函数定义为 Σ₀(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更新哈希值h0h0a h1h1b h2h2c h3h3d h4h4e h5h5f h6h6g h7h7h二、在可信固件更新中的应用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_#includeboard.h#includestdint.h#includestring.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[]);#endif2.sha256.c#includesha256.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-datalen0;ctx-bitlen0;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(i0,j0;i16;i,j4)m[i](data[j]24)|(data[j1]16)|(data[j2]8)|(data[j3]);for(;i64;i)m[i]SIG1(m[i-2])m[i-7]SIG0(m[i-15])m[i-16];actx-state[0];bctx-state[1];cctx-state[2];dctx-state[3];ectx-state[4];fctx-state[5];gctx-state[6];hctx-state[7];// 主压缩循环for(i0;i64;i){t1hEP1(e)CH(e,f,g)K[i]m[i];t2EP0(a)MAJ(a,b,c);hg;gf;fe;edt1;dc;cb;ba;at1t2;}// 更新状态值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(i0;ilen;i){ctx-data[ctx-datalen]data[i];ctx-datalen;if(ctx-datalen64){sha256_transform(ctx,ctx-data);ctx-bitlen512;ctx-datalen0;}}}/** * brief 完成SHA-256计算并获取哈希值 * param ctx上下文结构体 * param hash哈希值 */staticvoidsha256_final(SHA256_CTX*ctx,uint8_thash[]){uint32_ti;// 处理最后不满一个块的数据ictx-datalen;// 填充1位if(ctx-datalen56){ctx-data[i]0x80;// 10000000// 填充0位while(i56)ctx-data[i]0x00;}else{ctx-data[i]0x80;// 填充0位while(i64)ctx-data[i]0x00;sha256_transform(ctx,ctx-data);memset(ctx-data,0,56);}// 添加消息长度以位为单位ctx-bitlenctx-datalen*8;ctx-data[63](uint8_t)ctx-bitlen;ctx-data[62](uint8_t)(ctx-bitlen8);ctx-data[61](uint8_t)(ctx-bitlen16);ctx-data[60](uint8_t)(ctx-bitlen24);ctx-data[59](uint8_t)(ctx-bitlen32);ctx-data[58](uint8_t)(ctx-bitlen40);ctx-data[57](uint8_t)(ctx-bitlen48);ctx-data[56](uint8_t)(ctx-bitlen56);sha256_transform(ctx,ctx-data);// 大端序输出哈希值for(i0;i8;i){hash[i*4](ctx-state[i]24)0xFF;hash[i*41](ctx-state[i]16)0xFF;hash[i*42](ctx-state[i]8)0xFF;hash[i*43]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.endDataFlg1){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.DataTypeHASH_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凭借其出色的安全性能平衡在可预见的未来仍将是首选方案之一。