熵与NetBSD内核

2020-05-17 20:50:25

[注:没有发布到blog.NetBSD.org上,因为我认为它太固执己见了,而且我做的还不够多,没有足够的理由谈论它。]。

但如果我们想让他们的行为变得不可预测呢?如果我们想用随机密钥保护我们的私人通信,或者不让人们在电子游戏中作弊,或者如果我们正在做统计模拟或类似的事情,这是非常有用的。

传统的方式是通过伪装。我们采用各种被认为足够难以预测的因素,例如接收到来自硬件的某些信号的高分辨率定时,或者可能包含环境噪声(例如温度)的各种传感器的输出。

我们将它们送入散列函数,然后使用该散列函数的输出为随机数生成器提供初始种子。现代安全随机数生成器的定义是具有统计上的随机输出(具有不可检测的偏向于返回某些值),并且承诺您应该能够预测其未来的输出。

最近的硬件已经为系统引入了接收来自环境的真实随机性的设施。这包括诸如Intel';sRDRAND指令之类的内容。大多数操作系统选择不完全依赖这些,而是将它们的输出输入散列以引入额外的熵。

最近,NetBSD中的随机性进行了修改,使其符合规范,并有了一些新的期望。这主要是由Riastradh完成的,是由我和其他人的一些唠叨引起的。

这些期望中最重要的是,熵池中的256位不可预测值足以永远生成随机数,并且当您使用现代算法保护RNG时,不会因为使用它来生成更多的随机数而损失熵。即使有人使用量子计算机破解了世界上大部分的密码记录,这一点仍然成立。

在关机时(这些天也是在两次关机之间,只是在Case Power丢失的情况下),在系统生命周期内收集的熵池的当前状态被保存到一个文件中,以便在下一次引导时加载。这应该包括足够多的不可预测的数据,从而为您提供相当好的安全裕度。

第一次引导系统时,在引导过程的早期,事情会变得更加困难。

在现代的AMD/Intel系统上,不久之后的ARMv8.3中,您可以在引导过程的早期使用随机指令。这是它的主要卖点之一-几乎没有设置要求。

我们可以对它进行统计测试,以确保它是随机性的质量来源。

现在,内核在引导过程的早期需要随机性--如此之早以至于它不能依赖许多其他来源。它获取RDRAND(一个高精度定时器)的输出,将它们散列在一起,并使用它们作为早期随机数生成器的种子。

一个更大的担忧是,指令可能会被后退,以影响随机数生成器的状态,甚至会泄露它。

最近,Riastradh为基于Allwinner的ARM板提供了一个真正随机性的驱动程序,并对其进行了一些统计测试。他发现它产生了高度偏颇的产出。输出仍然被输入到熵池中,但是现在,我们知道我们不能依赖它。

其中一些硬件可能是小型嵌入式系统,没有很多传感器,没有硬件RNG来源,只有几个时钟定时,比如网络接口控制器。Riastradhr提出的一个问题是,攻击者可能会将数据包送入系统,并产生可预测的初始状态。

这是一个现实的威胁模型吗?攻击者是否能够影响网络计时到微秒/纳秒,以确保可预测的初始RNG状态?

您可能希望在引导过程中等待足够的熵从像样的来源收集,但在某些情况下,在最糟糕的、最糟糕的硬件上,您可能会永远等待。因此,在最糟糕的情况下,您可能希望在另一台计算机上生成种子文件。

有时,这包括硬件RNG而不包括其他任何东西,而不关心该硬件RNG是否后退。

有时,这基本上包括了所有东西,比如你正在使用的硬件的名称。显然,这是有效的熵-如果你的目标是增加池的大小,而不考虑实际的随机性。

[注意:我不会给这里描述的操作系统命名,以免用狗屎跟任何人说话来淡化我的任何观点。不过,你大概可以猜到。]。

最近对内核的改变之一包括取消了一种试图评估送入内核的样本质量的机制(这被认为太不科学了)。相反,报告其提供的熵值是每个司机的责任。

在大多数情况下,驱动程序被认为提供了0比特的熵,除非它们提供的随机性的质量能够得到证明。

我在这里争取了一个折衷方案:就像初始化userland一样,在启动任何守护进程之前,我们合并输入到池中的任何熵,并在内核中重新设定随机数生成器的种子。

我的目标是确保我们从尽可能多的潜在随机性来源中收集信息,以确保为用户空间随机数生成器提供高质量的初始种子。因此,它包括所有内容,包括被认为价值较低的来源,如中断计时。

即使在糟糕的硬件上,我们也不希望在初次启动时生成弱密钥。如果内核怀疑可能会发生这种情况,它将会非常嘈杂。

我只是个黑客小妞,不是安全专家或密码学家(但我在网上玩)。

以下是我的观点:我们都破产了。可喜的是,利用这一点已经够难的了,没有人能弄明白这一点。

如果你想成为一名NetBSD律师,你可以阅读rn.4。它引用了一些有趣的论文。