密钥生成审计:生成过程日志、随机数检测、合规性检查

密钥生成是整个SM2生命周期里最容易被忽视的一环。很多人觉得“生成密钥嘛,调个库就完事了”。但我在几次项目中踩过坑后才发现——生成那一刻没审好,后面一切审计都是空中楼阁。这一章咱们就聊聊密钥生成阶段的三项硬核审计点:日志记录、随机数质量、合规性检查。

1. 生成过程日志 —— 审计的“黑匣子”

为什么非要把日志单独拎出来?因为密钥生成是不可逆操作,一旦过程有纰漏,你没法让时光倒流。日志就是唯一的还原现场工具。我个人习惯要求日志必须包含以下关键字段:

字段 说明 示例
时间戳 高精度UTC时间,含毫秒 2025-04-07T08:32:17.823Z
操作标识 生成操作用UUID唯一标记 gen-uuid-a1b2c3...
密钥标识 生成的密钥公钥/ID SM2-key-20250407-001
随机数源 硬件/软件RNG,熵池哈希值 hw-rng: sha256(entropy)=...
随机数检测结果 检测项、统计量、P-value 频数检测: P=0.43 通过
操作者/系统 调用方身份或服务名称 kms-srv-03@internal
审计签名 整个日志记录的HMAC hmac_sha256(k, log_data)

这里有个细节:日志必须是写前日志(Write-Ahead Log),而不是事后补录。我见过有些系统先生成密钥再写日志,结果生成过程中断电,日志丢了,密钥却已经写入了存储——这就没法审计了。逻辑应该是:先落日志,再执行生成,生成成功更新日志状态为完成。

2. 随机数检测 —— 别信“随机”是随机的

SM2密钥的随机数质量直接影响安全性。你以为操作系统自带的 /dev/random 就够用了?实际上很多嵌入式环境或容器环境下的熵池可能严重不足。我参与过的一个IoT项目,就是因为随机数源用的默认软件RNG,生成的密钥对居然有重复——概率极低,但确实发生了。从那以后,我对随机数检测有了执念。

国密标准GM/T 0005-2021《随机性检测规范》规定了15项检测,但审计时通常只要求覆盖以下核心项:

  • 频数检测(Monobit Test)—— 看0和1的比例是否接近 1:1
  • 游程检测(Runs Test)—— 检查连续相同比特的长度分布
  • 块内频数检测(Block Frequency Test)—— 分块看比例
  • 近似熵检测(Approximate Entropy)—— 检测重复模式的复杂度
  • 累加和检测(Cumulative Sums)—— 检测正向/反向偏移

一般做法是:取至少1Mbit的随机数样本,调用检测工具(如国密推荐的 GRND_Tester 或开源工具 dieharder),每个检测项输出P-value。只有当P-value ≥ 0.01时才算通过。审计时需检查原始检测报告,不能只看“通过”二字——要确认样本量、检测参数是否合规。

代码示例(伪代码,实际调用需根据具体库调整):

# 从HWRNG读取1Mbit随机数
random_bits = hw_rng.read_bits(1024 * 1024)  

# 调用国密检测工具
for test in [monobit, runs, block_freq, approx_entropy, cumsum]:
    result = gm_random_tester(test, random_bits)
    audit_log.append(f"{test.name}: P-value={result.p_value}")
    if result.p_value < 0.01:
        raise AuditFailure(f"随机数检测失败: {test.name}")
提示: 不需要每次生成密钥都跑全量检测。一般建议:每次启动时检测一次、每生成1000个密钥重新检测一次,或在熵池状态变化时(如热插拔硬件RNG)触发检测。审计时检查这些触发条件的覆盖性。

3. 合规性检查 —— 对着一纸清单打勾

合规性检查说白了就是对着标准一条条核对。我建议把检查项做成表格,每次生成密钥后自动生成检查报告。以下是SM2密钥生成审计的典型检查清单:

检查项 依据标准 通过条件
随机数源认证 GM/T 0012-2020 硬件RNG通过FIPS140-2 Level 2或经国密认证
密钥长度 GB/T 32918.1-2016 SM2密钥长度256位
密钥参数验证 GB/T 32918.1-2016 基点G、阶n、余因子h正确
随机数通过检测 GM/T 0005-2021 P-value ≥ 0.01 且样本量≥1Mbit
日志完整性 内部审计策略 日志已签名,且写入在生成前
密钥生成环境 等保2.0三级 在物理隔离环境中执行,无网络暴露

每一条检查都应当有证据:比如硬件RNG的认证证书扫描件、检测报告PDF、日志记录哈希等。没有证据的检查等于没做——这是我被审计老师傅怼过后才明白的。

4. 避坑指南:我踩过的三个坑

  • 坑一:随机数检测过了,但密钥对仍然弱。 我曾经遇到一个情况:随机数序列本身质量没问题,但密钥生成算法(SM2点乘)实现有bug,导致部分私钥落在小阶子群。后来我们增加了密钥参数验证(检查私钥是否小于群阶n,公钥是否在曲线上),这才堵住漏洞。
  • 坑二:日志签名用的密钥和业务密钥混用。 嗯,这是典型的设计问题。日志签名密钥一旦泄露,攻击者就可以伪造任意日志。必须单独派生一个审计签名密钥,并且与业务密钥隔离存储。
  • 坑三:只看单次检测P-value,不看趋势。 每次生成都检测,P-value忽高忽低属正常。但如果你把100次检测的P-value画成直方图,发现它们严重偏离均匀分布——那就说明随机数源有问题,即使每次都能通过阈值。所以审计报告里最好附带P-value分布图(当然,手动审查时可只看统计摘要)。
警告: 任何时候都不应使用系统自带的库函数 rand() 或 random() 生成密钥随机数。它们不是密码学安全随机数生成器(CSPRNG)。我在一个遗留系统里见过这种用法,直接导致私钥可预测——还好那只是个测试环境,不然后果不堪设想。
密钥生成审计流程 密钥生成审计核心流程 生成与检测域 合规与记录域 1. 密钥生成请求 2. 获取随机数(硬件RNG) 3. 随机数检测 4. 生成SM2密钥对 密钥+日志 5. 合规性检查 6. 生成过程日志(WAL) 7. 日志签名与归档 审计可全程追溯

上面这个流程图把密钥生成审计分成了两个域:左侧是生成与检测,右侧是合规与记录。注意第6步“生成过程日志”必须放在随机数检测和密钥生成之后、签名归档之前,并且采用WAL策略。我记得有一次合规审查,对方要求展示整个过程的时间轴——有了这个流程和对应的日志,几分钟就讲清楚了。

核心总结:密钥生成审计不是单纯检查“有没有日志”,而是要看日志是否在生成操作之前写出、随机数是否经过标准检测、合规检查项是否有证据支撑。这三点做到位,生成阶段的审计基本就稳了。如果时间允许,建议定期做一次回归式随机数检测——比如每个月把硬件RNG的熵源拿去做一次全面检测,而不是只依赖生成时的快速检测。这样即使某次生成时检测通过但长期趋势异常,也能尽早发现。