第4章:密钥生成的最佳实践
密钥生成这事儿,看着简单,坑可不少。我早年做密钥管理项目时,有次发现生成的RSA密钥对居然有规律——排查半天,问题出在随机数生成器上。嗯,从那以后我养成了个习惯:先问三个问题——随机源靠谱吗?熵够不够?算法选对了吗?
4.1 随机数生成器:硬件还是软件?
说白了,密码学里的随机数不能“真随机”。我们需要的是密码学安全的伪随机数生成器(CSPRNG)。为什么?因为真随机数生成器依赖物理熵源,速度慢、输出不稳定;而CSPRNG基于种子,用加密算法扩展,既快又不可预测。
我建议区分两种场景:
- 系统级生成器:Linux的
/dev/urandom、Windows的CryptGenRandom、macOS的arc4random。这些已经经过安全评审,普通密钥生成直接用就行。 - 硬件随机数生成器(HRNG):比如Intel的RDRAND/RDSEED指令、TEE芯片内置的TRNG。适合对速度或独立性要求高的场景,比如嵌入式设备、HSM。
rand()或random()生成密钥——那玩意儿是线性同余生成器,周期短、可预测。密钥被猜中只是时间问题。记住:普通语言的Math.random()一律不准用于密码学。
4.2 熵源:质量决定一切
生成器的种子质量,取决于熵源。熵不够,密钥强度就虚。你想想看,如果种子只有32比特,那无论你后面怎么扩展,有效安全强度也不会超过32比特。
实际项目中,熵源通常来自:
| 熵源类型 | 典型例子 | 比特率 | 可靠性 |
|---|---|---|---|
| 物理噪声 | 热噪声、抖动 | 低(每秒几十比特) | 高 |
| 用户交互 | 鼠标移动、键盘按键时序 | 极低 | 中(易受测量偏差) |
| 网络事件 | 网卡中断时间、数据包到达间隔 | 中等 | 低(受环境干扰) |
| 专用硬件 | 独立TRNG芯片 | 高(Mbps级) | 非常高 |
4.3 生成算法选择:不同密钥不同打法
选算法要看密钥用途。对称密钥、非对称密钥、密钥派生,各自套路不一样。我习惯按三类来记:
4.3.1 对称密钥直接生成
最简单:直接从CSPRNG取随机字节。比如AES-256需要32字节,调用一次getrandom()就行。注意长度必须与安全强度匹配——别用128位密钥但你声称256位安全。
// C语言示例:使用Linux getrandom生成AES-256密钥
#include <sys/random.h>
#include <stdint.h>
uint8_t key[32];
if (getrandom(key, sizeof(key), 0) != sizeof(key)) {
// 处理失败,重试或终止
}
4.3.2 非对称密钥对生成
这个要依赖专门算法。RSA需要选大素数,ECC需要生成椭圆曲线上的点。标准库(OpenSSL、Bouncy Castle)内部已经处理了随机性,你只管指定算法和参数。但要注意:有些实现允许你自定义随机源,最好传一个高熵的接口引用。
RAND_bytes的回调,并提前垫了熵池。
4.3.3 派生密钥生成(PBKDF2/Argon2/HKDF)
从密码或共享秘密派生出密钥时,要用密钥派生函数(KDF)。注意:KDF需要加盐(salt),盐必须用CSPRNG生成,长度至少16字节。我一般生成32字节盐,这样即使遭遇彩虹表也能扛住。
# Python示例:使用os.urandom生成盐,再HKDF派生
import os
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
from cryptography.hazmat.primitives import hashes
salt = os.urandom(32) # 随机盐
hkdf = HKDF(
algorithm=hashes.SHA256(),
length=32,
salt=salt,
info=b'key-boundary-example',
)
derived_key = hkdf.derive(b'user_password')
4.4 知识结构图:密钥生成决策流
下面的SVG图总结了密钥生成的核心流程和决策点,方便你在方案设计时快速参考。
4.5 生成后的健康检查
密钥生成完别急着用。我习惯做三件事:
- 重复性检测:对比数据库中已有密钥的哈希,防止意外重复(概率极低,但HSM掉电重启可能重走种子)。
- 统计测试:用NIST SP 800-22测试集检查随机性。当然,生产环境不可能跑全套,但至少跑个FIPS 140-2连续测试。
- 熵源健康检查:记录生成时的熵估计值,低于阈值就告警。我曾经用
/proc/sys/kernel/random/entropy_avail监控Linux熵池,低于128就拒绝生成RSA密钥。
密钥生成看起来就几行代码,但每次调用都关系到整个系统的安全根基。别图省事,多花几分钟检查随机源、选对算法、跑一遍健康检查——这笔投入值得。