从/ dev / random读取不会产生任何数据


19

我经常使用命令

cat /dev/urandom | strings --bytes 1 | tr -d '\n\t ' | head --bytes 32

生成伪随机密码。这不适用于/dev/random

特别

  • cat /dev/urandom | strings --bytes 1 | tr -d '\n\t ' 产生输出
  • cat /dev/random | strings --bytes 1 产生输出
  • cat /dev/random | strings --bytes 1 | tr -d '\n\t ' 产生输出

注意:使用时,/dev/random您可能不得不扭动鼠标或按下键(例如ctrl,shift等)以产生熵。

为什么最后一个示例不起作用?是否tr有某种大型的内部缓冲区可以/dev/urandom快速填充但/dev/random没有?

PS我正在使用CentOS 6.5

cat /proc/version
Linux version 2.6.32-431.3.1.el6.x86_64 (mockbuild@c6b10.bsys.dev.centos.org) (gcc version 4.4.7 20120313 (Red Hat 4.4.7-4) (GCC) ) #1 SMP Fri Jan 3 21:39:27 UTC 2014

您的发行版是什么,您的内核版本是什么?在Cygwin上都返回值。
Kiwy

@Kiwy请参见编辑。
亚伦J朗

1
pwgen特别知道pwgen -s吗?
MvG 2014年

2
-s开关使得它们不太令人难忘,更真正随机的。@Boyd:除了基于Debian的发行版之外,makepasswd是否可以广泛使用?我的看法是,pwgen可用于CentOS,makepasswd不可用
MvG 2014年

1
@BoydStephenSmithJr。我同意@MvG makepasswd在平台上不可用,还是要感谢
Aaron J Lang

Answers:


27

它将最终。

在:

cat /dev/random | strings --bytes 1 | tr -d '\n\t '

cat 永远不会缓冲,但这是多余的,因为这里没有任何连接。

< /dev/random strings --bytes 1 | tr -d '\n\t '

strings虽然,因为它的输出是不是不再是一个终端将缓冲由块其输出(的像4或8KB),而不是线时的输出变为一个终端。

因此,只有在累积了4kB的字符要输出时才开始写入stdout,这/dev/random将需要一段时间。

tr输出到终端(如果您在终端的shell提示符下运行该终端),因此它将按行缓冲其输出。因为您要删除\n,所以它永远不会写整行,因此,它将在积累了整个块后立即进行写操作(例如,当输出未到达终端时)。

因此,在读取足够多的数据tr之前,它可能不写任何东西strings/dev/random以便写入8kB(可能更多的2个块)的数据(因为第一个块可能包含换行符或制表符或空格字符)。

在此系统上,我可以平均每秒获得3个字节/dev/random(相对于12MiB /dev/urandom),因此在最佳情况下(前4096个字节/dev/random都是可打印的)说话22分钟后才tr开始输出任何内容。但这很可能要花几个小时(在快速测试中,我看到strings每读取1到2个块就写入一个块,并且输出块包含大约30%的换行符,所以我希望它需要读取至少3个块之前tr有4096个字符要输出)。

为了避免这种情况,您可以执行以下操作:

< /dev/random stdbuf -o0 strings --bytes 1 | stdbuf -o0 tr -d '\n\t '

stdbuf 是一个GNU命令(在某些BSD上也可以找到),它通过LD_PRELOAD技巧更改命令的stdio缓冲。

请注意strings,您可以使用而不是来tr -cd '[:graph:]'排除制表符,换行符和空格。

您可能还希望将语言环境也固定C为避免将来可能出现UTF-8字符意外的情况。


令人印象深刻的解释。
2014年

2
惊人!很好的解释和解决方案。我一直使用cat“无用的”,因为我从来不喜欢在管道的末尾重定向stdin,现在我可以“保存进程”并且仍然具有可读的命令。我的最终解决方案是< /dev/random stdbuf -o0 tr -Cd '[:graph:]' | stdbuf -o0 head --bytes 32
Aaron J Lang

@AaronJLang,关于[:graph:]。我已经忘记了那个。
斯特凡Chazelas

@AaronJLang,你不需要stdbufhead -c32除非你想允许它写入数据,只要它有它(如在几个块,而不是一个32字节的块,只要它的得到他们)
斯特凡Chazelas

2
我认为,/ dev / urandom足以供作者使用。如果有人对urandom与随机相比的工作方式感到好奇,我建议阅读内核源代码树的drivers / char / random.c中驱动程序顶部的注释。评论中提到了对PRNG及其实现的分析。希望本文能回答以下问题:“与随机相比,随机数是多少?” 此处可用:eprint.iacr.org/2012/251.pdf
etherfish 2014年

5

为许多安全应用程序生成随机数需要足够的熵—熵衡量了随机性的不可预测性。确定性处理器无法生成熵,因此熵必须来自外部,要么来自具有不确定性行为的硬件组件,要么来自其他难以再现的因素,例如用户操作的时机(在那儿摆动鼠标)进来)。一旦有足够的熵可用,就可以使用密码术生成几乎无限的随机数流。

Linux的工作原理是在一个池中累积熵,然后使用加密技术通过/dev/random和产生可接受的随机数/dev/urandom。所不同的是,/dev/random应用了非常保守的熵计算,该计算减少了池中生成的每个字节的熵估计,而/dev/urandom与池中的熵量无关。

如果池中的熵估计值太低,则会/dev/random阻塞直到可以累积更多的熵。这会严重削弱/dev/random产生产出的速度。这就是您在这里观察到的。它与无关tr; 但是strings使用缓冲读取输出,因此它必须从中读取完整的缓冲区(几KB)/dev/random才能产生至少一个字节的输入。

/dev/urandom生成加密密钥是完全可以接受的,因为熵实际上并没有以任何可感知的方式减小。(如果您使计算机的运行时间超过Universe的运行时间,则不能忽略这些注意事项,但是,否则,您会感到很满意。)只有一种情况/dev/urandom是不好,这是在全新安装的系统中没有还没有时间生成熵,也没有时间从只读媒体启动的新启动的系统。

strings从启动链中消除可能会加快您的过程。下面tr将过滤非打印字符:

</dev/random LC_ALL=C tr -dc '!-~'

但是您可以/dev/urandom在这里使用,只要您注意不要在没有时间累积足够熵的系统上生成密码。您可以在其中检查Linux的熵池的级别/proc/sys/kernel/random/entropy_avail(如果使用/dev/random,则此文件中的数字为保守数字,可能非常保守)。


1

仅当您绝对需要真正不可预测的随机数时/dev/urandom/dev/random才应使用它来获取高质量(伪)随机数。下面NSA的资源,攻击者将有一个非常艰难的时间来破解/dev/urandom(不要忘了橡胶软管加密)。内核使用“真正随机的”字节填充缓冲区,这就是/dev/random给出的结果。可悲的是,生成它们的速率很低,因此从中读取大量内容/dev/random 将使等待随机性停滞。

您可能会考虑使用random.org或其密码生成器,或者是许多随机生成的随机密码生成器之一,例如,请参见此页面上的一些命令行提示(不是我建议所有人使用它们) ,但它们应该给您一些想法),或者您可以使用类似的东西mkpasswd(1)(在Fedora的19部分expect-5.45-8.fc19.x86_64)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.