熵质量测试

本文档介绍了我们如何测试用于 是 Zircon CPRNG 的种子。

理论问题

大致来说,有时候很容易分辨出一串流数字, 而不是随机生成的。我们无法保证 数字是真正随机的。先进的 希望能发现任何可利用的弱点。

当有随机性特征的数据时, 不是完全随机的数字(当它们的分布不均匀时,或者 序列中数字之间的相关性有限时)。答 不完美的随机数流仍然包含一些随机性, 也很难判断它的随机性

出于我们的目的,该数字可以很好地衡量流中包含多少随机性 一个不完美的随机数字就是最小熵。这与 Shannon 熵用于信息理论,但始终采用较小的值。 最小熵控制我们能够从 熵来源;比如 https://en.wikipedia.org/wiki/Randomness_extractor#Formal_definition_of_extractors

从实际的角度来看,我们可以使用美国 NIST 中描述的测试套件 SP800-90B,用于分析熵源的随机样本。原型 可从 https://github.com/usnistgov/SP800-90B_EntropyAssessment.该套件采用了 样本数据文件(例如,1MB 的随机字节)作为输入。此功能的优点是 可以处理不完美的 RNG,而且它会报告 随机数据流的每个字节包含多少最小熵。

测试未处理数据的重要性

从熵源提取熵后, 我们要将其混合到 CPRNG “安全”这种方法基本上消除了可检测的相关性, 来自熵的原始随机字节流中的分布缺陷 来源。在生成随机数字序列时, 但在测试时,我们必须避免这种混合和处理阶段 信息。

举一个明显的例子,说明为什么在想要测试未处理的数据时 测试实际的熵源,这是一个实验。它应该在任意一个 安装了 OpenSSL 的现代 Linux 系统。

head -c 1000000 /dev/zero >zero.bin
openssl enc -aes-256-ctr -in zero.bin -out random.bin -nosalt -k "password"

该方法从 /dev/zero 中占用 100 万个字节,通过 AES-256 对它们进行加密,以 密码安全系数低且不含盐(当然,这是一个可怕的加密方案!)。事实上 输出结果好像是优质的随机数据, 但这也显示了根据模型估算熵内容的风险, 处理的数据:一起,/dev/zero 和“password”提供大约 0 位的熵, 但我们的测试对结果数据更加乐观!

如需更具体的与锆石相关的示例,请考虑抖动熵(RNG http://www.chronox.de/jent/doc/CPU-Jitter-NPTRNG.html)。 抖动根据 CPU 时间的变化绘制熵。未处理的数据 是运行某一 CPU 密集型和内存密集型代码块所需的时间 (以纳秒为单位)。当然,这些时间数据并非完全随机: 以平均值为中心,但有一些波动。每个 单个数据样本可能是数位(例如 64 位整数),但只有 贡献不超过 1 位的最小熵。

完整的抖动 RNG 代码需要几个原始时间数据样本, 将它们处理为单个随机输出(通过 LFSR 转换, 其他内容)。如果我们测试处理后的输出,会发现明显的随机性 包括来自实际时间变化和 LFSR我们希望重点介绍 因此我们应该测试原始时间样本。请注意, 您可以通过 kernel.jitterentropy.raw 命令行。

质量测试实现

如上所述,NIST 测试套件将充满随机字节的文件作为 输入。我们在 Zircon 系统上收集这些字节(可能具有较薄的紫红色 然后通常将它们导出到功能更强大的工作站 测试套件

启动时测试

系统会在启动期间启动用户空间之前读取我们的一些熵源。 为了在真实环境中测试这些熵源,我们运行测试 启动。相关代码位于 kernel/lib/crypto/entropy/quality\_test.cpp,但基本思路是 内核会分配一个较大的静态缓冲区以在前期启动期间保存测试数据 (在 VMM 启动之前,因此在分配 VMO 之前)。之后, 并将 VMO 数据复制到 userboot 和 devmgr 中,其中 它会以伪文件的形式呈现在 /boot/kernel/debug/entropy.bin。用户空间 应用可以读取该文件并导出数据(通过复制到永久性存储空间或 使用网络)。

从理论上讲,通过熵收集器测试,你应该能够构建锆石 使用 scripts/entropy-test/make-parallel 启用后,您应该能够 使用脚本运行单个启动时测试 scripts/entropy-test/run-boot-testrun-boot-test 脚本主要用于 预期会由其他脚本调用,因此,对代码 边缘(例如,它的大多数参数都通过命令行选项传递) 例如-a x86-64,但其中许多“选项”实际上是强制性的)。

假设 run-boot-test 脚本成功,它应该会在 输出目录:entropy.000000000.binentropy.000000000.meta。通过 第一个是从熵源收集的原始数据,第二个是从熵源收集的原始数据, 简单文本文件,其中每行都是一个键值对。键为单个字词 匹配 /[a-zA-Z0-9_-]+/,这些值通过空格匹配分隔 /[ \t]+/。可以在 Bash 中轻松通过 read 解析此文件, 在 Python 中为 str.split(),或者(通常谨慎对待缓冲区溢出) scanf 的 C 语言。

在实际操作中,我担心这些脚本中的位腐烂,因此接下来的几个 部分介绍了脚本的预期用途, 或在脚本中断时手动修复脚本。

启动时测试:构建

由于启动时熵测试需要 永久预留(针对 VMM 之前的临时缓冲区),我们通常不会构建 将熵测试模式嵌入内核中。要启用这些测试,您需要将 构建时使用 ENABLE_ENTROPY_COLLECTOR_TEST 标志,例如添加以下代码行

EXTERNAL_DEFINES += ENABLE_ENTROPY_COLLECTOR_TEST=1

发送至 local.mk。目前还有一个构建时常量, ENTROPY_COLLECTOR_TEST_MAXLEN:(如果提供)是 静态分配的缓冲区。如果未指定,则默认值为 1MiB。

启动时测试:配置

启动时测试通过内核 cmdline 控制。相关 cmdline kernel.entropy-test.*,记录在 kernel_cmdline.md

一些熵源(尤其是抖动源)的参数值可 通过内核 cmdline 进行调整。同样,请参阅 kernel_cmdline.md 了解更多详情。

启动时测试:正在运行

只要启动过程正确无误,启动时测试就会在启动期间自动运行 会传递内核 cmdlines(如果 cmdlines 有问题、错误 消息)。这些测试在 RNG 种子,发生在 LK_INIT_LEVEL_PLATFORM_EARLY 之前不久 VMM 启动的堆如果运行大型测试,启动速度通常会变慢 明显下降。例如,从 Android 6.0 平台上的 rpi3 可能需要大约一分钟的时间,具体取决于参数值。

运行时测试

TODO(https://fxbug.dev/42098992):讨论实际的用户模式测试过程

目前的大致思路:只有内核可以触发 hwrng 读取。要进行测试 用户空间发出内核命令(例如 k hwrng test),其中一些参数 指定测试来源和长度。内核会将随机字节收集到 位于 /boot/kernel/debug/entropy.bin 的现有 VMO 支持的伪文件,假设 确认这是可安全写入的目前尚未实现;由于缺少 用户空间 HWRNG 驱动程序。可以先测试 VMO 重写机制。

测试数据导出

测试数据保存在 Zircon 系统的 /boot/kernel/debug/entropy.bin 中 测试。到目前为止,我通常通过 netcp 手动导出数据文件。 如果您使用正确的 Fuchsia 软件包进行构建,则其他选项包括 scp;或者 保存到永久性存储空间

运行 NIST 测试套件

注意:实际上,NIST 测试并未在 Fuchsia 中反映出来。现在,您需要 从代码库克隆测试(位于 https://github.com/usnistgov/SP800-90B_EntropyAssessment.

NIST 测试套件有三个入口点(截至 2008 年 10 月提交的版本。 2016):iid_main.pynoniid_main.pyrestart.py。两个“主要” 脚本会执行大部分工作。iid_main.py 脚本旨在 生成独立、等分布数据样本的熵源。 大多数测试是验证 iid 条件。许多熵源 不是 iid,因此 noniid_main.py 测试会实现多个熵估算器 不需要 iid 数据的数据。

请注意,来自 NIST 代码库的测试二进制文件是不含 Shebang 行,因此您可能需要对命令明确调用 python

前两个脚本有两个必需参数:要读取的数据文件、 和每个样本的有效位数量(如果小于 8,则仅低 N 位)。它们可以选择接受 -v 标志以生成 详细输出或 -h 以获取帮助。

noniid_main.py 还可以选择接受 -u <int> 标志,该标志可减少 低于在第二个必需参数中传递的 N 值的位数。 我不太清楚为什么提供此标志;但其功能 是多余的,但传递它确实会略微更改详细输出。我最猜的 之所以提供该结果,是因为非国际化马尔可夫检验只适用于 最多为 6 位,因此 7 位或 8 位数据集将降低到其低 6 位, 此测试。相比之下,所有 iid 测试都可以在 8 位样本上运行。

iid_main.py 脚本的示例调用:

python2 -- $FUCHSIA_DIR/third_party/sp800-90b-entropy-assessment/iid_main.py -v /path/to/datafile.bin 8

restart.py 脚本接受相同的两个参数,外加第三个参数: 上一次运行 iid_main.py 返回的最小熵估算值,或 noniid_main.py。本文档未介绍重启测试。目前,请参阅 NIST SP800-90B 了解更多详情。

未来方向

自动化

如果能自动化构建、配置和运行 质量测试。首先,应该可以轻松编写 Shell 脚本, 执行这些步骤。更好的方法是使用测试基础架构 自动运行熵收集器质量测试,主要是为了减少位衰减 。如果自动化操作失败,我们只能依靠人工进行定期 运行测试(或修复测试中断时的问题)。