密钥生成策略:从熵源到算法选择

密钥生成,是整个密钥生命周期里最基础也最容易出问题的一环。我见过不少项目,加密算法选得很强,密钥长度也够,结果一查——密钥是用 rand() 生成的。嗯,那基本等于没锁门。

这一节我们重点聊两件事:真随机数生成器(TRNG)和伪随机数生成器(PRNG)到底差在哪,以及在实际工程里怎么选、怎么用。

TRNG vs PRNG:核心差异

先给个直观对比。你想想看,TRNG 是从物理世界「采集」随机性,比如热噪声、量子效应、放射性衰变。PRNG 则是用算法「模拟」随机性,给它一个种子,它就能源源不断地吐出看起来随机的数。

特性 TRNG PRNG
熵来源 物理过程(热噪声、时钟抖动等) 算法 + 种子
输出是否可预测 不可预测(理论上) 种子已知则可预测
输出速率 慢(通常几十 Kbps ~ 几 Mbps) 快(可达 Gbps 级别)
硬件依赖 需要专用硬件 纯软件即可
典型用途 生成种子、密钥材料 派生密钥、IV、nonce

说白了,TRNG 是「真随机」,但慢且贵;PRNG 是「假随机」,但快且便宜。实际工程里,两者是配合使用的,不是二选一。

TRNG:物理熵源的采集与挑战

TRNG 的核心是熵源。常见的物理熵源包括:

  • 热噪声:电阻或二极管的热噪声,放大后采样
  • 时钟抖动:两个独立振荡器之间的相位差
  • 量子效应:光子到达时间、隧穿效应
  • 放射性衰变:虽然可靠,但不太实用

我在一个 IoT 安全芯片项目里遇到过一个问题:芯片内部的 TRNG 模块在量产测试时,有大约 0.3% 的样本熵源输出偏了。后来排查发现,是晶圆工艺偏差导致热噪声放大器的增益不一致。嗯,硬件随机数生成器不是焊上去就能用的,必须做在线熵源健康检测。

注意:TRNG 的输出不能直接当密钥用。物理熵源可能受温度、电压、老化影响,输出质量会波动。标准做法是:TRNG 输出先经过去偏(如 Von Neumann 校正)和哈希提取(如 SHA-256),再作为种子或密钥材料。

PRNG:算法选择与安全等级

PRNG 分两类:密码学安全 PRNG(CSPRNG)和非密码学 PRNG。前者用于密钥生成,后者只适合模拟、测试等非安全场景。

常见的 CSPRNG 算法有:

  • Hash_DRBG(基于哈希函数,如 SHA-256)
  • HMAC_DRBG(基于 HMAC)
  • CTR_DRBG(基于分组密码,如 AES-256-CTR)
  • ChaCha20-based DRBG(流密码方案)

我个人习惯在服务端优先用 CTR_DRBG,因为它速度快,而且 AES 硬件加速指令(AES-NI)在主流 CPU 上都有。但在嵌入式环境里,如果芯片没有 AES 硬件,我会选 HMAC_DRBG,因为哈希函数通常有更小的代码体积。

经验之谈:不要自己实现 PRNG。标准库里的 /dev/urandom(Linux)、CryptGenRandom(Windows)、getrandom()(Rust)都是经过审计的 CSPRNG。除非你在做硬件安全模块(HSM)或嵌入式固件,否则直接用操作系统提供的接口就够了。

密钥生成的标准流程

一个安全的密钥生成流程,我建议至少包含以下步骤:

  1. 采集熵:从 TRNG 或系统熵池获取至少 256 位熵
  2. 熵提取:用哈希函数将熵压缩为固定长度的种子
  3. 种子注入:将种子安全地注入 CSPRNG
  4. 密钥派生:用 CSPRNG 生成所需长度的密钥材料
  5. 质量验证:对生成的密钥做统计测试(如 NIST SP 800-22)

我曾经在一个金融支付终端项目里,发现开发团队直接用 time(NULL) 做种子生成 RSA 密钥对。结果呢?同一秒内初始化的设备,生成的密钥完全一样。这个漏洞在安全审计时被标记为 Critical。从那以后,我对种子来源的检查就格外严格。

算法选择决策树

下面这张图是我在实际项目中总结的决策逻辑,你可以参考:

密钥生成算法选择决策树 密钥生成需求 有硬件 TRNG? 无硬件 TRNG TRNG 提取种子 熵池 + 哈希提取 系统熵池 (/dev/urandom) 多熵源混合 选择 CSPRNG 算法 有 AES-NI → CTR_DRBG 无硬件加速 → HMAC_DRBG 生成安全密钥 种子必须 ≥ 256 位 且不可重复使用

常见陷阱与避坑指南

这些年我踩过不少坑,挑几个典型的说说:

  • 种子重用:同一个种子生成多个密钥,等于所有密钥都相关。我曾经在代码里发现有人把种子写死在配置文件里——嗯,那跟没用加密差不多。
  • 忽略熵池枯竭:在容器或虚拟机里,系统熵池可能很小。启动时大量生成密钥,熵池被抽干,PRNG 会阻塞或降级。我建议在系统初始化时主动喂熵。
  • TRNG 输出直接当密钥:TRNG 原始输出可能有偏,必须经过提取。NIST SP 800-90B 对熵源有明确的健康测试要求。
  • 跨平台移植时忽略 PRNG 差异:Windows 的 CryptGenRandom 和 Linux 的 /dev/urandom 行为不同。我在一个跨平台 SDK 里吃过这个亏,后来统一封装了一层。
核心原则:密钥生成的安全,取决于最薄弱的环节。TRNG 再强,种子管理不当也白搭;CSPRNG 算法再安全,熵源被污染也没用。整个链路——熵源 → 提取 → 种子 → 派生 → 输出——每一步都要可审计、可测试。

标准与规范参考

如果你需要写安全规范或做合规审计,下面这几个标准是绕不开的:

  • NIST SP 800-90A:CSPRNG 算法标准(Hash_DRBG、HMAC_DRBG、CTR_DRBG)
  • NIST SP 800-90B:熵源健康测试与认证
  • FIPS 140-3:密码模块安全要求,包含密钥生成
  • BSI AIS 20/31:德国联邦信息安全局的随机数生成器评估标准

我个人习惯在项目初期就把这些标准列进需求文档里。别等到安全审计时才发现——那时候改起来成本就高了。