3、密钥生成策略与安全要求:随机数生成器、密钥长度、算法选择

密钥生成,说实话是整个生命周期里最容易“看起来没问题,实际埋雷”的环节。我从业头几年,就见过一家公司用的随机数生成器其实是个伪随机算法,密钥长度虽然够长,但生成出来的序列有规律——你想想看,这等于把保险柜密码写在墙上了。所以今天咱们把这张底牌摊开,讲清楚随机数、密钥长度和算法选型这三个硬骨头怎么啃。

我会先画一张总览图,让你对这三个要素之间的关系有个底。然后逐个拆解。

密钥生成策略核心要素 随机数生成器 密钥长度 算法选择 真随机 vs 伪随机 最小安全长度 对称 / 非对称 / 哈希 熵源 / 测试 / 随机性 NIST / 国密 / 行业标准 性能 / 兼容 / 合规 策略映射:业务场景 → 算法 → 随机源 → 长度 → 测试 → 归档

随机数生成器:真随机 vs 伪随机,你没得选

我见过最典型的事故是:一个金融交易系统用的密钥生成器是 C 语言的 rand(),种子的时间戳精度只到秒。你想想看,攻击者只要知道交易的大概时间窗口,就能把全套密钥穷举出来。后来我们审计时,他们技术负责人脸都绿了——这其实是个认识误区:很多人觉得“随机数嘛,看着乱就行”。

实际上,密码学要求的是不可预测性。真随机数生成器(TRNG)依赖物理熵源,比如硬件噪声、量子效应。伪随机数生成器(PRNG)则是通过算法扩展种子——但种子必须是真随机的。大部分系统用的方式是用操作系统提供的随机池(/dev/urandom、CryptGenRandom),这类接口已经综合了硬件熵源,可以认为是“接近真随机”的。

随机数类型熵来源安全性常见场景
真随机(TRNG)物理噪声、量子效应最高,不可预测生成主密钥、硬件安全模块(HSM)
伪随机(PRNG)算法 + 种子取决于种子熵会话密钥、IV 向量
混合型PRNG + 定期 reseed高,推荐企业使用大多数密码库(OpenSSL, Bouncy Castle)
个人习惯: 我建议生产环境一律走操作系统提供的 CSPRNG 接口,别自己写随机数池。以前有个项目,研发图省事直接用 Java 的 java.util.Random 生成 AES 密钥——我直接打了回票。

密钥长度:不是越长越好,但太短肯定不行

密钥长度直接决定了暴力穷举的难度。不过,你想想看,如果算法有结构性弱点,再长也没用——比如 DES 的 56 位密钥,就算你加长到 64 位,它的 S 盒设计缺陷照样能被差分攻击打穿。所以长度必须跟算法绑定来看。

我给几个当前公认的最低安全长度(基于 NIST SP 800-57 和国密标准):

算法类型推荐最小长度等效安全级别备注
AES(对称)128 位128 位256 位用于高安全场景
RSA(非对称)2048 位~112 位4096 位性能开销大,需评估
ECC(椭圆曲线)256 位128 位推荐 P-256 / secp256r1
SM2(国密)256 位128 位国内合规必须使用
共享密钥(HMAC)128 位128 位建议 ≥ 256 位
我曾经踩过一个坑: 有个客户从老系统迁移时,RSA 密钥还是 1024 位。我建议升级,他们觉得够用。结果半年后行业内爆出 1024 位 RSA 被学术界成功分解的——虽然那篇针对的是一类弱密钥,但要是我当时坚持换掉,风险会小很多。现在 1024 位在很多合规框架里已经被明确禁止了。

算法选择:别追新,也别守旧

说到算法选型,我见过两种极端:一种是死抱着 3DES 不撒手的老系统,另一种是看到新算法就往上冲——前些年有人直接上 Post-Quantum 候选算法,结果标准都没定,后来不得不全部返工。我个人觉得,合适的做法是“成熟优先,关注迁移”。

  • 对称加密: AES-256 是目前最稳妥的,优先使用 GCM 模式(认证加密)。不要再用 ECB 模式——我见过生产环境因为 ECB 模式泄露图片轮廓的案例。
  • 非对称加密: 签名用 ECDSA(P-256),密钥交换用 ECDH。RSA 适用于兼容性要求高的场景,但尽量不低于 2048 位。
  • 哈希算法: SHA-256 起步,SHA-3 可作为备选。千万别再用 SHA-1 签名——2017 年 Google 和学术界已经实现了 SHA-1 碰撞攻击。
  • 国密算法: 在国内政务、金融等合规场景下,必须使用 SM2/SM3/SM4。我建议将这些算法和标准算法并存,通过策略配置切换,而不是硬编码。

一个实用原则: 选用算法时,优先考虑库层面的支持情况和侧信道抗性。比如同样的 AES-256,用硬件指令(AES-NI)实现比纯软件实现快 10 倍以上,而且不易受时序攻击。

随机性质量检验:你不能假装看不见

密钥生成完了,怎么确认它真的“随机”?我在项目中见过不少人直接复用随机数生成器的输出,从不做质量检验。实际上,NIST 提供了 SP 800-22 随机性测试套件,里面包括频数检验、游程检验、块内频数检验等 15 项。企业级环境中,至少应该做以下三项基本检验:

  1. 频数检验 (Monobit Test) — 检查 0 和 1 的比例是否接近 1:1。
  2. 块内频数检验 (Block Frequency Test) — 在每个固定块内检查比例。
  3. 游程检验 (Runs Test) — 检查连续相同位的长度分布。

你不需要每次生成都跑全套,但在密钥生成器的首次部署和源变更(比如替换熵源)后必须跑一遍。我习惯在 CI/CD 流程中加入 nightly 随机性测试,一旦失败就告警。

避坑: 我曾经接手一个项目,他们为了“加快密钥生成”,从 MySQL 的 RAND() 函数取种子。这个函数是线性同余生成器,周期只有 2^32——等于给攻击者提供了一个 32 位的搜索空间。后来我们换成了 getrandom() 系统调用,问题才根治。

小结:把生成策略写进规范

密钥生成不是一次性的技术决定。你需要把它固定成可执行的规范:用什么随机源、长度下限是多少、算法白名单是什么、部署前要做什么测试。我通常会在安全架构评审中要求团队提供一份《密钥生成策略映射表》,把业务场景和上述三个要素一一对应。这样即使人员更替,决策逻辑也不会丢失。

说实话,大多数安全事件不是因为密码学被攻破,而是在生成环节留下了后门。所以你想想看,你手里的密钥生成流程,经得起一次红队演练吗?