恒定时间测试Skill constant-time-testing

恒定时间测试是一种安全测试技能,用于检测和防止密码学实现中的时序侧信道漏洞。通过分析代码执行时间是否依赖秘密数据,确保恒定时间属性,防止攻击者利用时序差异提取敏感信息。关键词:恒定时间、时序侧信道、密码学安全、漏洞检测、安全测试、密码学实现、时序攻击、侧信道分析。

密码学 0 次安装 0 次浏览 更新于 3/14/2026

名称: 恒定时间测试 类型: 领域 描述: > 恒定时间测试检测密码学代码中的时序侧信道。 用于审计密码实现中的时序漏洞。

恒定时间测试

时序攻击利用执行时间的变化从密码学实现中提取秘密信息。与针对理论弱点的密码分析不同,时序攻击利用实现缺陷——它们可以影响任何密码学代码。

背景

时序攻击由Kocher于1996年提出。此后,研究人员在RSA (Schindler)、OpenSSL (Brumley和Boneh)、AES实现甚至后量子算法如Kyber上展示了实际攻击。

关键概念

概念 描述
恒定时间 代码路径和内存访问独立于秘密数据
时序泄漏 可观察的执行时间差异与秘密数据相关
侧信道 从实现而非算法中提取的信息
微架构 CPU级时序差异(缓存、除法、移位)

为什么这很重要

时序漏洞可以:

  • 暴露私钥 - 提取RSA/ECDH中的秘密指数
  • 启用远程攻击 - 网络可观察的时序差异
  • 绕过密码学安全 - 破坏理论保证
  • 持续无声存在 - 通常未经专门分析难以检测

两个前提条件使利用成为可能:

  1. 访问预言机 - 对易受攻击实现的足够查询
  2. 时序依赖性 - 执行时间与秘密数据之间的相关性

常见的恒定时间违反模式

四种模式占大多数时序漏洞:

// 1. 条件跳转 - 最严重的时序差异
if(secret == 1) { ... }
while(secret > 0) { ... }

// 2. 数组访问 - 缓存时序攻击
lookup_table[secret];

// 3. 整数除法(处理器依赖)
data = secret / m;

// 4. 移位操作(处理器依赖)
data = a << secret;

条件跳转导致不同的代码路径,产生巨大时序差异。

数组访问依赖秘密数据启用缓存时序攻击,如AES缓存时序研究所示。

整数除法和移位操作在某些CPU架构和编译器配置中泄漏秘密。

当模式无法避免时,采用掩蔽技术去除时序与秘密之间的相关性。

示例:模幂时序攻击

模幂运算(用于RSA和Diffie-Hellman)易受时序攻击。RSA解密计算:

$$ct^{d} \mod{N}$$

其中$d$是秘密指数。平方乘幂优化将乘法减少到$\log{d}$:

$$ \begin{align*} & \textbf{输入: } \text{底数 }y,\text{指数 } d={d_n,\cdots,d_0}_2,\text{模数 } N \ & r = 1 \ & \textbf{for } i=|n| \text{ downto } 0: \ & \quad\textbf{if } d_i == 1: \ & \quad\quad r = r * y \mod{N} \ & \quad y = y * y \mod{N} \ & \textbf{return }r \end{align*} $$

代码在指数位$d_i$上分支,违反恒定时间原则。当$d_i = 1$时,发生额外乘法,增加执行时间并泄漏位信息。

Montgomery乘法(常用于模算术)也泄漏时序:当中间值超过模数$N$时,需要额外的约简步骤。攻击者构造输入$y$和$y’$使得:

$$ \begin{align*} y^2 < y^3 < N \ y’^2 < N \leq y’^3 \end{align*} $$

对于$y$,两个乘法都花费时间$t_1+t_1$。对于$y’$,第二个乘法需要约简,花费时间$t_1+t_2$。这种时序差异揭示$d_i$是0还是1。

何时使用

应用恒定时间分析当:

  • 审计密码学实现(原语、协议)
  • 代码处理秘密密钥、密码或敏感密码材料
  • 从头实现密码算法
  • 审查涉及密码代码的PR
  • 调查潜在的时序漏洞

考虑替代方案当:

  • 代码不处理秘密数据
  • 没有秘密输入的公共算法
  • 非密码学时序要求(性能优化)

快速参考

场景 推荐方法 技能
证明无泄漏 形式验证 SideTrail, ct-verif, FaCT
检测统计时序差异 统计测试 dudect
运行时跟踪秘密数据流 动态分析 timecop
查找缓存时序漏洞 符号执行 Binsec, pitchfork

恒定时间工具类别

密码学社区开发了四类时序分析工具:

类别 方法 优点 缺点
形式化 模型上的数学证明 保证无泄漏 复杂度、建模假设
符号化 符号执行路径 具体反例 路径探索时间密集
动态 运行时跟踪标记的秘密 细粒度、灵活 覆盖仅限于执行路径
统计 测量实际执行时序 实用、简单设置 无根本原因、噪声敏感

1. 形式化工具

形式验证在代码的抽象(模型)上数学证明时序属性。工具从源代码/二进制创建模型,并验证其满足指定属性(如变量标注为秘密)。

流行工具:

优势: 无泄漏证明、语言无关(LLVM字节码) 弱点: 需要专业知识、建模假设可能错过实际问题

2. 符号化工具

符号执行分析路径和内存访问如何依赖符号变量(秘密)。提供具体反例。专注于缓存时序攻击。

流行工具:

优势: 具体反例有助于调试 弱点: 路径爆炸导致长执行时间

3. 动态工具

动态分析标记敏感内存区域并跟踪执行以检测时序依赖操作。

流行工具:

优势: 细粒度控制、针对性分析 弱点: 覆盖仅限于执行路径

详细指导: 参见timecop技能以获取设置和用法。

4. 统计工具

执行具有各种输入的代码,测量经过时间,并检测不一致性。测试实际实现包括编译器优化和架构。

流行工具:

优势: 简单设置、实用实际结果 弱点: 无根本原因信息、噪声掩盖弱信号

详细指导: 参见dudect技能以获取设置和用法。

测试工作流

阶段1: 静态分析        阶段2: 统计测试
┌─────────────────┐            ┌─────────────────┐
│ 识别秘密数据流 │      →     │ 检测时序差异   │
│ 工具: ct-verif  │            │ 工具: dudect    │
└─────────────────┘            └─────────────────┘
         ↓                              ↓
阶段4: 根本原因            阶段3: 动态跟踪
┌─────────────────┐            ┌─────────────────┐
│ 精确定位泄漏点 │      ←     │ 跟踪秘密传播   │
│ 工具: Timecop   │            │ 工具: Timecop   │
└─────────────────┘            └─────────────────┘

推荐方法:

  1. 从dudect开始 - 快速统计检查时序差异
  2. 如果发现泄漏 - 使用Timecop精确定位根本原因
  3. 对于高保证 - 应用形式验证(ct-verif, SideTrail)
  4. 持续监控 - 将dudect集成到CI管道

工具和方法

Dudect - 统计分析

Dudect测量两个输入类(固定vs随机)的执行时间,并使用Welch的t检验检测统计显著差异。

详细指导: 参见dudect技能以获取完整设置、使用模式和CI集成。

恒定时间分析的快速入门

#define DUDECT_IMPLEMENTATION
#include "dudect.h"

uint8_t do_one_computation(uint8_t *data) {
    // 要测量的代码放在这里
}

void prepare_inputs(dudect_config_t *c, uint8_t *input_data, uint8_t *classes) {
    for (size_t i = 0; i < c->number_measurements; i++) {
        classes[i] = randombit();
        uint8_t *input = input_data + (size_t)i * c->chunk_size;
        if (classes[i] == 0) {
            // 固定输入类
        } else {
            // 随机输入类
        }
    }
}

关键优势:

  • 简单的C仅头文件集成
  • 通过Welch的t检验实现统计严谨
  • 适用于编译后的二进制(实际条件)

关键限制:

  • 检测到泄漏时无根本原因信息
  • 对测量噪声敏感
  • 不能保证无泄漏(仅统计置信)

Timecop - 动态跟踪

Timecop包装Valgrind以检测依赖秘密内存区域的运行时操作。

详细指导: 参见timecop技能以获取安装、示例和调试。

恒定时间分析的快速入门

#include "valgrind/memcheck.h"

#define poison(addr, len) VALGRIND_MAKE_MEM_UNDEFINED(addr, len)
#define unpoison(addr, len) VALGRIND_MAKE_MEM_DEFINED(addr, len)

int main() {
    unsigned long long secret_key = 0x12345678;

    // 将秘密标记为毒化
    poison(&secret_key, sizeof(secret_key));

    // 任何依赖secret_key的分支或内存访问
    // 都将被Valgrind报告
    crypto_operation(secret_key);

    unpoison(&secret_key, sizeof(secret_key));
}

使用Valgrind运行:

valgrind --leak-check=full --track-origins=yes ./binary

关键优势:

  • 精确定位时序泄漏的准确行
  • 无需代码插桩
  • 跟踪执行过程中的秘密传播

关键限制:

  • 无法检测微架构时序差异
  • 覆盖仅限于执行路径
  • 性能开销(在合成CPU上运行)

实施指南

阶段1:初始评估

识别处理秘密的密码学代码:

  • 私钥、指数、随机数
  • 密码哈希、认证令牌
  • 加密/解密操作

快速统计检查:

  1. 为密码函数编写dudect测试套件
  2. 运行5-10分钟,使用timeout 600 ./ct_test
  3. 监控t值:高绝对值表示泄漏

工具: dudect 预期时间: 1-2小时(套件编写 + 初始运行)

阶段2:详细分析

如果dudect检测到泄漏:

根本原因调查:

  1. 使用Timecop poison()标记秘密变量
  2. 在Valgrind下运行以识别准确行
  3. 审查四种常见违反模式
  4. 检查汇编输出以查找条件分支

工具: Timecop, 编译器输出 (objdump -d)

阶段3:修复

修复时序泄漏:

  • 用恒定时间选择(位操作)替换条件分支
  • 使用恒定时间比较函数
  • 替换数组查找为恒定时间替代方案或掩蔽
  • 验证编译器未优化掉恒定时间代码

重新验证:

  1. 再次运行dudect较长时间(30+分钟)
  2. 在不同编译器和优化级别上测试
  3. 在不同CPU架构上测试

阶段4:持续监控

集成到CI:

  • 将dudect测试添加到测试套件
  • 运行固定时长(CI中5-10分钟)
  • 如果检测到泄漏则构建失败

参见dudect技能以获取CI集成示例。

常见漏洞

漏洞 描述 检测 严重性
秘密依赖分支 if (secret_bit) { ... } dudect, Timecop 关键
秘密依赖数组访问 table[secret_index] Timecop, Binsec
可变时间除法 result = x / secret Timecop
可变时间移位 result = x << secret Timecop
Montgomery约简泄漏 中间值>N时的额外约简 dudect

秘密依赖分支:深入探讨

漏洞: 执行时间基于是否采取分支而不同。常见于优化的模幂运算(平方乘幂)。

如何使用dudect检测:

uint8_t do_one_computation(uint8_t *data) {
    uint64_t base = ((uint64_t*)data)[0];
    uint64_t exponent = ((uint64_t*)data)[1]; // 秘密!
    return mod_exp(base, exponent, MODULUS);
}

void prepare_inputs(dudect_config_t *c, uint8_t *input_data, uint8_t *classes) {
    for (size_t i = 0; i < c->number_measurements; i++) {
        classes[i] = randombit();
        uint64_t *input = (uint64_t*)(input_data + i * c->chunk_size);
        input[0] = rand(); // 随机底数
        input[1] = (classes[i] == 0) ? FIXED_EXPONENT : rand(); // 固定vs随机
    }
}

如何使用Timecop检测:

poison(&exponent, sizeof(exponent));
result = mod_exp(base, exponent, modulus);
unpoison(&exponent, sizeof(exponent));

Valgrind将报告:

条件跳转或移动依赖于未初始化的值
  位于 0x40115D: mod_exp (example.c:14)

相关技能: dudect, timecop

案例研究

案例研究:OpenSSL RSA时序攻击

Brumley和Boneh(2005年)通过网络从OpenSSL中提取RSA私钥。该漏洞利用了Montgomery乘法的可变时间约简步骤。

攻击向量: 模幂运算中的时序差异 检测方法: 统计分析(dudect的前身) 影响: 远程密钥提取

使用工具: 自定义时序测量 应用技术: 统计分析、选择密文查询

案例研究:KyberSlash

后量子算法Kyber的参考实现包含多项式操作中的时序漏洞。除法操作泄漏秘密系数。

攻击向量: 秘密依赖除法时序 检测方法: 动态分析和统计测试 影响: 后量子密码学中的秘密密钥恢复

使用工具: 时序测量工具 应用技术: 差分时序分析

高级用法

技巧与窍门

技巧 为什么有帮助
将dudect固定到隔离的CPU核心(taskset -c 2 减少操作系统噪声,改善信号检测
测试多个编译器(gcc, clang, MSVC) 优化可能引入或移除泄漏
运行dudect较长时间(小时) 增加统计置信度
最小化测试套件中的非密码代码 减少掩盖弱信号的噪声
检查汇编输出(objdump -d 验证编译器未引入分支
在测试中使用 -O3 -march=native 匹配生产优化级别

常见错误

错误 为什么错误 正确方法
仅测试一种输入分布 可能错过其他模式可见的泄漏 测试固定vs随机、固定vs不同固定等
dudect运行时间短(<1分钟) 弱信号测量不足 运行5-10+分钟,高保证需更长时间
忽略编译器优化级别 -O0可能隐藏-O3中存在的泄漏 在生产优化级别测试
未在目标架构上测试 x86 vs ARM具有不同时序特性 在部署平台上测试
在Timecop中标记过多为秘密 误报、结果不清晰 仅标记真正秘密(密钥,而非公共数据)

相关技能

工具技能

技能 在恒定时间分析中的主要用途
dudect 通过Welch的t检验统计检测时序差异
timecop 动态跟踪以精确定位时序泄漏位置

技术技能

技能 何时应用
coverage-analysis 确保测试输入覆盖密码函数的所有代码路径
ci-integration 自动化恒定时间测试在持续集成管道中

相关领域技能

技能 关系
crypto-testing 恒定时间分析是密码学测试的重要组成部分
fuzzing 模糊测试密码代码可能触发时序依赖路径

技能依赖图

                    ┌─────────────────────────┐
                    │  恒定时间分析          │
                    │    (本技能)          │
                    └───────────┬─────────────┘
                                │
                ┌───────────────┴───────────────┐
                │                               │
                ▼                               ▼
    ┌───────────────────┐           ┌───────────────────┐
    │      dudect       │           │     timecop       │
    │  (统计)         │           │    (动态)       │
    └────────┬──────────┘           └────────┬──────────┘
             │                               │
             └───────────────┬───────────────┘
                             │
                             ▼
              ┌──────────────────────────────┐
              │   支持技术                  │
              │ 覆盖率、CI集成              │
              └──────────────────────────────┘

资源

关键外部资源

这些结果必须为假:恒定时间分析工具的可用性评估 恒定时间分析工具的全面可用性研究。关键发现:开发者面临误报、需要更好的错误消息,并从工具集成中受益。评估了FaCT、ct-verif、dudect和Memsan在多个密码学实现上。推荐改进工具UX和更好的文档。

恒定时间工具列表 - CROCS 精选的恒定时间分析工具目录及教程。涵盖形式化工具(ct-verif, FaCT)、动态工具(Memsan, Timecop)、符号化工具(Binsec)和统计工具(dudect)。包括设置和使用的实用教程。

Paul Kocher:Diffie-Hellman、RSA、DSS和其他系统实现上的时序攻击 引入时序攻击的1996年原始论文。展示RSA和Diffie-Hellman中模幂运算的攻击。理解时序漏洞的基本历史背景。

远程时序攻击是实用的(Brumley & Boneh) 展示针对OpenSSL的实用远程时序攻击。显示网络级时序差异足以提取RSA密钥。证明时序攻击在实际网络条件下有效。

AES上的缓存时序攻击 展示使用查找表的AES实现易受缓存时序攻击。演示通过缓存时序侧信道提取AES密钥的实用攻击。

KyberSlash:除法时序泄漏秘密 Kyber(NIST后量子标准)中时序漏洞的最新发现。展示除法操作泄漏秘密系数。突显恒定时间问题甚至在现代后量子密码学中持续存在。

视频资源