/dev/random 极其缓慢?

51

背景信息:我想在一台Red Hat服务器上运行一个脚本,从/dev/random读取一些数据,并使用Perl的unpack()命令将其转换为十六进制字符串以备后用(评估数据库操作性能)。我对/dev/random运行了几个“head -1”,似乎一切正常,但是在多次调用之后,它会卡住。几分钟后,它最终输出一小块文本,然后完成。

我切换到了/dev/urandom(我真的不想这样做,因为它更慢,而我也不需要那么高质量的随机数),前两三次调用它都正常,然后它也开始挂起。我想知道是否是“head”命令导致了这个问题,所以我尝试使用Perl进行一些简单的I/O操作,但它也挂起了。最后我使用了“dd”命令将一些信息直接转储到文件中,而不是输出到终端。我要求它提供1MB的数据,但在我杀掉它之前,它花了3分钟才获取了约400字节。

我检查了进程列表,CPU和内存基本没有被使用。究竟是什么原因导致/dev/random出现了这种情况?我该如何避免/修复它在未来再次出现?

编辑:谢谢大家的帮助!看来我把random和urandom搞混了。现在我已经让脚本正常运行了。今天好像学到了新东西 :)


10
你似乎混淆了这两个设备;在Linux系统中,/dev/random是高质量的、阻塞的随机设备。当没有足够的熵来生成高质量的随机数时,它会“挂起”。/dev/urandom应该是非阻塞的和伪随机的。 - Wooble
关于/dev/random,请参考维基百科:"当熵池为空时,从/dev/random读取将会阻塞,直到收集到更多的环境噪声。" /dev/urandom应该是非阻塞的,你确定使用了它吗? - user395760
顺便提一下,你运行了 head -1 命令,这将读取一行数据,即读到遇到换行符为止。如果你想读取少量数据,最好使用 dd 命令。 - Hasturkun
1
尽管它不会阻塞,但即使是/dev/urandom也不太适合生成大量的随机数据。虽然在这种情况下你似乎并不太担心安全性,但也许你可以从/dev/urandom中获取几个字节,并用它来种子化Python(C,或其他)PRNG? - eaj
7个回答

54
在大多数Linux系统上,/dev/random是由环境收集的实际熵提供动力。如果你的系统从/dev/random没有提供大量数据,这很可能意味着你没有产生足够的环境随机性来为其供电。
我不知道你为什么认为/dev/urandom速度较慢或质量更高。它重新使用内部熵池生成伪随机数,使其略微低质量,但不会阻塞。通常,不需要高级或长期加密的应用程序可以可靠地使用/dev/urandom
尝试等待一段时间,然后再次从/dev/urandom读取。有可能你已经从/dev/random读取了太多,耗尽了内部熵池,破坏了两个生成器,允许你的系统创建更多的熵以补充它们。
请参见Wikipedia获取有关/dev/random/dev/urandom的更多信息。

啊,看来我混淆了哪一个在密码使用中不被视为安全。如果我写入/dev/random(以混合额外的随机数据),这是否有助于解决问题,我将获得什么“投资回报”? (例如,如果我写入1MB的数据,我保证可以读取多少MB的数据,或者是否是这种情况?) - Mr. Llama
1
@GigaWatt:这实际上取决于系统从你的写入中获得了多少比特的熵。除非你拥有比/dev/random更好的熵源,否则这也将是相当徒劳的,如果是这样,你应该首先让内核处理该熵源。 - Hasturkun
@GigaWatt:是的,你可以写入/dev/random,但这并没有帮助,因为你没有调用ioctl调用来增加熵,即使你获得了更高质量的随机数据,速度也不会更快。请阅读有关rngd的内容。 - akostadinov
10
/dev/random和/dev/urandom都使用同一个CSPRNG作为种子。鉴于现有的时间、密码分析和计算能力,/dev/urandom是无法与真随机区分的。认为/dev/random比/dev/urandom更真实随机的观念是错误的,只是一种谬论。/dev/random仅在输入熵池耗尽或者阻塞熵池中少于160位数据时才会阻塞。但它使用的是与/dev/urandom相同的CSPRNG,两者之间几乎没有实际区别。除非你正在使用某些信息理论算法,否则请使用/dev/urandom。 - Aaron Toponce

26

这个问题已经很老了,但仍然相关,所以我会给出我的答案。今天许多CPU都配备了内置硬件随机数生成器(RNG)。同时,许多系统也配备了可信平台模块(TPM),它们也提供RNG。还有其他可以购买的选项,但您的计算机很可能已经有了某种形式的RNG。

您可以在大多数Linux发行版上使用rng-utils软件包中的rngd来生成更多的随机数据。例如,在Fedora 18上,启用从TPM和CPU RNG(RDRAND指令)播种的唯一操作是:

# systemctl enable rngd
# systemctl start rngd

您可以比较使用和不使用rngd时的速度。建议从命令行运行rngd -v -f以显示检测到的熵源,并确保加载了支持您的熵源的所有必要模块。如果要使用TPM,则需要通过tpm-tools激活它。更新:这里有一个很好的教程

顺便说一句,我在互联网上看到有关TPM RNG经常以不同方式失效的一些担忧,但没有看到针对Intel、AMD和VIA芯片中发现的RNG的具体内容。如果您真的关心随机性质量,使用多个来源会更好。

urandom对于大多数用例都很好(除了早期引导期间)。现在大多数程序都使用urandom而不是random。甚至openssl也是这样做的。请参见有关urandom的神话随机接口的比较

在最近的Fedora和RHEL/CentOS中,rng-tools还支持jitter entropy。如果您缺乏硬件选项或者只是比您的硬件更信任它,可以使用它。

更新:增加了另一个获得更多熵的选项:HAVEGED(质量存疑)。在虚拟机中有一个kvm/qemu VirtIORNG(推荐)。

更新2:在Linux 5.6内核中进行了自己的抖动熵池


2
谢谢!!!对于Ubuntu 20.04,软件包和服务名称都是rng-tools - Bob Kocisko

16

使用 /dev/urandom,它具有加密安全性。

好的阅读材料:http://www.2uo.de/myths-about-urandom/

“如果您不确定是否应该使用 /dev/random 还是 /dev/urandom,则可能希望使用后者。”

当在早期引导时怀疑是否收集了足够的熵时,请改用系统调用 getrandom()。[1](适用于 Linux 内核版本 >= 3.17)这样可以兼顾两方面:

  • 它会阻塞直到收集到足够的熵(仅一次!)
  • 之后它将永远不会再次阻塞。

[1] git kernel commit


4
为什么这个答案被踩了?在我看来,它是一个好的回答...但也许我忽略了其中的问题。 - MountainX

2

如果你想为/dev/random获得更多的熵值,那么你需要购买硬件随机数生成器或使用其中一个*_entropyd守护程序来生成它。


生成熵是一个难题。对于没有深入加密知识的用户来说,避免更改默认机制更安全。最好按照这里所解释的使用/dev/urandom。http://www.2uo.de/myths-about-urandom/ - akostadinov

2

1

如果您在测试中使用随机性(而不是密码学),那么可重复的随机性更好,您可以通过从已知种子开始的伪随机性来实现这一点。大多数编程语言通常都有很好的库函数来实现这个。

它是可重复的,当您发现问题并尝试进行调试时非常有用。它也不会消耗熵。可以从/dev/urandom种子伪随机生成器,并将种子记录在测试日志中。Perl有一个伪随机数生成器可供使用。


/dev/randomurandom 是同样的伪随机数生成器,请参考 http://www.2uo.de/myths-about-urandom/。 - akostadinov
文章中提到/dev/random可能会阻塞。同时,它和/dev/urandom都是不可预测的。因此,正如我所说的那样,它们是不可重复的,因此不适合用于测试。 - ctrl-alt-delor
/dev/(u)random 是一个伪随机数生成器。可预测性和可重复性是不同的属性。您只是缺少必要的内核控制来使它们可预测和可重复(感谢上帝)。我同意其他生成器对于特定测试场景更好。我必须承认,您的回答为操作者提供了合理的建议。但是,SO在回答被编辑之前不会让我撤销我的投票。这也是一件好事。 - akostadinov

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接