1. 引言
时间攻击是侧信道攻击的一种,利用执行时间的变化来提取秘密信息。
与密码分析不同,密码分析旨在发现弱点并突破密码学协议的理论安全保证,而时间攻击则利用特定协议中的实现缺陷。虽然某些特定的密码学构造(如非对称加密)可能更容易受到时间攻击的影响,但这一攻击向量可以影响任何密码学实现。
为了减轻时间攻击,最佳实践是确保实现是常数时间的,即密码学函数的执行时间应保持不变,不论输入是什么。在实践中,应该确保代码路径和任何内存访问与秘密数据无关。 并非所有的时间差异都能被利用,但消除所有差异可以确保实现的安全性。为了确保实现是常数时间的,密码学从业者开发了各种工具来检测非常数时间代码。
本文分为两个部分:
- 第一部分为背景信息:介绍了时间攻击的基本概念和一个具体的示例
- 第二部分着重介绍了不同的工具,供从业者检查实现是否是常数时间的,并将其分类为四个不同的类别,每个类别都有其优点和限制。
2. 背景
密码学实现的时间攻击最早由Kocher在其1996年论文《Timing Attacks on Implementations of Diffie-Hellman, RSA, DSS, and Other Systems》 中提出。多年来,各种研究人员对这些攻击进行了扩展。特别是,Schindler 2000年论文《A Timing Attack against RSA with the Chinese Remainder Theorem》演示了针对RSA实现的攻击,该实现采用了特定的优化改进,2005年,Brumley和Boneh发布了《Remote Timing Attacks are Practical》,成功从OpenSSL中提取了私钥。同时,像AES这样的对称密码也可能受到时间攻击的影响,正如在2005年论文 《Cache-timing attacks on AES》中所示。
最近,后量子算法Kyber在其官方实现中发现了时间漏洞,称为KyberSlash(详情见2024年论文KyberSlash: Exploiting secret-dependent division timings in Kyber implementations)。CWE-385: Covert Timing Channel目录跟踪了在实现中发现的时间漏洞。
通常,要利用时间攻击,必须满足两个关键先决条件:
- 1)可以访问一个允许进行足够查询的oracle。
- 2)秘密数据与攻击者控制的数据之间存在时间依赖性。
所需的查询次数取决于时间泄漏的严重性。如果时间泄漏信号相对于所有其他指令或网络延迟引入的噪声较强,可能只需要少量的测量;否则,可能需要数百万次。时间依赖性是由于执行踪迹或指令时序的差异而产生的。
2.1 常见的常数时间违反模式
四种最常见的违反常数时间属性的模式,都是依赖于秘密数据的:
- 1)条件跳转:条件跳转会导致执行不同的指令,并通常导致四种模式中最显著的时间差异。使程序的执行流程依赖于秘密数据,将导致巨大的时间差异,具体取决于两个分支之间的差异有多大。
- 2)数组访问:依赖于秘密数据的数组访问和更一般的内存访问,可能会通过访问内存位置时的时间差异来提取索引值。这些时间差异主要源于缓存的使用,以及某个给定值是否位于缓存中。像AES这样的密码算法,它们使用依赖于秘密数据的替代表,即使在网络中,也很容易受到这种攻击,如2005年论文《Cache-timing attacks on AES》中所示。
- 3)整数除法(依赖于处理器):如果除数数量依赖于秘密数据,可能会泄露秘密。这些操作可能会根据使用的CPU架构或编译器泄漏秘密数据。
- 4)移位操作(依赖于处理器):如果移位的数量依赖于秘密数据,可能会泄露秘密。这些操作可能会根据使用的CPU架构或编译器泄漏秘密数据。
c
// 1. 条件跳转
if(secret == 1):
{
...
}
while(secret > 0)
{
...
}
// 2. 数组访问
lookup_table[secret];
// 3. 整数除法(依赖于处理器)
data = secret / m;
// 4. 移位操作(依赖于处理器)
data = a << secret;
在编写使用秘密数据进行操作的代码时,应考虑这四种模式,并尽量避免它们。
如果因为密码学算法的要求而无法避免这些模式,则应该采用掩码技术(见2013年论文《Masking against Side-Channel Attacks: A Formal Security Proof》),以消除或减少执行时间与秘密数据之间的相关性。
下一节将说明如何在模幂运算中利用条件跳转来实现时间攻击。
2.2 示例:模幂运算时间攻击
Kocher 1996年论文[《Timing Attacks on Implementations of Diffie-Hellman, RSA, DSS, and Other Systems》](https://paulkocher.com/doc/TimingAttacks.pdf)展示了用于计算模幂运算的算法容易受到时间攻击。像RSA和Diffie-Hellman这样的流行密码学系统都使用模幂运算,因此这种漏洞构成了一个重大的安全风险。如,在RSA中,解密涉及将密文 c t ct ct 提升到秘密指数 d d d,并对公共模数 N N N 取模:
c t d m o d N ct\^{d} \\mod{N} ctdmodN
如果攻击者可以在相同的秘密指数 d d d下,使用不同的密文值 c t ct ct查询解密函数,他们可能会根据计算所花费的时间推断出秘密指数 d d d值。由于模幂运算计算量大且广泛使用,优化此操作可以显著提高性能。这样的一种优化方法被称为*二次幂运算* 或*从右到左的二进制方法* ,可将乘法次数减少为 log d \\log d logd。
Input: base y , exponent d = { d n , ⋯ , d 0 } 2 , modulus N r = 1 for i = ∣ n ∣ downto 0 : if d i = = 1 : r = r ∗ y m o d N y = y ∗ y m o d N return r \\begin{align} \& \\textbf{Input: } \\text{base }y,\\text{exponent } d=\\{d_n,\\cdots,d_0\\}_2,\\text{modulus } 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} Input: base y,exponent d={dn,⋯,d0}2,modulus Nr=1for i=∣n∣ downto 0:if di==1:r=r∗ymodNy=y∗ymodNreturn r
生成的代码会根据指数位 d i d_i di进行分支,违反了前面提到的*条件跳转*原则。
* 如果指数位为 d i = 1 d_i=1 di=1,则执行额外的乘法操作 r = r ∗ y r=r\*y r=r∗y,导致更长的执行时间,从而泄漏出指数 d d d 中 1 1 1和 0 0 0的位数。
此外,一种常用的模乘技术叫做*Montgomery蒙哥马利乘法* ,它不是常数时间的,并且根据模数和乘法结果执行额外的计算。如果乘法的中间值超过模数 N N N,则需要执行归约步骤。额外的归约步骤会导致可观察到的时间差异。
为了利用这些变化,攻击者可以构造两个输入 y y y 和 y ′ y' y′,使得:
y 2 \< y 3 \< N y ′ 2 \< N ≤ y ′ 3 \\begin{align\*} y\^2 \< y\^3 \< N \\\\ y'\^2 \< N \\leq y'\^3 \\end{align\*} y2\