随机数生成
来自 wikipedia:Random number generation
- 随机数生成器 (RNG) 是一种计算或物理设备,旨在生成一个没有模式(即看起来随机)的数字或符号序列。
随机数据的生成对于许多应用至关重要,例如创建加密密钥(例如用于 静态数据加密)、安全擦除磁盘,以及运行加密的 软件接入点。
内核内置 RNG
Linux 内核的内置 RNG 产生加密安全的伪随机数据。它通过从各种来源收集 熵 (entropy) 来工作,例如硬件 RNG、中断和基于 CPU 的抖动熵 (jitterentropy)。它不完全依赖于单一的熵源。熵使用 BLAKE2s 加密哈希函数 提取,并用于为一组提供实际随机数据的 ChaCha20 CRNG(加密随机数生成器)提供种子。只要内核在运行,就会持续收集熵,并定期重新为 CRNG 播种。
Linux RNG 为用户空间提供了三种获取随机数据的接口:
- getrandom(2) 系统调用
/dev/random/dev/urandom
在历史上,/dev/random 被认为比 /dev/urandom 提供更强的随机数。然而,/dev/random 和 /dev/urandom 的行为随着时间的推移已显著趋同,并且在 x86-64 系统上它们现在是等价的。由于 Arch Linux 仅支持 x86-64,因此 /dev/random 和 /dev/urandom 在 Arch Linux 上是等价的。(这是因为所有 x86-64 CPU 均具备 RDTSC 指令,这意味着 基于 CPU 的抖动熵算法 始终能够生成熵,更不用说大多数 x86-64 CPU 还支持 RDRAND。)
在其他架构上(特别是没有快速周期计数器的架构),两者之间仍有一个区别:/dev/random 会阻塞,直到内核估计 CRNG 已正确初始化,而 /dev/urandom 则不会。因此,在一般情况下,用户和应用程序仍应遵循传统指南,在生成长期加密密钥时使用 /dev/random,或者使用默认行为与 /dev/random 类似的 getrandom(2)。
请注意,由于 /dev/random 不再旨在提供真正的随机数据,而仅是提供加密安全的随机数据(这足以满足所有实际应用场景),因此从其中读取不再会导致内核熵池耗尽。因此,/proc/sys/kernel/random/entropy_avail 应该始终包含 256,即 ChaCha20 密钥的位数大小。可以忽略那些预期该文件具有较大值,或者预期用户在值变得“过低”时采取行动的历史文档。
替代方案
不需要加密安全随机数的应用程序可以简单地使用非加密随机数生成器,例如 random(3)。
对于确实需要加密安全随机数的应用程序,通常除了内核 RNG 之外不需要其他任何东西。在历史上,内核 RNG 相当慢,且未能充分利用尽可能多的熵源。然而,它后来得到了改进,在 x86-64 上可提供约 400 MB/s 的吞吐量,并能利用更多的熵源。即使对于需要相当高吞吐量随机数的情况,例如 安全擦除磁盘,简单地从 /dev/urandom 读取即可正常工作。
不直接使用内核 RNG 且有意义的情况包括:
- 在极少数情况下,应用程序需要具有极高吞吐量或极低延迟的加密安全随机数,此时系统调用的开销是不可容忍的。用户空间 CRNG 可以解决这个问题。用户空间 CRNG 应该由内核 RNG 提供种子,以确保其安全性至少与内核 RNG 一样(除重新播种等考虑因素外)。
- 某些应用程序运行在已经有成熟 API 使用用户空间 CRNG 生成加密安全随机数的领域。例如,当应用程序使用 OpenSSL 时,使用 OpenSSL 的 RAND_bytes(3) 可能是合理的。当应用程序用 Java 编写时,使用
java.security.SecureRandom可能是合理的。通常,这些 API 底层的用户空间 CRNG 会自动使用内核 RNG 进行播种。
- 如果你想使用尚未包含在内核 RNG 中的额外熵源,那么不直接使用内核 RNG 可能是合理的。例如,Haveged 可以提供使用抖动熵生成的随机数据。如果可能,额外熵源不应取代内核 RNG,而应与之结合使用,通过额外熵源和内核 RNG 同时为用户空间 CRNG 提供种子。也可以向
/dev/random写入额外的熵以使其被纳入内核 RNG,但由于内核 CRNG 的重新播种计划,这可能需要最多 60 秒才能生效。注:内核已经使用 RDSEED 和其他硬件随机数生成器作为熵源。
参见
- 内核 RNG 改进
- random: replace non-blocking pool with a Chacha20-based CRNG - 引入 ChaCha20 CRNG (2016)
- random: try to actively add entropy rather than passively wait for it - 使基于 CPU 的抖动熵可作为后备方案使用 (2019)
- Removing the Linux /dev/random blocking pool - 使
/dev/random像/dev/urandom一样使用 CRNG,而不再尝试提供“真正的”随机性 (2020) - Linux 5.17 和 5.18 的随机数生成器增强 (2022)
- random: use simpler fast key erasure flow on per-cpu keys - 简化并优化了 CRNG 设计 (2022)
- random: do not pretend to handle premature next security model - 使新熵能被更快速地利用 (2022)
- random: opportunistically initialize on /dev/urandom reads - 使
/dev/urandom在 x86 上与/dev/random一样安全 (2022)
- Randomness - 解释不同 RNG 的科普文章
- ENT - 一个用于测试随机序列的简单程序(熵、卡方检验、蒙特卡罗、相关性等)
- An Analysis of OpenSSL's Random Number Generator - 关于 OpenSSL 功能中 RNG 重新播种风险的论文