随机数生成

出自 ArchWiki
(重定向自随机数生成器

出自wikipedia:随机数生成

随机数生成器 (RNG) 是一种计算或物理设备,旨在生成一系列缺乏任何模式的数字或符号,即看起来是随机的。

随机数据的生成对于多种应用至关重要,例如生成加密密钥(例如用于静态数据加密)、安全擦除磁盘、运行加密的 软件接入点

内核内置 RNG

注意: Linux RNG 近年来得到了显著改进,在 4.x 和 5.x 内核系列中发生了许多变化。因此,关于它的许多现有信息已经过时。本页描述了当前的实现和行为,适用于包括 Arch Linux 官方支持的内核在内的现代内核。

Linux 内核的内置 RNG 生成密码学安全的伪随机数据。它的工作原理是从各种来源收集,例如硬件 RNG、中断和基于 CPU 的抖动熵。没有单独依赖任何单一的熵源。熵使用 BLAKE2s 密码学哈希函数 提取,并用于播种一组 ChaCha20 CRNG(密码学随机数生成器),这些 CRNG 提供实际的随机数据。只要内核正在运行,熵就会持续收集,并且 CRNG 会定期重新播种。

Linux RNG 为用户空间提供三个接口来获取随机数据

历史上,/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/randomgetrandom(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 可以提供使用抖动熵生成的随机数据。如果可能,额外的熵源不应取代内核 RNG,而应通过从额外的熵源和内核 RNG 中播种用户空间 CRNG 来与内核 RNG 结合使用。也可以将额外的熵写入 /dev/random,使其合并到内核 RNG 中,但这可能需要长达 60 秒才能生效,因为内核 CRNG 重新播种计划。注意:内核已经使用 RDSEED 和其他硬件随机数生成器作为熵源。

参见