在虚拟机上使用 haveged 作为熵源是否合适?

信息安全 linux 虚拟化 随机的
2021-08-24 06:16:19

在寻找虚拟机上熵池耗尽的解决方案时,我遇到了一个名为 的有趣项目haveged,它基于HAVEGE算法(硬件易失熵收集和扩展)。它提出了一个非常棒的主张。

HAVEGE 是一个随机数生成器,它利用内部 CPU 硬件状态(缓存、分支预测器、TLB)的修改作为不确定性的来源。在初始化阶段,处理器的硬件时钟周期计数器用于收集部分熵:平均每个操作系统调用可以收集数万个不可预测的位。

如果这真的在无头虚拟机上产生了几乎无限的高质量熵,那么它应该默认包含在每个服务器分发中!然而,也有人提出了担忧。

“本质上,[HAVEGE] 使用基于处理器的高分辨率计时器(RDTSC 指令)的时序信息。该指令可以虚拟化,一些虚拟机主机选择禁用该指令,返回 0 或可预测的结果。”
(来源:polarssl.org 上的 PolarSSL 安全咨询 2011-02)。

此外,流行的 NIST 和 ENT 测试有时会给出havegedPASS,即使它是故意错误配置的,实际上并没有产生随机数!

我用常量 0(零)替换了 HAVEGE 中的“HARDTICKS”宏,而不是读取处理器的时间戳计数器。这立即未能通过随机性测试。但是,当我改用常量 1(一)时,ent 测试通过了。甚至 nist 在执行的 426 次测试中也只有一个错过的测试几乎通过了。(来源:在 engbloms.se 上评估 HAVEGE 随机性)。

  • 那么,哪些虚拟化平台/管理程序可以在虚拟机中安全使用haveged
  • 是否有一种普遍接受的最佳实践方法来测试随机源是否产生足够高质量的数字?
3个回答

警告:我当然不会声称 HAVEGE 符合其要求。我没有检查过他们的理论或实施。)

为了获得随机性,HAVEGE 和类似系统以“物理事件”为基础,特别是物理事件的时间此类事件包括硬件中断的发生(反过来,它会收集有关击键、鼠标移动、传入以太网数据包、硬盘完成写入请求的时间......)。HAVEGE 还声称可以提供 CPU 中发生的所有类型的缓存未命中(L1 缓存、L2 缓存、TLB、分支预测......);这些元素的行为取决于 CPU 在之前的几千个时钟周期中所做的事情,因此可能存在一些“随机性”。这取决于能否以极高的精度(不一定准确)测量当前时间,这就是rdtsc指令开始发挥作用。它返回内部计数器的当前内容,该计数器在每个时钟周期递增,因此它提供亚纳秒精度。

对于虚拟机系统,关于这条指令有三种选择:

  1. 让指令直接进入硬件。
  2. 捕获指令并模仿它。
  3. 完全禁用该指令。

如果 VM 管理器选择第一个解决方案,则rdtsc具有所有所需的精度,并且应该像在物理机器上一样工作,以便从硬件事件中收集熵。但是,由于这是一个虚拟机,它是宿主系统上的一个应用程序;它不会一直占用 CPU。从使用的客户操作系统的角度来看rdtsc,这看起来好像它的 CPU 偶尔会被“偷走”:两条连续rdtsc的指令,名义上相隔一个时钟周期,可能会报告计数器增加数百万简而言之,当rdtsc简单地应用于硬件时,客户操作系统可以使用它来检测虚拟机管理程序的存在。

第二种解决方案旨在通过维护一个虚拟的每个 VM 周期计数器来使仿真更加“完美”,该计数器跟踪实际分配给该 VM 的周期。好处是rdtsc,从客人的角度来看,将不再表现出“被盗周期”效应。缺点是这种模拟是通过触发和捕获 CPU 异常来执行的,从而将rdtsc操作码的成本从几十个时钟周期(这取决于 CPU 品牌;一些执行rdtsc不到 10 个周期,其他使用 60 或 70 个周期) ) 超过一千次循环。如果客人尝试做很多事情rdtsc(就像 HAVEGE 很容易做的那样),然后它会减速到爬行。此外,异常处理代码会破坏措施;代码将测量异常处理程序的执行时间,而不是测量硬件事件时间,这可能会降低提取随机性的质量。

第三种解决方案(禁用rdtsc)将简单地阻止 HAVEGE 返回良好的随机性。由于它在内部使用了PRNG,因此输出可能仍然会欺骗统计分析工具,因为“看起来随机”和“不可预测”之间存在巨大差异(统计分析工具遵循“看起来随机”路径,但密码安全性依赖于不可预测性)。

VirtualBox 手册声称,默认情况下,VirtualBox 遵循第一种方法(无条件rdtsc允许并直接应用于硬件),但可以配置为应用第二种解决方案(在这种情况下,您不需要)。

要测试你的虚拟机做了什么,你可以试试这个小程序(gcc -W -Wall -O在 Linux 上编译;这-O很重要):

#include <stdio.h>

#if defined(__i386__)

static __inline__ unsigned long long rdtsc(void)
{
        unsigned long long int x;

        __asm__ __volatile__ (".byte 0x0f, 0x31" : "=A" (x));
        return x;
}

#elif defined(__x86_64__)

static __inline__ unsigned long long rdtsc(void)
{
        unsigned hi, lo;

        __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
        return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
}

#endif

int
main(void)
{
        long i;
        unsigned long long d;

        d = 0;
        for (i = 0; i < 1000000; i ++) {
                unsigned long long b, e;

                b = rdtsc();
                e = rdtsc();
                d += e - b;
        }
        printf("average : %.3f\n", (double)d / 1000000.0);
        return 0;
}

在非虚拟机上,使用“true” rdtsc,这将报告 10 到 100 之间的值,具体取决于 CPU 品牌。如果报告的值为 0,或者程序崩溃,rdtsc则被禁用。如果值以千为单位,rdtsc则被模拟,这意味着熵收集可能无法像预期的那样工作。

请注意,即使获得 10 到 100 之间的值也不能保证rdtsc不被模拟,因为 VM 管理器在维护其虚拟计数器的同时,可能会从中减去执行异常处理程序所需的预期时间。最后,你真的需要好好看看你的虚拟机管理器的手册和配置。


当然,HAVEGE 的整个前提是有问题的。对于任何实际的安全性,您需要一些“真正的随机”位,不超过 200,您将其用作密码安全 PRNG中的种子。PRNG 将产生千兆字节的伪 alea,与真正的随机性无法区分,这对于所有实际目的来说已经足够了。

坚持每一点都回到硬件看起来像是又一次爆发这种有缺陷的想法,将熵视为一种汽油,当你看到它时你会燃烧它。

关于 polarssl 咨询:可以在最新的 debian 源代码中找到详细的技术响应:

http://bazaar.launchpad.net/~ubuntu-branches/debian/experimental/haveged/experimental/revision/12?start_revid=12#debian/README.Debian

执行摘要是:polarssl != haveged != HAVEGE

在 embloms.se 模拟器实验中:

测试haveged套件NISTent验证源构建已生成功能 RNG。需要运行时测试来验证虚拟环境中的已执行操作。这是对 hasged 的​​一个相当新的补充。

关于统计检验:

假设你有 a hardware RNG, a TRNG,你怎么知道它没有坏掉?硬件中断。德国标准机构有一个规范来处理这个问题,AIS31. haveged采用了这种方法。有关适用于 haveged 的​​ RNG 标准的(有偏见的)讨论,请参见:

http://www.issihosts.com/haveged/ais31.html

的不可预测性HAVEGE与基准测试软件中的机制完全相同。这不是由于计时器漂移,而是现代处理器中异步行为的聚合。性能变化是来自缓存未命中还是交付给另一个处理器的时间片并不重要。只要“足够”,计时器的准确性也无关紧要。这是怎么确定的?由输出。通过设计(或者可能是过度设计)/dev/random不受不良输入数据的影响。颠覆设计的唯一方法是谎报添加到熵池中的熵。最新版本的 haveged 对输出生成执行运行时熵估计,以确保输出与理想的 TRNG 一致。

执行摘要:输出与德国标准机构用于认证的测试haveged没有区别如果不是这种情况,将关闭。TRNGTRNGhaveged

更新,感谢gwuertz的当前作者/维护者haveged,我错过了 和 之间的分离HAVEGEhaveged

haveged是用于生成随机数的 HAVEGE 方法的独特实现,它是最新的,在此处维护和记录:http : //www.issihosts.com/haveged/(不再直接使用 libhavege)。

HAVEGE不是很最新(2006 年),尽管有人最近(2009 年)为了速度和正确性对它进行了修补。我会谨慎,因为它没有记录它的方法,没有提到虚拟机,并且如前所述,它(严重)依赖RDTSC(或平台等效)。(源代码也让我不寒而栗,但这是相当主观的。)

我会争辩说,宿主 VM 不应该无意中将任何状态泄漏给来宾,因此在使用这种方法时,它不应该被认为是一个好的熵源。

Linux 上更好的方法是使用virtio-rng半虚拟化 rng 驱动程序的rng-tools(即允许客人访问主机收集的熵,消除客人查看“随机”事件的许多潜在问题),或者您可能会发现Entropy经纪人更有用。在最近的英特尔芯片上,您还可以向客人公开RDRAND指令,从而回避问题。

这篇文章(来自hpaLinuxCon Europe 2012上的演讲)是有用的阅读: http: //lwn.net/Articles/525459/,它还讨论了HAVEGE/ haveged(尽管这里的区别也不清楚)。

有关如何确定缺乏随机性的一些想法,请参阅此问题的答案:哪些统计数据可用于识别伪随机数据?