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

Aar*_*ang 21 linux random

我经常使用命令

cat /dev/urandom | strings --bytes 1 | tr -d '\n\t ' | head --bytes 32
Run Code Online (Sandbox Code Playgroud)

生成伪随机密码。这不适用于/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
Run Code Online (Sandbox Code Playgroud)

Sté*_*las 28

它最终会。

在:

cat /dev/random | strings --bytes 1 | tr -d '\n\t '
Run Code Online (Sandbox Code Playgroud)

cat 永远不会缓冲,但无论如何它都是多余的,因为这里没有什么可以连接的。

< /dev/random strings --bytes 1 | tr -d '\n\t '
Run Code Online (Sandbox Code Playgroud)

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

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

tr输出到终端(如果您在终端的 shell 提示符下运行它),因此它将按行缓冲其输出。因为您正在删除\n,它永远不会有完整的行要写入,因此,一旦累积了完整的块,它就会写入(例如当输出没有进入终端时)。

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

在这个系统上我正在尝试这个,我可以平均每秒获得 3 个字节/dev/random(而不是 12MiB on /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 '
Run Code Online (Sandbox Code Playgroud)

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

请注意strings,您可以使用tr -cd '[:graph:]'which代替,也将排除制表符、换行符和空格。

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

  • 惊人的!很好的解释和解决方案。我一直“无用”地使用“cat”,因为我从不喜欢在管道末端重定向 stdin,现在我可以“保存进程”并且仍然拥有可读的命令。我的最终解决方案是`&lt; /dev/random stdbuf -o0 tr -Cd '[:graph:]' | stdbuf -o0 head --bytes 32` (2认同)
  • 在我看来, /dev/urandom 足以满足作者的使用。如果有人对 urandom 与 random 相比具体如何工作感到好奇,我建议您阅读内核源代码树的drivers/char/random.c 中驱动程序顶部的注释。评论提到了对 PRNG 及其实现的分析。希望这篇论文能够回答“与随机相比,urandom 的随机程度是多少?”的问题。可在此处获取:http://eprint.iacr.org/2012/251.pdf (2认同)

Gil*_*il' 5

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

Linux 的工作原理是在池中累积熵,然后使用密码术通过/dev/random和生成可接受的随机数/dev/urandom。不同之处在于/dev/random应用了极其保守的熵计算,该计算减少了池中对于它生成的每个字节的熵的估计,/dev/urandom而不关心池中的熵量。

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

/dev/urandom生成加密密钥是完全可以接受的,因为熵实际上并没有以任何可察觉的方式减少。(如果你让你的机器运行的时间比宇宙存在的时间长,你不能忽视这些注意事项,否则你很好。)只有一种情况/dev/urandom不好,那就是在新安装的系统上没有' 还没有时间生成熵,或者从只读媒体启动的新启动系统。

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

</dev/random LC_ALL=C tr -dc '!-~'
Run Code Online (Sandbox Code Playgroud)

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