hmac-sha256不是简单拼接密钥与数据的哈希,而是严格遵循rfc 2104的两轮异或填充算法:先用密钥与ipad异或后哈希消息,再将结果与密钥和opad异或后的值二次哈希,输出32字节二进制认证码。

SHA256加盐(keyed)不是直接调用SHA256()函数就能完成的
标准C++标准库(<functional></functional>或<openssl></openssl>)不提供“带密钥的SHA256”原生接口。所谓“带密钥的哈希”,实际指HMAC-SHA256——它不是简单把密钥拼到消息前/后哈希,而是有严格两轮填充与异或的算法。直接SHA256(key + data)或SHA256(data + key)既不安全也不符合HMAC规范,会被长度扩展攻击利用。
用OpenSSL实现HMAC-SHA256最可靠
OpenSSL的HMAC()函数专为此设计,封装了RFC 2104全部逻辑。注意:必须用HMAC_CTX_new() + HMAC_Init_ex() + HMAC_Update() + HMAC_Final()这一套流程,旧版HMAC()单函数接口已弃用(OpenSSL 3.0+移除)。
常见错误包括:
- 传入空
key指针或key_len = 0,导致返回全零哈希 - 误用
EVP_sha256()返回值作为const EVP_MD *参数时未检查是否为nullptr - 忘记
HMAC_CTX_free(ctx),造成内存泄漏(尤其在循环中)
示例关键片段:
HMAC_CTX *ctx = HMAC_CTX_new(); HMAC_Init_ex(ctx, key, key_len, EVP_sha256(), nullptr); HMAC_Update(ctx, data, data_len); unsigned char md[EVP_MAX_MD_SIZE]; uint32_t md_len; HMAC_Final(ctx, md, &md_len); HMAC_CTX_free(ctx);
如果不能用OpenSSL,别手写HMAC,改用libsodium
自己实现HMAC-SHA256极易出错(比如密钥过长时没做哈希截断、ipad/opad填充字节算错)。更现实的选择是引入libsodium——它提供简洁安全的crypto_auth_hmacsha256()接口:
要点:
-
key必须恰好crypto_auth_hmacsha256_KEYBYTES字节(32字节),短于该长度需补零,长于则先SHA256哈希再截取 - 输出长度固定为
crypto_auth_hmacsha256_BYTES(32字节),无需手动指定 - 比OpenSSL API更难误用,且默认启用运行时密码学安全检测
调用示例:
unsigned char mac[crypto_auth_hmacsha256_BYTES]; crypto_auth_hmacsha256(mac, msg, msg_len, key);
别混淆HMAC和HKDF,也别把AES密钥派生当哈希用
有人看到“带密钥的SHA256”就去用HKDF-SHA256或AES-CTR-PRF,这是场景错配。HMAC-SHA256用于消息认证(验证完整性+来源),而HKDF用于密钥派生(从弱熵生成强密钥)。若你真正需要的是“用密码生成固定哈希”,应选PKCS#5 PBKDF2_HMAC_SHA256并设足够迭代次数;若只是校验数据是否被篡改且知道密钥,HMAC就是唯一正解。
最容易被忽略的一点:HMAC输出是二进制字节流,转十六进制字符串时必须逐字节printf("%02x", byte),不能直接std::string构造或std::cout ——后者会因遇到<code>\0提前截断。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











