0f7b5a87fb
登记簿、文档与代码注释里的存量字母加数字编号(N-x / S-x / T-x / E-x / A-x / 卡号) 一律改写为语义短语,净删 2,028 处引用;删除基线与待确认、并行分道方案、排期详述、 采集保护收尾 4 篇(内容已并入 docs/任务规划/README 与登记簿)。 门禁机器与三张账同批重打:check_ids.py 新增变更记录行豁免与第二根护栏 undecidable_total_ceiling;check_test_traceability.py 只加 stdout/stderr UTF-8 reconfigure(TC_RE 未动);check_cubemx_survival.py 的 --write 固定 newline=LF; id_registry / id_aliases(+19 条 retired-to-phrase)/ id_known_backlog 重打。 test/ 56 个文件同步 TC 标签语义化,其中 18 个 TU 改了 CHECK / printf 里的标签文字, 是本批唯一改变构建产物的文件集合。 为什么合成一笔、不拆四笔(实测撞闸,非偏好):pre-commit 跑钩子前会 stash 未 staged 部分,拆开后中间提交必然是「新规则 + 旧语料」——实跑可判定 85.15% < 基线 86.00%、 不可判定 1,453 > 上限 1,166,编号门禁直接拦下。编号识别面与它描述的语料只能同码移动。 实跑基线(工作区全量):754 文件 / 8,230 处编号字面量 / 可判定 7,079 = 86.01% (基线 86.0%,容差 0.1pp)/ 不可判定绝对数 1,151(上限 1,166)/ 校验 1-6 错误级 0 / 告警 = 悬空 2(App/algo/freq.c 的 S2,属 §4.4 同号不同义)+ 孤儿 50。 基线从 84.0 抬到 86.0 的理由见 docs/门禁说明/id-check.md §7.6:本批真删了 2,028 处 引用,可判定面随真实内容上升,不是把分母做小。同批新增排除 docs/硬件平台/ 语料,使 识别面少 264 处——芯片手册位号与网表料号不属编号空间(registry 有 excluded_paths_note)。 ⚠ 余量只剩 0.11pp(约 10 处)与绝对数 15 处:把「可判定的引用」改成散文会立刻撞第二 根护栏。另遗留一项:id_aliases 里 retired 的 N / S / T / A 别名没有 scope(U1~U5 有), 今后有人新写一个 A-4,校验 3 不会响,只能靠人,建议下批补 scope。 固件不变证据:115 个 .c/.h 剥注释并归一字符串后与 HEAD 逐字节全等,残留代码差异 0; App / Src / Drivers 的字符串字面量零改动。@build 0 错误 0 警告;40/40 主机套件、2,889 断言全通过;覆盖率 line 89.2% / func 92.6%;pre-commit 48 钩子 --all-files 全绿; check_doc_links --all 通过(176 文档,章节引用无法判定 0);逐字节卫生核过:14 个带 BOM 文件与 HEAD 一致、0 个 CR、0 个 U+FFFD,字符串字面量纯 ASCII。 .cubemx_survival_baseline.json 的 watchdog-module 哈希 56bf27 变 2bb051 属合法: Src/freertos.c 的 USER CODE 区内只有注释文字随编号改写,代码未变。 同批带上体积同码凭证与 RAM 台账行(@build 之后盖戳):RW_IRAM1 79,008 B / 60.3%, RW_CCM 57,376 B / 87.9%,阈值 92%。
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 王建锋 创建初始版本(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;
|
||
}
|