随机数生成
来自 wikipedia:Random number generation
- 随机数生成器 (RNG) 是一种计算或物理设备,旨在生成缺乏任何模式的数字或符号序列,即看起来是随机的。
随机数据的生成对于多种应用至关重要,例如生成加密密钥(例如用于静态数据加密)、安全擦除磁盘、运行加密的 软件接入点。
内核内置 RNG
Linux 内核的内置 RNG 生成密码学安全的伪随机数据。它的工作原理是从各种来源收集熵,例如硬件 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 的 jitterentropy 算法 将始终能够生成熵,更不用说大多数 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 一样安全,但要考虑重新播种等因素。
- 一些应用程序在已经为使用用户空间 CRNG 生成密码学安全随机数建立了完善的 API 的领域中工作。例如,当应用程序使用 OpenSSL 时,使用 OpenSSL 的 RAND_bytes(3) 可能是有意义的。当应用程序用 Java 编写时,使用
java.security.SecureRandom
可能是有意义的。通常,这些 API 下的用户空间 CRNG 会使用内核 RNG 自动播种。
- 如果您想使用尚未并入内核 RNG 的其他熵源,则不直接使用内核 RNG 可能会有意义。例如,Haveged 可以提供使用 jitterentropy 生成的随机数据。如果可能,额外的熵源不应取代内核 RNG,而应通过从额外的熵源和内核 RNG 播种用户空间 CRNG 来与内核 RNG 结合使用。也可以将额外的熵写入
/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 的 jitterentropy 被用作后备 (2019)
- Removing the Linux /dev/random blocking pool - 使
/dev/random
使用 CRNG,就像/dev/urandom
一样,并且不尝试提供“真正”的随机性 (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 重新播种风险的论文