在以下意义上需要熵:如果 PRNG 只有n位熵,那么这意味着它(在概念上)只有 2 n 个可能的内部状态,因此可以通过对这 2 n个状态的粗略枚举来打破,前提是n足够低,使得这种蛮力攻击是可行的。
然后事情变得复杂,因为内核报告的“熵水平”不是熵。不是我上面说的那个。
从密码学的角度来看,计算两者输出的算法/dev/random
是/dev/urandom
(假设)密码安全的 PRNG。实际上,对于实际安全而言,重要的是内部状态的累积熵。除非该 PRNG 存在密码学缺陷(目前尚不为人所知),否则熵只会随着时间的推移而增加或保持不变。事实上,“熵”也可以称为“攻击者不知道的”,如果 PRNG 确实在密码学上是安全的,那么根据定义,观察千兆字节的输出只会产生可忽略不计的内部状态信息。这就是密码安全的含义。
因此,如果/dev/urandom
自上次启动以来的某个时刻有 200 位熵,那么它仍然有 200 位熵,甚至更多。
从编写该代码的人(以及可怕的相应手册页)的角度来看,熵在使用时“耗尽”。这是某人的立场,为了争论,PRNG 在密码学上不是安全的,实际上在某种程度上等同于简单地按原样输出内部状态。从这个角度来看,如果/dev/random
从n位熵开始并输出k位,那么它现在有nk位熵。
然而,这种观点最终是站不住脚的,因为虽然它是基于 PRNG 完全损坏且无法操作的假设,但同时它也基于 PRNG 仍然是密码学的假设足够安全,可以将“硬件熵”(假设为有点随机的数据元素的来源)变成一个很好的统一位序列。简而言之,熵耗尽的概念只有在我们采用 PRNG 完全弱的极端假设时才有效,但在这种假设下,对真正存在多少熵的估计完全不成立。
从本质上讲,这种观点是自相矛盾的。不幸的是,/dev/random
实现了依赖于这种有缺陷的熵估计的阻塞策略,这非常不方便。
/dev/urandom
永远不会阻塞,无论自上次启动以来已经收集了多少“硬件熵”。但是,在“正常”Linux 安装中,随机种子会在引导过程的早期插入;该种子在上次启动时保存,并在插入后立即更新。该种子主要扩展了/dev/urandom
重新启动的熵。所以断言变成:如果自操作系统首次安装以来的任何时候/dev/urandom
都有 200位的熵,那么它仍然有 200 位的熵。
对于某些特定情况,例如无盘引导,这种行为仍然会有些麻烦。启动机器可能需要一些随机性才能访问其文件(例如,建立到达包含所述文件的服务器所需的IPsec上下文)。一个更好的实现/dev/urandom
会阻塞,直到收集到足够数量的硬件熵(例如 128 位),但随后会“永远”产生位,而不实现某种熵耗尽。这正是 FreeBSD/dev/urandom
所做的。这很好。
总结:别着急。如果内核中使用的 PRNG 在密码学上是安全的,那么“entropy_avail”计数就毫无意义。如果内核中使用的 PRNG 在密码学上不是安全的,那么“entropy_avail”计数仍然存在缺陷,无论如何你都会遇到大麻烦。
请注意,VM 快照会破坏熵,因为还原后 VM 的行为将始终在保存在快照中的状态上起作用,并且只会通过新硬件事件的累积而发生分歧(这在 VM 中可能很棘手,因为VM 硬件不是真正的硬件)。内核的“entropy_avail”计数器和/dev/random
阻塞行为根本没有改变。对于系统 PRNG,VM 快照/恢复是一个比“entropy_avail”试图捕获(但实际上未能捕获)的学术纯理论场景更合理的安全漏洞。