密钥生成与随机数源:真随机数生成器(TRNG)、伪随机数生成器(PRNG)、熵源管理

各位同学,今天我们聊点真正核心的东西——密钥怎么来的。你想想看,HSM 整个安全体系,密钥就是最底层的那块砖。如果这块砖是空心甚至假的,上面堆再高的防护墙也没用。所以密钥生成的质量,直接决定了整个系统的安全底线。

我自己做 HSM 设计这么多年,见过太多以为随机数“差不多就行”的项目,结果被攻击者从随机源攻破整条防线。嗯,这里面的坑,我今天一次性给大家讲清楚。

密钥生成的根基——随机数

HSM 里的密钥,本质上就是一串二进制位。但问题在于:这串二进制位必须同时满足两个条件——“不可预测”和“唯一性”。说白了,攻击者算不出你接下来会生成什么密钥,你的密钥也不能跟别人的重复。

我见过一个很典型的案例:某款设备因为 TRNG 的熵源电路设计有问题,实际输出的随机数呈现出周期性规律,攻击者只需要采集几百个样本就能用线性回归模型预测后续密钥。这就是基础没打好的代价。

随机数生成器主要分两类:真随机数生成器(TRNG)和伪随机数生成器(PRNG)。它们各有各的用武之地,但千万别搞混。

维度 TRNG PRNG
熵来源 物理现象(热噪声、量子效应等) 确定性算法 + 种子
输出可预测性 理论上不可预测 种子保密则不可预测
输出速率 较低(c-c几kbps到Mbps) 极高(百Mbps以上)
用途 种子生成、密钥直接输出 大量会话密钥生成
硬件依赖 必须专用模拟电路 可纯软件实现

真随机数生成器(TRNG)——物理世界的噪声

TRNG 的核心思想,就是把物理世界中不可预测的随机性“翻译”成二进制位。常用的物理源包括:

  • 热噪声:电阻或晶体管中的电子热运动
  • 振荡器抖动:环形振荡器频率的微小波动
  • 量子效应:如 PN 结的散粒噪声
  • 大气噪声:射频接收器捕获的环境电磁辐射

我自己设计 TRNG 时,习惯用 振荡器采样法 作为基础结构。原理很简单:一个慢速振荡器去采一个快速振荡器的相位。因为慢速时钟的每次采样点都不同,而快速振荡器的抖动会累积,导致采样结果不可预测。

// 简化的 TRNG 核心结构示意(Verilog)
module trng_core(
    input  wire clk_slow,   // ~100kHz 慢时钟(带抖动)
    input  wire clk_fast,   // ~500MHz 快速环形振荡器
    output reg  rnd_bit
);

    reg [2:0] sync_ff;
    
    always @(posedge clk_fast) begin
        sync_ff <= {sync_ff[1:0], clk_slow};
    end
    
    always @(posedge clk_fast) begin
        // 每次采样都会因为抖动产生随机位
        rnd_bit <= sync_ff[2] ^ sync_ff[1];
    end
endmodule

但注意!这个结构存在一个经典问题:偏置(bias)。如果慢时钟的占空比不是 50%,输出的随机位就会向 0 或 1 倾斜。我曾在客户的芯片上遇到过这种情况——实际测试出来的“随机”序列里 0 的比例高达 65%。

经验之谈:TRNG 输出一定要过 后处理(post-processing)。最简单的方案是用 Von Neumann 纠正器:连续采两比特,如果相同则丢弃,如果不同则取第一个比特。这会消除静态偏置,但输出速率会减半。

伪随机数生成器(PRNG)——确定性的“伪随机”

PRNG 不产生真正的熵,它只是用确定性算法“扩频”一个初始种子。但为什么要用它?说白了,TRNG 太慢了,HSM 每秒可能需要生成成千上万条密钥,TRNG 根本跟不上。这时候 PRNG 就派上用场了。

HSM 设计中,我推荐使用 NIST SP 800-90A 标准中定义的 DRBG(Deterministic Random Bit Generator),具体包括:

  • CTR_DRBG:基于分组密码(如 AES-256)的计数器模式
  • Hash_DRBG:基于哈希函数(如 SHA-256/512)
  • HMAC_DRBG:基于 HMAC 的构造

这三种各有优劣,我挑重点说:

DRBG 类型 速度 安全强度 硬件面积 我的选择建议
CTR_DRBG 非常快 256 bit 中等 HSM 主选
Hash_DRBG 中等 256 bit 小 面积受限场景
HMAC_DRBG 较慢 256 bit 大 FIPS 认证首选

我个人习惯在 HSM 中使用 CTR_DRBG 作为主 PRNG,因为它的硬件实现效率极高。你想想看,一次 AES 加解密就能产生 128 位随机数,而且可以流水线起来,速率轻松跑到 Gbps 级别。

// CTR_DRBG 核心状态更新逻辑(伪代码)
state = AES_encrypt(V, key)
// 每次输出后更新 V 和 key
V = V + 1
key = AES_encrypt(V xor constant, key)

避坑指南:PRNG 的安全性完全取决于种子的质量。我曾经见过一个“移植”来的 PRNG 实现,开发者在 PCB 上直接用一条长走线当天线来“采集熵”,结果 EMC 测试时发现这个天线把系统时钟谐波也耦合进来了,PRNG 输出的随机性大打折扣。正确的做法是:PRNG 种子必须来自经过健康检查的 TRNG 输出。

熵源管理——别让你的随机数“枯竭”

熵源管理是一门平衡的艺术。HSM 里的 TRNG 就像一口井,你不能无节制地抽,否则可能抽到混着泥巴的水(低质量随机数)。

熵源管理的核心三原则:

  1. 持续监测:实时统计 TRNG 输出的熵率,低于阈值时报警或封堵输出
  2. 定期重播种:每生成一定量的密钥后,强制用 TRNG 的新输出更新 PRNG 的种子
  3. 熵池设计:建立一个中间缓冲层,TRNG 持续往池里注水,PRNG 从池里取水,避免直接耦合

我参与过的一个 FIPS 140-3 Level 3 项目里,我们设计了一个四层熵池架构:

物理熵源 → 健康测试单元 → 数据压缩(去偏) → 熵池(FIFO) → PRNG种子更新

每次健康测试单元会跑两个检查:一阶矩(均值偏移)和二阶矩(自相关异常)。任何一个测试连续三次失败,整个 TRNG 就被标记为“不可用”,系统会自动切到备份熵源。

关键数据:一个合格的 HSM 熵源管理模块,必须保证 TRNG 的有效输出熵率不低于 0.997 bit/bit。低于这个值,就意味着存在可被利用的统计偏置。

来看看完整的密钥生成流程,我用一张图帮你理清脉络:

HSM 密钥生成 & 随机数源架构 物理熵源 热噪声 / 量子效应 健康测试单元 一阶矩 / 自相关 后处理去偏 Von Neumann / XOR 熵池(FIFO) 512-bit 深度 定期注入 PRNG 种子更新 从熵池提取 256 bit CTR_DRBG AES-256 扩频输出 密钥输出 AES/KECCAK/HMAC 密钥 注意:安全边界 熵池到 DRBG 之间 必须物理隔离 防止侧信道耦合

最后,关于熵源管理,我必须强调一个常被忽视的点——冷启动熵源问题。HSM 刚上电时,内部的热噪声源还没稳定,振荡器抖动幅度不足,这时候直接生成密钥非常危险。

我曾经遇到过一台 HSM 样机,每次冷启动后前 1000 个密钥都是可预测的。排查了三天才发现问题:熵源电路的偏置电压建立时间太长,导致前 200ms 内的 TRNG 输出几乎全零。解决方案是在电源管理模块里加一个“熵源就绪”信号,TRNG 输出在被健康测试确认合格之前,输出门必须保持关闭。

在实际工程中,我建议的熵源管理策略包括:

  • 硬件层面:两个独立的 TRNG 物理源做 XOR 迭合,哪个坏了都不怕
  • 启动阶段:250ms 预热期 + 健康测试收敛确认
  • 运行阶段:每 1 秒用 TRNG 重播种 PRNG
  • 异常处理:连续三次健康测试失败,触发安全中断,密钥生成模块锁定

嗯,关于密钥生成与随机数源,最重要的就是一句话:永远不要相信“看上去随机”的数据,要相信经过严格测试的熵。 下节课我们来聊密钥的生命周期管理,从摇篮到坟墓的整个过程。