d1e6bb4ba7
N-19 FTP 鉴权:
- lftpd_auth(USER/PASS 状态机 + 连续5次失败锁60s)+ SHA-256
(user||pwd) 口令哈希;config.ini [ftp] 段 user/pwd_hash/write,
出厂 admin/admin 在用有启动告警;lftpd_log.c 删除并入 lftpd_auth
- ftp_cfg 配置读写;台架 ftp_auth_bench.py 13/13
N-30 / Trap 25(CH395F_Trap_Records.md 四次定案全记录):
- 修复1 closed-with-data accept:客户端发完正常 FIN 后芯片按
FUN_PARA(0x09) §5.52② 保留 Socket+RX 缓冲,旧代码把 CLOSED 一律
relisten 自毁缓冲 → STOR 必挂 425;改为接受"已关但可读"连接排空
- 修复2 丢 CONNECT 中断探针 net_lost_connect_probe + last_peer_port
幽灵甄别(拆链窗口握手完成但中断丢失,双信源去抖补 accept)
- 修复3 send_list/send_nlst 批量单发:背靠背 ~60B 小段毒化芯片 TX
(芯片报 SEND_OK 但对端全丢),整份目录一次性写入
- 证伪存档:固定沉降/Socket 轮换冷却/listen 门控(台架 v7 矩阵)
- 台架工具 test/board/ch395f_reuse_bench.{c,h} + host 脚本存档
(不注册编译;实验分支 n30-chip-bench 保留)
N-20:Error_Handler 死循环降级(记录+复位路径)
N-23:scripts/check_registration.py 双端注册反向校验(pre-commit)
N-26:GD5F NAND 直 DMA 调用方缓冲窗口断言
验证:BUILD_OK 0/0;ftp_regression 连跑 4 轮 11/11(修复前
LIST#4/#7 100% 挂、STOR#2 曾 100% 425);ftp_auth_bench 13/13;
@test 启动标记 PASS;ci_local L0+L0.5 全过;doc-links 通过。
登记簿 N-30 已销项。
254 lines
8.5 KiB
C
254 lines
8.5 KiB
C
/*
|
||
* 模块名称:sha256
|
||
* 模块功能:SHA-256 安全散列(FIPS 180-4)实现——纯标准库、零堆分配
|
||
* 适用平台:STM32F407ZGTx / PC 主机侧单测(双端共用)
|
||
* 作者:王建锋
|
||
* 创建日期:2026-10-11
|
||
* 修改记录:
|
||
* v1.0 2026-10-11 王建锋 创建初始版本(N-19 FTP 鉴权;标准向量由
|
||
* test/host/sha256 主机单测钉死)
|
||
*/
|
||
|
||
/* 头文件包含区 */
|
||
#include <string.h>
|
||
|
||
#include "sha256.h"
|
||
|
||
/* 私有宏定义区 */
|
||
#define SHA256_ROTR32(x, n) (((x) >> (n)) | ((x) << (32u - (n))))
|
||
#define SHA256_CH(x, y, z) (((x) & (y)) ^ ((~(x)) & (z)))
|
||
#define SHA256_MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
|
||
#define SHA256_EP0(x) (SHA256_ROTR32(x, 2u) ^ SHA256_ROTR32(x, 13u) ^ SHA256_ROTR32(x, 22u))
|
||
#define SHA256_EP1(x) (SHA256_ROTR32(x, 6u) ^ SHA256_ROTR32(x, 11u) ^ SHA256_ROTR32(x, 25u))
|
||
#define SHA256_SIG0(x) (SHA256_ROTR32(x, 7u) ^ SHA256_ROTR32(x, 18u) ^ ((x) >> 3u))
|
||
#define SHA256_SIG1(x) (SHA256_ROTR32(x, 17u) ^ SHA256_ROTR32(x, 19u) ^ ((x) >> 10u))
|
||
|
||
/* 私有变量定义区 */
|
||
/* 轮常量(FIPS 180-4 §4.2.2.2:前 64 个素数立方根小数部分前 32 位) */
|
||
static const uint32_t s_k[64] = {
|
||
0x428a2f98u, 0x71374491u, 0xb5c0fbcfu, 0xe9b5dba5u,
|
||
0x3956c25bu, 0x59f111f1u, 0x923f82a4u, 0xab1c5ed5u,
|
||
0xd807aa98u, 0x12835b01u, 0x243185beu, 0x550c7dc3u,
|
||
0x72be5d74u, 0x80deb1feu, 0x9bdc06a7u, 0xc19bf174u,
|
||
0xe49b69c1u, 0xefbe4786u, 0x0fc19dc6u, 0x240ca1ccu,
|
||
0x2de92c6fu, 0x4a7484aau, 0x5cb0a9dcu, 0x76f988dau,
|
||
0x983e5152u, 0xa831c66du, 0xb00327c8u, 0xbf597fc7u,
|
||
0xc6e00bf3u, 0xd5a79147u, 0x06ca6351u, 0x14292967u,
|
||
0x27b70a85u, 0x2e1b2138u, 0x4d2c6dfcu, 0x53380d13u,
|
||
0x650a7354u, 0x766a0abbu, 0x81c2c92eu, 0x92722c85u,
|
||
0xa2bfe8a1u, 0xa81a664bu, 0xc24b8b70u, 0xc76c51a3u,
|
||
0xd192e819u, 0xd6990624u, 0xf40e3585u, 0x106aa070u,
|
||
0x19a4c116u, 0x1e376c08u, 0x2748774cu, 0x34b0bcb5u,
|
||
0x391c0cb3u, 0x4ed8aa4au, 0x5b9cca4fu, 0x682e6ff3u,
|
||
0x748f82eeu, 0x78a5636fu, 0x84c87814u, 0x8cc70208u,
|
||
0x90befffau, 0xa4506cebu, 0xbef9a3f7u, 0xc67178f2u,
|
||
};
|
||
|
||
/* 函数定义区 */
|
||
|
||
/*
|
||
* 函数功能:处理一个 64 B 分组(消息扩展 + 64 轮压缩)
|
||
* 入口参数:p_ctx - 上下文 p_block - 64 B 分组(大端字序)
|
||
* 返回值:无
|
||
* 限定条件:p_block 恰为 64 B 有效数据
|
||
* 函数说明:w[64] 为栈上消息扩展数组(256 B,ftpTask 4 KB 栈可容纳)
|
||
*/
|
||
static void s_transform(sha256_ctx_t *p_ctx, const uint8_t *p_block) {
|
||
uint32_t w[64];
|
||
uint32_t a;
|
||
uint32_t b;
|
||
uint32_t c;
|
||
uint32_t d;
|
||
uint32_t e;
|
||
uint32_t f;
|
||
uint32_t g;
|
||
uint32_t h;
|
||
|
||
for (uint32_t i = 0u; i < 16u; i++) {
|
||
w[i] = ((uint32_t)p_block[4u * i] << 24) |
|
||
((uint32_t)p_block[4u * i + 1u] << 16) |
|
||
((uint32_t)p_block[4u * i + 2u] << 8) |
|
||
(uint32_t)p_block[4u * i + 3u];
|
||
}
|
||
for (uint32_t i = 16u; i < 64u; i++) {
|
||
w[i] = SHA256_SIG1(w[i - 2u]) + w[i - 7u] +
|
||
SHA256_SIG0(w[i - 15u]) + w[i - 16u];
|
||
}
|
||
|
||
a = p_ctx->state[0];
|
||
b = p_ctx->state[1];
|
||
c = p_ctx->state[2];
|
||
d = p_ctx->state[3];
|
||
e = p_ctx->state[4];
|
||
f = p_ctx->state[5];
|
||
g = p_ctx->state[6];
|
||
h = p_ctx->state[7];
|
||
|
||
for (uint32_t i = 0u; i < 64u; i++) {
|
||
uint32_t t1 = h + SHA256_EP1(e) + SHA256_CH(e, f, g) + s_k[i] + w[i];
|
||
uint32_t t2 = SHA256_EP0(a) + SHA256_MAJ(a, b, c);
|
||
h = g;
|
||
g = f;
|
||
f = e;
|
||
e = d + t1;
|
||
d = c;
|
||
c = b;
|
||
b = a;
|
||
a = t1 + t2;
|
||
}
|
||
|
||
p_ctx->state[0] += a;
|
||
p_ctx->state[1] += b;
|
||
p_ctx->state[2] += c;
|
||
p_ctx->state[3] += d;
|
||
p_ctx->state[4] += e;
|
||
p_ctx->state[5] += f;
|
||
p_ctx->state[6] += g;
|
||
p_ctx->state[7] += h;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:初始化上下文(清零 + 置初始链接变量,FIPS 180-4 §5.3.3)
|
||
* 入口参数:p_ctx - 上下文
|
||
* 返回值:无
|
||
* 限定条件:p_ctx 为 NULL 时静默返回(fail-safe)
|
||
*/
|
||
void sha256_init(sha256_ctx_t *p_ctx) {
|
||
if (p_ctx == NULL) {
|
||
return;
|
||
}
|
||
(void)memset(p_ctx, 0, sizeof(*p_ctx));
|
||
/* 初始链接变量(FIPS 180-4 §5.3.3:前 8 个素数平方根小数部分前 32 位) */
|
||
p_ctx->state[0] = 0x6a09e667u;
|
||
p_ctx->state[1] = 0xbb67ae85u;
|
||
p_ctx->state[2] = 0x3c6ef372u;
|
||
p_ctx->state[3] = 0xa54ff53au;
|
||
p_ctx->state[4] = 0x510e527fu;
|
||
p_ctx->state[5] = 0x9b05688cu;
|
||
p_ctx->state[6] = 0x1f83d9abu;
|
||
p_ctx->state[7] = 0x5be0cd19u;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:流式喂入数据(任意长度,内部按 64 B 分组压缩)
|
||
* 入口参数:p_ctx - 上下文 p_data - 数据 len - 字节数
|
||
* 返回值:无
|
||
* 限定条件:p_ctx/p_data 为 NULL 时静默返回
|
||
*/
|
||
void sha256_update(sha256_ctx_t *p_ctx, const void *p_data, size_t len) {
|
||
const uint8_t *p = (const uint8_t *)p_data;
|
||
|
||
if ((p_ctx == NULL) || (p == NULL)) {
|
||
return;
|
||
}
|
||
for (size_t i = 0u; i < len; i++) {
|
||
p_ctx->buf[p_ctx->buf_len] = p[i];
|
||
p_ctx->buf_len++;
|
||
if (p_ctx->buf_len >= SHA256_BLOCK_SIZE) {
|
||
s_transform(p_ctx, p_ctx->buf);
|
||
p_ctx->bitlen += (uint64_t)SHA256_BLOCK_SIZE * 8u;
|
||
p_ctx->buf_len = 0u;
|
||
}
|
||
}
|
||
}
|
||
|
||
/*
|
||
* 函数功能:收尾输出 32 B 摘要(补位 + 长度字段 + 末次压缩)
|
||
* 入口参数:p_ctx - 上下文 p_out - 32 B 摘要输出
|
||
* 返回值:无
|
||
* 限定条件:p_ctx/p_out 为 NULL 时静默返回;收尾后上下文清零(防敏感残留)
|
||
*/
|
||
void sha256_final(sha256_ctx_t *p_ctx, uint8_t p_out[SHA256_DIGEST_SIZE]) {
|
||
uint64_t bitlen;
|
||
uint8_t pad = 0x80u;
|
||
uint8_t zero = 0x00u;
|
||
uint8_t len_be[8];
|
||
|
||
if ((p_ctx == NULL) || (p_out == NULL)) {
|
||
return;
|
||
}
|
||
/* 总长 = 完整分组累计 + 暂存区(必须在补位前定稿) */
|
||
bitlen = p_ctx->bitlen + (uint64_t)p_ctx->buf_len * 8u;
|
||
|
||
(void)sha256_update(p_ctx, &pad, 1u);
|
||
while (p_ctx->buf_len != 56u) {
|
||
(void)sha256_update(p_ctx, &zero, 1u);
|
||
}
|
||
for (uint32_t i = 0u; i < 8u; i++) {
|
||
len_be[i] = (uint8_t)((bitlen >> (56u - 8u * i)) & 0xFFu);
|
||
}
|
||
(void)sha256_update(p_ctx, len_be, 8u);
|
||
|
||
for (uint32_t i = 0u; i < 8u; i++) {
|
||
p_out[4u * i] = (uint8_t)(p_ctx->state[i] >> 24);
|
||
p_out[4u * i + 1u] = (uint8_t)(p_ctx->state[i] >> 16);
|
||
p_out[4u * i + 2u] = (uint8_t)(p_ctx->state[i] >> 8);
|
||
p_out[4u * i + 3u] = (uint8_t)(p_ctx->state[i]);
|
||
}
|
||
(void)memset(p_ctx, 0, sizeof(*p_ctx));
|
||
}
|
||
|
||
/*
|
||
* 函数功能:一次性计算 32 B 摘要(init+update+final 便捷封装)
|
||
* 入口参数:p_data - 数据 len - 字节数 p_out - 摘要输出
|
||
* 返回值:无
|
||
* 限定条件:栈上上下文 ≈108 B;NULL 参数由子函数兜底
|
||
*/
|
||
void sha256_calc(const void *p_data, size_t len, uint8_t p_out[SHA256_DIGEST_SIZE]) {
|
||
sha256_ctx_t ctx;
|
||
|
||
sha256_init(&ctx);
|
||
sha256_update(&ctx, p_data, len);
|
||
sha256_final(&ctx, p_out);
|
||
}
|
||
|
||
/*
|
||
* 函数功能:hex 字符 → 半字节值
|
||
* 入口参数:c - 字符 p_out - 输出 0~15
|
||
* 返回值:0 - 合法;-1 - 非法 int
|
||
* 限定条件:p_out 非空
|
||
*/
|
||
static int s_hex_nibble(char c, uint8_t *p_out) {
|
||
uint8_t v;
|
||
|
||
if ((c >= '0') && (c <= '9')) {
|
||
v = (uint8_t)(c - '0');
|
||
} else if ((c >= 'a') && (c <= 'f')) {
|
||
v = (uint8_t)(c - 'a') + 10u;
|
||
} else if ((c >= 'A') && (c <= 'F')) {
|
||
v = (uint8_t)(c - 'A') + 10u;
|
||
} else {
|
||
return -1;
|
||
}
|
||
*p_out = v;
|
||
return 0;
|
||
}
|
||
|
||
/*
|
||
* 函数功能:摘要与 64 位 hex 串恒定时间比较(大小写不敏感)
|
||
* 入口参数:p_digest - 32 B 摘要 p_hex - 64 字符 hex 串
|
||
* 返回值:1 - 相等;0 - 不等 / 长度非 64 / 非法 hex / NULL
|
||
* 限定条件:比较段不短路(XOR 累加器);hex 非法属配置错误,早退不构成口令侧信道
|
||
*/
|
||
int sha256_hex_eq(const uint8_t p_digest[SHA256_DIGEST_SIZE], const char *p_hex) {
|
||
uint8_t acc = 0u;
|
||
uint8_t hi;
|
||
uint8_t lo;
|
||
|
||
if ((p_digest == NULL) || (p_hex == NULL)) {
|
||
return 0;
|
||
}
|
||
if (strlen(p_hex) != (SHA256_DIGEST_SIZE * 2u)) {
|
||
return 0;
|
||
}
|
||
for (uint32_t i = 0u; i < SHA256_DIGEST_SIZE; i++) {
|
||
if ((s_hex_nibble(p_hex[2u * i], &hi) != 0) ||
|
||
(s_hex_nibble(p_hex[2u * i + 1u], &lo) != 0)) {
|
||
/* hex 非法 = 配置错误(可信来源),早退不构成口令侧信道 */
|
||
return 0;
|
||
}
|
||
acc |= (uint8_t)(p_digest[i] ^ (uint8_t)((hi << 4) | lo));
|
||
}
|
||
return (acc == 0u) ? 1 : 0;
|
||
}
|