# Hash算法
***Copyright © Quectel Wireless Solutions Co., Ltd. 2026. All rights reserved.***
---
# 功能概述
本模块提供标准的消息摘要(Hash)计算功能,支持SHA-1、SHA-256和MD5算法,可用于数据完整性校验、密码加盐散列存储,以及基于HMAC(散列消息认证码)的API鉴权防篡改。
## 主要应用场景
1. 文件完整性校验:下载OTA固件后计算其SHA-256摘要,与云端提供的摘要比对,判断文件是否损坏或被篡改。
2. 报文完整性校验:对通信数据计算Hash值,确认传输前后内容一致。
3. HMAC身份认证:使用密钥对消息计算HMAC-SHA256签名,供云端与设备双方校验请求是否合法。
4. 密码保护:不直接保存明文密码,而是保存经专用密码哈希算法处理后的结果;嵌入式设备常用PBKDF2-HMAC-SHA256。
5. 密钥派生:通过ECDH得到共享秘密后,使用HKDF-SHA256派生AES会话密钥。
6. 数字签名:RSA/ECDSA通常先对固件或数据计算SHA-256摘要,再对摘要进行签名。
7. 数据去重与版本识别:通过比较文件的Hash值判断两个文件内容是否相同。
## 常见问题
1. Hash不是加密算法:Hash运算不可逆,无法"解密",主要用于完整性校验和摘要计算。
2. 密码不能直接用SHA-256存储:保存密码应使用Argon2、bcrypt、scrypt或PBKDF2等专用算法,并加入随机盐。
3. 身份认证不能只用普通Hash:消息防篡改应使用HMAC-SHA256,不能以"密钥拼接数据后直接计算SHA-256"的方式代替。
4. 避免使用MD5/SHA-1:安全场景应优先选用SHA-256/SHA-3;比较摘要时应使用恒定时间比较,避免时序信息泄露。
# Hash算法 API
## 头文件
*qcm_sha256.h*
## 函数概览
| **函数** | **说明** |
| --- | --- |
| *qcm_core_sha256()* | 一次性计算输入数据的SHA-256摘要 |
| *qcm_hmac_sha256()* | 一次性计算数据的HMAC-SHA256认证码 |
| *qcm_sha256_init()* | 初始化SHA-256流式计算上下文 |
| *qcm_sha256_starts()* | 启动或重置流式计算 |
| *qcm_sha256_update()* | 追加处理一段输入数据 |
| *qcm_sha256_finish()* | 结束流式计算并输出32字节摘要 |
| *qcm_sha256_free()* | 释放SHA-256上下文并清除敏感数据 |
## 函数详解
### qcm_core_sha256
- **功能描述**
一次性计算输入数据的SHA-256摘要。适用于长度较小且已知的数据,将任意长度的输入直接散列为32字节的摘要结果。系统同时提供宏别名 *qcm_sha256()*,两者功能完全一致。
- **函数原型**
```c
void qcm_core_sha256(const qosa_uint8_t *input, qosa_uint32_t ilen, qosa_uint8_t output[32]);
```
- **参数说明**
| **参数名** | **输入/输出** | **类型** | **说明** |
| --- | --- | --- | --- |
| *input* | 输入 | const qosa_uint8_t * | 待计算数据的缓冲区首地址 |
| *ilen* | 输入 | qosa_uint32_t | 输入数据的长度;单位:字节 |
| *output* | 输出 | qosa_uint8_t[32] | 存放32字节摘要结果的输出数组 |
- **返回值说明**
无
### qcm_hmac_sha256
- **功能描述**
基于SHA-256计算HMAC(密钥散列消息认证码)。常用于调用云平台API时,对密钥与请求报文联合运算生成鉴权签名,防止请求内容被篡改。
- **函数原型**
```c
void qcm_hmac_sha256(const qosa_uint8_t *msg,
qosa_uint32_t msg_len,
const qosa_uint8_t *key,
qosa_uint32_t key_len,
qosa_uint8_t output[32]);
```
- **参数说明**
| **参数名** | **输入/输出** | **类型** | **说明** |
| --- | --- | --- | --- |
| *msg* | 输入 | const qosa_uint8_t * | 待认证消息的缓冲区首地址 |
| *msg_len* | 输入 | qosa_uint32_t | 消息长度;单位:字节 |
| *key* | 输入 | const qosa_uint8_t * | 鉴权密钥的缓冲区首地址 |
| *key_len* | 输入 | qosa_uint32_t | 密钥长度;单位:字节 |
| *output* | 输出 | qosa_uint8_t[32] | 存放32字节认证码结果的输出数组 |
- **返回值说明**
无
### qcm_sha256_init
- **功能描述**
初始化SHA-256流式计算上下文,为流式计算做准备。流式计算流程的第一步。
- **函数原型**
```c
void qcm_sha256_init(qcm_core_sha256_context_t *ctx);
```
- **参数说明**
| **参数名** | **输入/输出** | **类型** | **说明** |
| --- | --- | --- | --- |
| *ctx* | 输出 | *qcm_core_sha256_context_t ** | 待初始化的上下文;详见 [*qcm_core_sha256_context_t*](#qcmcoresha256contextt) |
- **返回值说明**
无
### qcm_sha256_starts
- **功能描述**
启动或重置流式计算。若上下文中存有此前的计算状态,将被重置。
- **函数原型**
```c
void qcm_sha256_starts(qcm_core_sha256_context_t *ctx);
```
- **参数说明**
| **参数名** | **输入/输出** | **类型** | **说明** |
| --- | --- | --- | --- |
| *ctx* | 输入/输出 | *qcm_core_sha256_context_t ** | 已初始化的上下文;详见 [*qcm_core_sha256_context_t*](#qcmcoresha256contextt) |
- **返回值说明**
无
### qcm_sha256_update
- **功能描述**
追加处理一段输入数据。可循环多次调用,将超出内存容量的大文件分段送入计算。
- **函数原型**
```c
void qcm_sha256_update(qcm_core_sha256_context_t *ctx, const qosa_uint8_t *input, qosa_uint32_t ilen);
```
- **参数说明**
| **参数名** | **输入/输出** | **类型** | **说明** |
| --- | --- | --- | --- |
| *ctx* | 输入/输出 | *qcm_core_sha256_context_t ** | 已完成启动的上下文;详见 [*qcm_core_sha256_context_t*](#qcmcoresha256contextt) |
| *input* | 输入 | const qosa_uint8_t * | 本次追加数据的缓冲区首地址 |
| *ilen* | 输入 | qosa_uint32_t | 本次追加数据的长度;单位:字节 |
- **返回值说明**
无
### qcm_sha256_finish
- **功能描述**
结束流式计算,输出最终的32字节摘要,内部自动完成数据补位。
- **函数原型**
```c
void qcm_sha256_finish(qcm_core_sha256_context_t *ctx, qosa_uint8_t output[32]);
```
- **参数说明**
| **参数名** | **输入/输出** | **类型** | **说明** |
| --- | --- | --- | --- |
| *ctx* | 输入/输出 | *qcm_core_sha256_context_t ** | 当前计算的上下文;详见 [*qcm_core_sha256_context_t*](#qcmcoresha256contextt) |
| *output* | 输出 | qosa_uint8_t[32] | 存放32字节摘要结果的输出数组 |
- **返回值说明**
无
### qcm_sha256_free
- **功能描述**
释放SHA-256上下文,擦除其中的内部状态与敏感数据,防止残留数据被误用。
- **函数原型**
```c
void qcm_sha256_free(qcm_core_sha256_context_t *ctx);
```
- **参数说明**
| **参数名** | **输入/输出** | **类型** | **说明** |
| --- | --- | --- | --- |
| *ctx* | 输入/输出 | *qcm_core_sha256_context_t ** | 计算完成后待清理的上下文;详见 [*qcm_core_sha256_context_t*](#qcmcoresha256contextt) |
- **返回值说明**
无
## 结构体定义
### qcm_core_sha256_context_t
SHA-256流式计算上下文结构体定义如下:
```c
typedef struct
{
qosa_uint32_t total[2];
qosa_uint32_t state[8];
qosa_uint8_t buffer[64];
qosa_uint8_t is224;
} qcm_core_sha256_context_t;
```
| **参数** | **类型** | **说明** |
| --- | --- | --- |
| *total* | qosa_uint32_t[2] | 已处理数据的总长度计数器;单位:字节 |
| *state* | qosa_uint32_t[8] | 哈希运算的中间状态 |
| *buffer* | qosa_uint8_t[64] | 暂存不足64字节的末尾数据,供后续运算或结束时补位处理 |
| *is224* | qosa_uint8_t | 算法选择标志
*0*:SHA-256
其他值:SHA-224 |
# 应用逻辑流程图
```{image} images/image_MehQb5OlBo2b01xPXo9cvTCjn5g.webp
:width: 1038px
:height: 733px
```
# 示例代码
1. 常规短文本摘要计算(一次性计算):
```c
#include "qcm_sha256.h"
#include "qosa_sys.h"
void app_sha_demo_short() {
qosa_uint8_t input_msg[] = "Hello_UniRTOS_2026!";
qosa_uint8_t hash_res[32] = {0};
// 一次性计算,调用完成后 hash_res 中即为32字节摘要结果
qcm_core_sha256(input_msg, sizeof(input_msg) - 1, hash_res);
}
```
2. 大文件分段计算(流式计算):
```c
#include "qcm_sha256.h"
#include "qosa_sys.h"
void app_sha_demo_long_file_sim() {
qcm_core_sha256_context_t ctx;
qosa_uint8_t final_res[32] = {0};
qosa_uint8_t file_chunk_buf[1024]; // 每次读取1024字节的数据缓冲区
// 1. 初始化并启动流式计算
qcm_sha256_init(&ctx);
qcm_sha256_starts(&ctx);
// 2. 循环读取文件并分段送入计算
while(/* 文件未读完,每次读取一段数据存入 file_chunk_buf */) {
qcm_sha256_update(&ctx, file_chunk_buf, 1024 /* 实际读取长度 */);
}
// 3. 结束计算并获取最终摘要
qcm_sha256_finish(&ctx, final_res);
// 4. 释放上下文
qcm_sha256_free(&ctx);
}
```