ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Linux 内核 SHA-3 算法库完全指南:FIPS-202 摘要与可扩展输出函数(XOF)编程实战

2026/9/16 11:34:43 拓冰建站 浏览量
Linux 内核 SHA-3 算法库完全指南:FIPS-202 摘要与可扩展输出函数(XOF)编程实战 Linux 内核 SHA-3 算法库完全指南FIPS-202 摘要与可扩展输出函数XOF编程实战【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linuxSHA-3 是 NIST FIPS-202 标准定义的哈希算法家族Linux 内核在lib/crypto/sha3.c中提供了完整的 SHA-3 库实现覆盖 SHA3-224/256/384/512 四种摘要算法与 SHAKE128/SHAKE256 两种可扩展输出函数。本文以内核文档 Documentation/crypto/sha3.rst 为主体结合 include/crypto/sha3.h 头文件与 lib/crypto/sha3.c 源码系统讲解 SHA-3 库的 API 设计、海绵结构底层原理、增量式数据流处理、架构优化与 KUnit/FIPS 测试体系帮助内核驱动与模块开发者快速掌握在内核态使用 SHA-3 的正确姿势。背景FIPS-202 与 Keccak 海绵结构SHA-3 家族算法由 NIST FIPS-202 标准规定全部基于 Keccak 海绵函数sponge function构造。正如文档 Overview 一节所述六个算法之间的差异体现在三个方面rate速率每次调用 Keccak 置换函数之间状态缓冲区中被新数据更新的字节数其作用与传统哈希的块大小block size类似域分隔后缀domain separation suffix追加到输入数据末尾、用于区分不同算法的固定字节输出长度算法结束时从状态中提取的输出数据量。Keccak 海绵函数被设计为可以为某些算法产生任意长度的输出这正是 SHAKE128/SHAKE256 作为可扩展输出函数Extendable-Output FunctionXOF能够按需生成任意长度伪随机输出的根本原因。内核 SHA-3 库提供六个算法中的全部成员四个摘要算法SHA3-224、SHA3-256、SHA3-384、SHA3-512以及两个 XOF 算法SHAKE128、SHAKE256。其中四个摘要算法除库 API 外还通过 crypto/sha3.c 接入内核通用加密框架的crypto_shash与crypto_ahashAPI。算法全景六个算法与关键参数include/crypto/sha3.h 顶部用宏定义了每个算法的摘要长度digest size与块大小block size两者严格遵循 FIPS-202 的换算关系block_size 200 - 2 * digest_size其中 200 字节即 Keccak-f[1600] 置换的状态大小SHA3_STATE_SIZE。算法摘要/默认输出长度块大小rate域分隔后缀源码可见SHA3-22428 字节224 bit144 字节0x06SHA3-25632 字节256 bit136 字节0x06SHA3-38448 字节384 bit104 字节0x06SHA3-51264 字节512 bit72 字节0x06SHAKE128任意长度默认 16 字节168 字节0x1fSHAKE256任意长度默认 32 字节136 字节0x1f宏定义示例摘自头文件第 13-36 行#define SHA3_224_DIGEST_SIZE (224 / 8) #define SHA3_224_BLOCK_SIZE (200 - 2 * SHA3_224_DIGEST_SIZE) #define SHA3_256_DIGEST_SIZE (256 / 8) #define SHA3_256_BLOCK_SIZE (200 - 2 * SHA3_256_DIGEST_SIZE) #define SHAKE128_DEFAULT_SIZE (128 / 8) #define SHAKE128_BLOCK_SIZE (200 - 2 * SHAKE128_DEFAULT_SIZE) #define SHA3_STATE_SIZE 200头文件中的注释还解释了 SHAKE128/SHAKE256 的块大小计算方式它们虽然实际输出长度可变但为了计算 rate 值仍沿用各自名义上的 128/256 bit 长度参与200 - 2 * size的换算。此外头文件为每个算法定义了导出大小宏如SHA3_224_EXPORT_SIZE用于crypto_shash模板接口的上下文导出/导入场景。内核 SHA-3 库的组成与启用SHA-3 库的代码分布于两处职责清晰库函数层librarylib/crypto/sha3.c 实现 Keccak-f[1600] 置换、数据吸收absorb、摘要终结final与 XOF 挤压squeeze并导出全部六个算法的一口one-shot与增量 API模板 API 层shash/ahashcrypto/sha3.c 将四个摘要算法包装为内核通用加密框架的crypto_shash/crypto_ahash模板由CONFIG_CRYPTO_SHA3控制编译见 crypto/Makefile。库函数层通过CONFIG_CRYPTO_LIB_SHA3开启其 Kconfig 帮助文本说明若模块使用了 include/crypto/sha3.h 中的任何函数就应选中该配置见 lib/crypto/Kconfig 第 285-290 行config CRYPTO_LIB_SHA3 tristate select CRYPTO_LIB_UTILS help The SHA3 library functions. Select this if your module uses any of the functions from crypto/sha3.h.库层导出的符号均以EXPORT_SYMBOL_GPL导出包括__sha3_update、sha3_final、shake_squeeze、sha3_224至sha3_512、shake128、shake256因此内核模块GPL 许可可以直接链接使用这些符号。摘要算法DigestAPI一口式与增量式文档 Digests 一节完整给出了摘要算法的两套使用方式。所有函数以u8 *缓冲区和size_t长度作为基本参数in为输入数据out为输出摘要。一口式 APIone-shot当所有输入数据一次可得时直接调用以下四个便捷函数原文档第 45-48 行void sha3_224(const u8 *in, size_t in_len, u8 out[SHA3_224_DIGEST_SIZE]); void sha3_256(const u8 *in, size_t in_len, u8 out[SHA3_256_DIGEST_SIZE]); void sha3_384(const u8 *in, size_t in_len, u8 out[SHA3_384_DIGEST_SIZE]); void sha3_512(const u8 *in, size_t in_len, u8 out[SHA3_512_DIGEST_SIZE]);头文件 kernel-doc 明确指出能够一次性提供全部输入时应优先使用一口式 API 而非增量式 API。示例#include crypto/sha3.h u8 digest[SHA3_256_DIGEST_SIZE]; sha3_256(data, data_len, digest);增量式 APIincremental对无法一次性获取全部数据如流式数据、分块读取的场景使用基于struct sha3_ctx的增量接口原文档第 51-71 行struct sha3_ctx ctx; u8 digest[SHA3_512_DIGEST_SIZE]; /* 1. 初始化决定摘要长度 */ sha3_512_init(ctx); /* 2. 任意多次追加输入 */ sha3_update(ctx, part1, len1); sha3_update(ctx, part2, len2); /* 3. 终结并取出摘要此调用同时将 ctx 清零 */ sha3_final(ctx, digest);四个初始化函数sha3_224_init/sha3_256_init/sha3_384_init/sha3_512_init均为头文件中的static inline实现其本质只是为struct __sha3_ctx设置digest_size与block_size两个字段见 include/crypto/sha3.h 第 116-170 行。最终摘要的长度由所调用的初始化函数决定因此sha3_final的out缓冲区必须至少容纳对应的SHA3_*_DIGEST_SIZE字节。文档特别强调sha3_final()在生成摘要后会自动清零zeroize上下文调用者无需也不应再手动清除头文件中的sha3_zeroize_ctx()内联函数仅供放弃上下文而不调用sha3_final()的异常路径使用其实现基于memzero_explicit()确保优化器不会消除清零操作static inline void sha3_zeroize_ctx(struct sha3_ctx *ctx) { memzero_explicit(ctx, sizeof(*ctx)); }XOF APISHAKE128/SHAKE256 的任意长度输出可扩展输出函数与摘要算法的核心区别在于输入长度固定、输出长度由调用方按需指定。文档 Extendable-Output Functions 一节给出了完整用法。一口式 APIvoid shake128(const u8 *in, size_t in_len, u8 *out, size_t out_len); void shake256(const u8 *in, size_t in_len, u8 *out, size_t out_len);out_len决定产生多少字节输出头文件 kernel-doc 注明所有输出长度均被支持All output lengths are supported。例如生成 64 字节伪随机输出#include crypto/sha3.h u8 out[64]; shake256(data, data_len, out, sizeof(out));增量式 API分块输入 分次挤压对于需要增量输入和/或增量输出的场景文档给出了基于struct shake_ctx的四步流程原文档第 88-109 行struct shake_ctx ctx; u8 out1[32], out2[64]; /* 1. 初始化 */ shake256_init(ctx); /* 2. 任意多次追加输入数据 */ shake_update(ctx, part1, len1); shake_update(ctx, part2, len2); /* 3. 按需分多次提取输出 */ shake_squeeze(ctx, out1, sizeof(out1)); shake_squeeze(ctx, out2, sizeof(out2)); /* 4. 全部输出提取完毕后显式清零上下文 */ shake_zeroize_ctx(ctx);使用上必须注意文档强调的三个语义约束多次挤压等价于单次挤压多次shake_squeeze的输出按顺序拼接在同一个缓冲区中与一次性请求等长输出的结果完全一致。这一点由 lib/crypto/tests/sha3_kunit.c 中的test_shake_multiple_squeezes测试用例专门验证——该测试随机生成输入/输出长度与挤压次数组合将多次挤压结果与一口式结果逐一比对挤压开始后不能再追加输入shake_update必须在第一次shake_squeeze之前调用完毕__sha3_update内部用WARN_ON_ONCE(absorb_offset block_size)对挤压已开始仍继续吸收的情况发出警告见 lib/crypto/sha3.c 第 206 行上下文需显式清零与摘要算法不同shake_squeeze不会自动清零上下文全部输出提取完毕后必须调用shake_zeroize_ctx()。从源码实现看shake_squeezelib/crypto/sha3.c 第 245-280 行在首次挤压时向状态写入域分隔后缀0x1f和末尾填充位0x80并将absorb_offset置为block_size以标记挤压已开始之后按需反复调用sha3_keccakf()并拷贝状态字节直到满足out_len为止。底层原理从 lib/crypto/sha3.c 看实现Keccak-f[1600] 置换SHA-3 的运算核心是 Keccak-f[1600] 置换状态为 200 字节25 个 64 位字依次执行 24 轮SHA3_KECCAK_ROUNDS每轮由 Theta、Rho、Pi、Chi、Iota 五个步骤构成。lib/crypto/sha3.c 第 52-156 行给出了完整的通用 C 实现sha3_keccakf_one_round_generic()第 38-47 行列出了 Iota 步骤使用的 24 个轮常数sha3_keccakf_rndc[]。状态的字序默认按小端保存在struct sha3_state中union同时提供__le64 words[25]、u8 bytes[200]和u64 native_words[25]三种视图这样吸收与挤压阶段可以直接把状态当作字节数组处理只有在执行置换前sha3_keccakf_generic()才将字转换为本机字节序置换完成后转回小端第 158-175 行。注释明确指出在小端机器上这套转换是空操作会被编译器优化掉。数据吸收absorb与域分隔/填充__sha3_update()第 200-230 行实现海绵结构的吸收阶段若上次残留数据与本次输入合并后达到一个块先 XOR 进状态并调用一次 Keccak 置换对完整块调用sha3_absorb_blocks_generic()第 181-191 行每块先与状态 XOR 再执行置换剩余不足一块的数据 XOR 进状态缓冲区记录absorb_offset供下次继续。摘要终结sha3_final()第 233-243 行在吸收完成后写入域分隔后缀0x06与填充位0x80对应海绵结构标准的多速率填充 pad10*1执行最后一次置换从状态中拷贝出digest_size字节作为摘要最后清零上下文。XOF 的域分隔后缀为0x1f在shake_squeeze()首次挤压时写入——这正是 FIPS-202 通过不同后缀区分摘要算法与 XOF、实现域分离的机制。一口式函数的内部路径一口式函数如sha3_224第 312-321 行的实现很直观先尝试架构优化路径sha3_224_arch()若架构不支持返回false则回退为 init → update → final 的增量调用组合。该模式在六个一口式函数中保持一致。架构加速与回退机制SHA-3 库预留了架构级优化钩子。CONFIG_CRYPTO_LIB_SHA3_ARCHlib/crypto/Kconfig 第 292-296 行在ARM64与S390上默认开启default y if ARM64/default y if S390。当该配置开启时lib/crypto/sha3.c 第 193-198 行会包含架构私有的$(SRCARCH)/sha3.h其中定义sha3_keccakf与sha3_absorb_blocks的优化实现以覆盖通用版本否则二者退化为sha3_keccakf_generic与sha3_absorb_blocks_generic。一口式函数的架构路径则更细粒度只要架构头文件提供了sha3_224_arch、sha3_256_arch等任一符号对应算法的一口式调用即可整体绕过通用代码路径未定义时由第 283-310 行的兜底内联函数返回false自动回退到通用实现。这种库层通用 架构可选覆盖的双层设计使 SHA-3 在 x86、ARM、S390 等平台都能获得恰当的性能表现同时保证任何架构都能以正确性优先的通用代码运行。与 crypto 模板 APIshash/ahash的关系文档 Overview 明确指出四个摘要算法除了库 API还通过crypto_shash与crypto_ahashAPI 向内核通用加密框架开放。这一层由 crypto/sha3.c 实现以CONFIG_CRYPTO_SHA3编译进内核crypto/Makefile 第 84 行。需要以算法名称如sha3-256动态查找哈希算法、或利用框架的异步/同步抽象时应使用模板 API而需要零依赖、符号级直接调用的场景如本文介绍的库 API则更加轻量。从 crypto/asymmetric_keys/x509_cert_parser.c、crypto/asymmetric_keys/pkcs7_parser.c 可以看到内核在处理 X.509 证书与 PKCS#7 消息时会依据 OID 将sha3-256/sha3-384/sha3-512识别为合法的签名摘要算法供证书与签名验证流程使用。测试与验证KUnit 套件与 FIPS 自测KUnit 测试sha3_kunit文档 Testing 一节给出的正式测试手段是启用CONFIG_CRYPTO_LIB_SHA3_KUNIT_TEST对应测试套件名sha3即文档所称的sha3_kunit。该配置定义于 lib/crypto/tests/Kconfig 第 144-152 行依赖KUNIT CRYPTO_LIB_SHA3测试源码为 lib/crypto/tests/sha3_kunit.c。lib/crypto/tests/sha3_kunit.c 的测试覆盖面相当完整基本正确性对固定样例消息The quick red fox jumped over the lazy brown dog! 重复 4 次验证 SHA3-224/256/384/512 与 SHAKE128/SHAKE256 的输出期望值通过openssl sha3-*生成并固化在测试向量中且每个测试缓冲区前后都设置了 8 字节守卫区可捕获越界写NIST 官方向量test_shake128_nist/test_shake256_nist使用 NIST 示例值验证空输入与 1600 字节0xa3重复输入的 SHAKE 输出test_nist_1600_sample全长度扫描test_shake_all_lens_up_to_4096对 SHAKE128/SHAKE256 遍历输入长度 0~4096、输出长度按(in_len * 293) % (max_len 1)变化的全部 4096 种组合将所有输出拼接后计算 SHA3-256 摘要并与预计算的shake*_testvec_consolidated比对多次挤压一致性test_shake_multiple_squeezes随机拆分挤压次数验证多次挤压与单次挤压结果一致2000 次随机迭代守卫页测试test_shake_with_guarded_bufs将输入/输出缓冲区置于未映射页之前专门捕捉汇编代码中的越界访问性能基准套件末尾的benchmark_hash提供 SHA-3 的基准测试能力由CRYPTO_LIB_BENCHMARK_VISIBLE控制可见性。此外SHA3-256 还通过hash-test-template.h通用模板驱动了一组独立用例HASH_KUNIT_CASES复用框架级哈希测试逻辑。FIPS 模式自测由于 SHA-3 算法通过 FIPS 认证当内核以 FIPS 模式启动时SHA-3 库还会执行一次简单的自测文档 Testing 一节对此有明确说明这纯粹是为了满足 FIPS 要求。实现位于 lib/crypto/sha3.c 第 382-402 行sha3_mod_init()在fips_enabled时对内置的fips_test_data计算 SHA3-256 摘要与 lib/crypto/fips-sha.h 中固化的期望值fips_test_sha3_256_value比对不一致则直接panic(sha3: FIPS self-test failed)。注释说明按 FIPS 实现指南测试任意一个 SHA-3 算法即可满足所有 SHA-3 算法的测试要求。文档建议内核开发与集成人员以覆盖面更广的 KUnit 套件作为常规回归手段而非依赖这个精简自测。内核中的实际使用案例SHA-3 库 API 在内核中已有真实的生产使用者jitterentropy 噪声源crypto/jitterentropy-kcapi.c 引入crypto/sha3.h在jent_hash_time()中使用struct sha3_ctx对时间戳与附加数据做哈希为抖动熵源提供内存健康检查等场景的哈希能力并借助sha3_final()自动清零的语义安全地处理临时上下文签名与证书验证如前述crypto/asymmetric_keys/ 子系统的 X.509、PKCS#7 解析器以及 ECDSA 验签路径crypto/asymmetric_keys/public_key.c均接受sha3-256/384/512作为签名摘要算法。这些案例说明SHA-3 库 API 既适合随机数、熵源等基础子系统做轻量内联调用也通过模板 API 深度服务于内核的证书信任链与签名校验体系。总结Linux 内核的 SHA-3 算法库围绕 Keccak 海绵函数提供了完整且层次分明的实现一口式与增量式 API 覆盖摘要SHA3-224/256/384/512与可扩展输出函数SHAKE128/SHAKE256的全部使用场景域分隔后缀0x06/0x1f与填充位的处理严格遵循 FIPS-202架构级钩子ARM64/S390与通用回退路径兼顾性能与可移植性KUnit 套件全长度扫描、多次挤压一致性、守卫页与 FIPS 模式自测共同保障正确性。内核模块开发者可根据实际场景在直接链接库 API与使用 shash/ahash 模板之间做出合适选择并参考本文的代码示例与参数表快速上手。【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考