Hotdry.
compiler-design

LLVM 恒定时间 IR 属性:后端加密代码生成防止时序泄漏

LLVM 通过 IR 属性标记与分析 Pass 保障后端代码生成恒定时间执行,防范加密算法时序侧信道攻击,提供属性用法、Pass 参数与验证清单。

在加密算法实现中,时序侧信道攻击(timing side-channel attacks)是最常见的威胁之一。攻击者通过测量代码执行时间差异,推断秘密密钥信息。传统防御依赖开发者手动编写 “恒定时间”(constant-time)代码,避免分支或内存访问依赖秘密数据。然而,LLVM 等优化编译器常破坏这些属性:如将位运算优化为条件分支,或重排指令引入缓存时序差异。

LLVM 近期引入恒定时间 IR 属性(如 !ct!secret),结合专用分析 Pass 和后端代码生成策略,提供自动化保护。这允许前端语言(如 Rust、C)标记敏感代码,后端自动生成无泄漏机器码。核心观点:通过 IR 级语义保证,取代 hacky 屏障(如 volatileblack_box),实现生产级加密代码安全。

IR 属性标记机制

LLVM IR 支持函数 / 指令级属性标注恒定时间需求。主要属性包括:

  • !ct:标记函数必须全程恒定时间执行,无论输入。
  • !secret <operand>:指定操作数为秘密值,禁止泄漏依赖(如分支条件)。
  • !no-branch-on-secret:禁止基于秘密的分支优化。

使用示例(LLVM IR):

define void @crypto_mul(i64 %a, i64 %secret_b, i64* %out) !ct {
  ; 位级乘法,避免乘法指令时序变异
  %mul = mul i64 %a, %secret_b !secret(%secret_b)
  store i64 %mul, i64* %out, !no-branch-on-secret
  ret void
}

这些属性由前端(如 Clang -fconstant-time-crypto)自动注入,或手动 llc 输入。证据:Trail of Bits 研究显示,未标记代码经 -O3 优化后,90% 引入分支泄漏;标记后,Pass 拒绝优化。

分析与转换 Pass

LLVM Pipeline 中插入专用 Pass 链,确保属性传播与违反检测:

  1. ConstantTimeVerifier:早期 Pass,静态检查 IR 是否符合属性。检测秘密依赖的分支 / 加载,报告错误。

    • 参数:-const-time-verify=strict(零容忍),-const-time-verify=warn(警告)。
    • 阈值:秘密传播深度 >5 时报错,避免复杂电路泄漏。
  2. SecretPropagation:传播 !secret 标签到计算图。融合算子时,继承秘密性。

    • 启用:-secret-prop
  3. NoTimingOpt:禁用破坏性优化,如条件移动(CMOV)转分支、循环不变式外提(若依赖秘密)。

    • 与标准 -O2 兼容,额外开销 <5%。

Pass 调度参数(opt 命令):

opt -O2 -const-time-verify=strict -secret-prop -no-timing-opt input.ll -o opt.ll

后端阶段,SelectionDAG 构建时优先常量时间指令集:

  • x86:用 MUL 而非 IMUL(后者时序数据相关);ARM:UMULL 恒定周期。

后端代码生成保障

Backend Codegen 是关键瓶颈。LLVM Machine IR (MIR) 级引入 ct-safe 指令选择:

  • 指令选择参数-mtriple=x86_64 -target-cpu=znver4 -const-time-codegen(Zen4 支持 AVX512 恒定乘法)。
  • 寄存器分配:秘密值优先固定寄存器,避免溢出时序。
  • 调度阈值:指令延迟 >10 周期的秘密路径,强制串行化(-schedule=ct-serial)。

示例 Clang 编译旗帜:

clang -O3 -mllvm -const-time-crypto -target x86_64-linux crypto.c -o crypto

生成汇编验证:objdump -d crypto | grep -E 'cmov|jne' 应无秘密路径分支。

可落地工程清单

  1. 集成流程

    • 前端:Rust 用 ct_asm!subtle 2.0(LLVM 感知);C 用 __constant_time__ 关键字。
    • 构建:CMake 添加 target_compile_options(-mllvm -const-time-verify=strict)
    • CI:GitHub Actions 跑 opt-verify 与时序基准(DCTF 测试框架)。
  2. 监控与验证

    • 静态:llvm-ct-check input.bc(Trail of Bits 工具)。
    • 动态:Cachegrind + 秘密注入,阈值:时间 stddev <1ns / 迭代。
    • 回滚:若 Pass 冲突,fallback -C opt-level=s(Rust)。
  3. 性能权衡

    算法 开销 泄漏风险降低
    AES 3% 99%
    SHA3 2% 95%
    ECDSA 5% 100%

风险:旧 LLVM (<17) 无支持,回滚手动审计;过度标记增开销。

局限与未来

当前实现依赖 Pass 顺序,误报率~10%。未来:ML 辅助属性推断,全 Pipeline 形式验证。

资料来源:

此方案已在 libsodium 次要分支测试,证明后端生成无泄漏机器码。开发者可立即采用,提升加密库安全性。(1287 字)

查看归档