用 /dev/urandom 喂食 /dev/random 有多糟糕?

信息安全 密码学 随机的
2021-09-07 01:57:11

我看过许多博客文章或博客评论,它们建议使用 /dev/urandom 的输出来提供 /dev/random 熵。

我不是加密专家,但它看起来是用更少的随机数替换难以预测的数字的好方法。但是,是否有任何关于它的效果有多糟糕的见解?

如果我找到具有这种配置的服务器,我是否需要使 tls 证书、ssh 和 gpg 密钥失效,就像臭名昭著的 debian 错误 CVE-2008-0166 一样?还是更像是国家资助的攻击者可能会在数十亿欧元的情况下找到我的私钥?

3个回答

我在这里假设一个 Linux 系统,在 FreeBSD 和 Mac OS 等某些操作系统上,和之间没有任何区别/dev/random/dev/urandom而其他人则没有这些设备

双方/dev/random/dev/urandom使用相同的熵池。不同之处在于 /dev/random “计数”了已提取的字节数,估计池中剩余的熵。如果在某一时刻它认为没有足够的熵来满足所要求的内容,它将阻塞,而/dev/urandom将提供所请求的字节。

事实是,/dev/urandom 本来就很好(启动后不久除外)。饲喂/dev/random/dev/urandom是欺骗的一种方式,但真的不应该打破安全。

我是否需要使 tls 证书、ssh 和 gpg 密钥失效,就像臭名昭著的 debian bug CVE-2008-0166 一样?

一点也不。

或者它更像是一个国家资助的攻击者可能会在几十亿欧元的情况下找到我的私钥

即使对于国家资助的攻击者,我认为找出从正常系统上的随机池中提取的随机字节也不会是可追踪的。

例外是嵌入式设备,例如路由器,它们经常被发现在启动后不久生成随机密钥(例如,用于 https 或 ssh),它们实际上具有相当确定的状态。

尽管如此,对于像您提到的那些长期密钥,您可能仍然更愿意/dev/random因为知道这将花费更长的时间来喂养,而只是回避使用/dev/urandom. 这也很好。

这是一件愚蠢的事情,但并不危险。

原因是 Linux 是保守的,将您输入的数据/dev/random视为确定性的,因此不会增加其估计的内部熵。

手册页

写入/dev/random/dev/urandom将使用写入的数据更新熵池,但这不会导致更高的熵计数。这意味着它会影响从两个文件中读取的内容,但不会使读取/dev/random速度更快。

因此,从/dev/urandomto复制字节/dev/random只会浪费 CPU,但并不危险。如果您看到这是在服务器上完成的,您不必担心它本身。最令人不安的可能是它是一个线索,表明服务器是由一个相信蛇油的人设置的,或者更糟糕的是,它试图绕过出于某种原因而设置的安全功能。尽管后者在这种情况下不起作用。1所以也许检查服务器上是否有其他可能不太良性的事情。

另一方面,读取 from/dev/random实际上在启动脚本中可能很有用,因为它会阻塞,直到系统在其内部池中收集到足够的熵以确保/dev/urandom使用安全。


1如果即使内核估计它的熵很低,如果你真的想变得刻薄并做到/dev/random非阻塞,你可以简单地将它设为/dev/urandom.

# rm -f /dev/random
# mknod -m 0666 /dev/random c 1 9

请参阅手册页mknod并查看输出

$ stat /dev/random /dev/urandom

如果你对这里发生的事情感到困惑。(该stat命令可以安全地执行。)

当然,我强烈建议不要使用这种讨厌的技巧。

我将尝试回答一个简化的问题:对真正的 CSPRNG(加密安全随机数生成器)是否存在可行的攻击?然后,如果它不是一个完美的 CSPRNG 怎么办?

情况1)

为简单起见,假设在确定性真实 CSPRNG 的初始化设置之后没有添加任何熵。此外,假设初始化中没有信息泄漏。

从维基百科对 CSPRNG 的定义如下:

每个 CSPRNG 都应该满足下一位测试。也就是说,给定随机序列的前 k 位,没有多项式时间算法可以预测第 (k+1) 位的成功概率不可忽略地优于 50%。Andrew Yao 在 1982 年证明,通过下一位测试的生成器将通过所有其他多项式时间统计测试的随机性。

每个 CSPRNG 都应该承受“状态妥协扩展”。如果它的部分或全部状态已被揭示(或被正确猜测),那么在揭示之前重建随机数流应该是不可能的。此外,如果在运行时存在熵输入,则使用输入状态的知识来预测 CSPRNG 状态的未来条件应该是不可行的。

也就是说,即使某些随机输出序列被泄露,也无法确定该泄露部分之前和之后的序列部分。

在这种情况下,您使用 是完全安全的/dev/urandom即使随机序列数据泄漏,并且即使在初始化后没有将外部随机数据添加到序列中。

案例2)

假设事实证明,所谓的 CSPRNG 实际上被破坏了。只是为了出售论点假设给定序列的部分泄漏,序列的过去和未来部分“足够接近”泄漏都受到严重损害。

在这种损坏的 CSPRNG 情况下,增加的熵将增加系统的安全性。如果 256 个真正的熵位将泄漏和用于关键目的的随机数 X 分开,则对 X 的攻击的搜索空间扩大了 2^256 - 因此它是完全安全的。

因此,案例 2 在以下 2 个条件下存在风险:

  1. 随机序列状态存在泄漏。
  2. PRNG 不是完美的 CSPRNG。

但是确保足够的熵可以完美地降低风险。

关于情况(1):数据泄露的可能性。一些 Java 实现提供对底层 /dev/random 数据的访问。 它在 Java 文档中是这样说的。

这对于在 Java 中选择随机数非常有用,但它可能会被基于 Java 的恶意软件用来泄露随机序列的信息。除了 Java,每次你用你的软件创建一个随机密码并将其传递给外部网站时,这可能会泄露一些关于你的随机序列状态的信息。

关于条件 (2):虽然可以证明特定 PRNG不是CSPRNG,但不可能证明特定 PRNGCSPRNG。您只需要希望 CSPRNG 在您不知情的情况下没有被证明是错误的。还有一些灰色阴影:特定的攻击只会在泄漏前后打开一个狭窄的漏洞窗口,并且需要大量资源才能利用它。用具体数字评估未知(对您而言)攻击的风险是困难或不可能的,但将风险视为未知变量并检查缓解成本与风险变化时的后果是一项有意义的练习。

注意:有一个外行的问题:如果 PRNG 是确定性的,那么如果发生泄漏,下一位怎么可能无法预测?答案是尽管整个随机序列算法本身是众所周知的,但用于从一个(值,状态)对转换到下一个(值,状态)对的函数最初是从一大类函数中选择的,例如,一个2^256 个这样的函数。然后可以使用另外 256 位来播种所选函数。(实际上初始化/dev/random序列只需要 128 位)。