CDF 是一个用于自动测试加密软件正确性和安全性的工具。CDF 能够检测实现错误、合规失败、侧信道泄露等问题。
CDF 实现了单元测试与“差异模糊测试”的结合,该方法通过比较相同原语不同实现在输入边缘情况和最大化代码覆盖率的值时的行为来工作。
与通用模糊测试器和测试软件不同,CDF 具有以下特点:
CDF 的目标是为开发者和安全研究人员提供更高效的测试工具,比测试向量更有效,比人工审计或形式化验证更便宜。
CDF 首次在 Black Hat USA 2017 上展示。您可以查看我们演示的幻灯片,其中包含关于 CDF 原理和设计的通用信息。
CDF 使用 Go 编写,当前版本使用 Go 1.8 开发。除了 Go 的标准库外,没有其他依赖。
然而,我们提供了使用 CDF 进行测试的示例程序,这些程序使用 C、Python、C++、Java 和 Go 编写,并且需要特定的加密库才能运行。当前需要的库有:
make 将构建 cdf 二进制文件。
在 example 目录下提供了一系列示例程序:make examples-all 将构建所有示例,而 make examples-go 将只构建 Go 示例。
make test 将运行(CDF 的)单元测试。
对于初学者,您可能想通过运行 cdf -h 查看使用信息。
然后您可以尝试一个示例,例如针对 RSA OAEP 的 Go 和 CryptoPP 示例使用 rsaenc 接口。将 CryptoPP 视为参考,您可以通过以下方式测试 Go 实现:
cdf rsaenc /examples/oaep_rsa2048_go /examples/oaep_rsa2048_cryptopp
该命令将执行特定于 rsaenc 接口的各种测试。
在此示例中,CDF 应该会抱怨 Go 实现支持的最大公指数大小:如果我们查看其代码,可以看到公指数被存储为普通整数,而在 CryptoPP(以及大多数其他实现)中,它被存储为大整数。然而,这是故意设计的,很可能不会被更改。
参数在 config.json 中定义。
大多数参数都是不言自明的。您可能想要为 rsaenc 和 ecdsa 设置其他私钥(这些接口使用固定密钥进行测试,尽管某些密钥参数(如指数)会在某些测试中更改)。
seed 参数允许您更改 CDF 伪随机生成器中使用的种子。(然而,被测程序可能使用其他方式播种的 PRNG,例如 OAEP 示例。)concurrency 参数允许您设置在派生程序时 CDF 应产生的并发 goroutine 数量。注意最好将此数字保持在真实核心数以下。verboseLog 参数如果设置为 true,将会将所有程序的输入和输出(即使是成功的测试)写入文件 log.txt。
为了使用 CDF 测试您的软件,您必须创建一个程序,该程序读取输入并按照 CDF 接口写入输出,并在内部调用被测程序。 CDF 接口是加密功能的抽象,以便允许对任意实现进行黑盒测试。
例如,如果您实现了 ECDSA 签名方案,您的程序应满足 ecdsa 接口,并且分别需要 4 或 5 个参数来签名消息或验证签名。这些参数是公钥 X 坐标、公钥 Y 坐标、私钥 D 大整数以及要签名的消息,然后它应仅输出大整数 R 和 S,每个占一行。或者,要验证消息,它应接受 X、Y、R、S 和消息,然后应仅输出 True 或 False。接口规范在下面详细说明。
我们的接口实现示例将帮助您创建自己的接口。
错误处理留给被测程序,但为了让 CDF 有意义的错误信息,最好在失败时退出,返回错误代码并打印错误消息。
接口程序可以用任何语言编写,只需是一个符合 CDF 接口的可执行文件即可。 接口程序通常使用与被测程序相同的语言编写,但这不是强制性的(例如,对于 Java 程序,它可能是另一种语言的包装器)。
CDF 当前支持以下接口,其中参数编码为十六进制 ASCII 字符串,除非另有说明:
dsa 接口测试数字签名算法(DSA)的实现。它必须支持签名和验证操作:
| 操作 | 输入 | 输出 |
|---|---|---|
| 签名 | p q g y x m | r s |
| 验证 | p q g y r s m | 真值 |
这里 p、q、g 是 DSA 参数,y 是公钥,x 是私钥,m 是消息,r 和 s 构成签名,必须用换行符分隔返回。真值,要么是“true”要么是“false”,表示为字符串。
dsa 接口支持可选测试:-h 标志允许绕过哈希过程,直接提供要签名的哈希值。这使得 CDF 能够执行更多测试,例如检查溢出或哈希截断。
ecdsa 接口测试椭圆曲线数字签名算法(ECDSA)的实现。它必须支持签名和验证操作:
| 操作 | 输入 | 输出 |
|---|---|---|
| 签名 | x y d m | r s |
| 验证 | x y r s m | 真值 |
这里 x 和 y 是 ECDSA 公钥坐标,d 是私钥,m 是消息,r 和 s 构成签名,必须用换行符分隔返回。真值,要么是“true”要么是“false”,表示为字符串。
标志 -h 的作用与 dsa 相同。
请注意,我们当前的设计假定了一个固定的曲线,该曲线在被测程序中定义。
为了在这些测试中获得可重现的结果并充分利用 CDF 检测能力,您必须使用固定种子为随机生成器播种,或使用确定性 ECDSA 变体,否则 CDF 无法自动检测诸如相同标签问题之类的问题。
enc 接口测试对称加密和解密操作,通常在使用分组密码时(流密码可以使用 prf 接口进行测试)。它必须支持加密和解密:
| 操作 | 输入 | 输出 |
|---|---|---|
| 加密 | k m | c |
| 解密 | k c | r |
这里 k 是密钥,m 是消息,c 是密文,r 是恢复的明文。
prf 接口测试带密钥的哈希(伪随机函数、MAC),以及流密码:
| 操作 | 输入 | 输出 |
|---|---|---|
| 计算 | k m | h |
这里 k 是密钥,m 是消息(对于流密码来说是对应 nonce),h 是 PRF 计算的结果。我们的接口假定固定密钥大小和可变输入长度。如果需要指定特定密钥,则由被测程序负责忽略密钥输入,或者可以选择使用 xof 接口。
rsaenc 测试 RSA 加密和解密,包括 OAEP(PKCS 2.1)和 PKCS 1.5:
| 操作 | 输入 | 输出 |
|---|---|---|
| 加密 | n e m | c |
| 解密 | p q e d c | r |
这里 n 是模数,e 是公指数(为了与某些库兼容,解密时也需要 e),m 是消息,p 和 q 是 n 的因子(要求 p > q,因为库通常要求如此),d 是私指数,r 是恢复的明文。
xof 接口测试哈希函数、可扩展输出函数(XOF)、确定性随机比特生成器(DRBG):
| 操作 | 输入 | 输出 |
|---|---|---|
| 计算 | m | h |
这里 m 是消息,h 是结果。
CDF 基于 JP Aumasson 的初始想法,首次公开于 WarCon 2016,大部分代码由 Yolan Romailler 编写。
CDF 版权归 Nagravision SA 所有(2016-2017),保留所有权利。
CDF 以 GPLv3 许可证发布。