本文档介绍了我们如何测试用于 是 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-test
。run-boot-test
脚本主要用于
预期会由其他脚本调用,因此,对代码
边缘(例如,它的大多数参数都通过命令行选项传递)
例如-a x86-64
,但其中许多“选项”实际上是强制性的)。
假设 run-boot-test
脚本成功,它应该会在
输出目录:entropy.000000000.bin
和 entropy.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.py
、noniid_main.py
和 restart.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 脚本, 执行这些步骤。更好的方法是使用测试基础架构 自动运行熵收集器质量测试,主要是为了减少位衰减 。如果自动化操作失败,我们只能依靠人工进行定期 运行测试(或修复测试中断时的问题)。