4. 物理攻击与防护:功耗分析、电磁辐射、故障注入与时序攻击

各位,这一章我们聊聊物理攻击。说白了,就是攻击者拿着示波器、探针、甚至激光器,直接对着你的芯片动手。我早年做第一颗安全芯片时,总觉得算法够强就行,结果被实验室的同事用一台老式示波器就破了功。从那以后,我再也不敢小看物理攻击了。

物理攻击种类很多,但核心就四类:功耗分析、电磁辐射、故障注入、时序攻击。咱们一个一个拆开讲。

物理攻击与防护知识体系 物理攻击与防护 功耗分析攻击 SPA / DPA 掩码 / 隐藏 双轨逻辑 电磁辐射分析 EM 探针扫描 屏蔽罩 / 去耦 差分布线 故障注入攻击 激光 / 电磁脉冲 时钟毛刺 / 电压毛刺 错误检测 + 冗余 时序攻击 数据相关延迟 恒定时间实现 分支平衡 防护目标:消除侧信道信息泄露

4.1 功耗分析攻击:SPA 与 DPA

功耗分析,就是盯着芯片的电流变化来猜密钥。CMOS 电路有个特点:数据翻转时耗电,不翻转时省电。攻击者就利用这个物理特性。

4.1.1 简单功耗分析(SPA)

SPA 最直接。攻击者直接看功耗波形,就能识别出芯片在执行什么操作。比如 RSA 的平方-乘算法,乘法和平方的功耗特征不一样,一眼就能看出来。

SPA 攻击实例:DES 的 16 轮迭代,每一轮功耗波形都不同。攻击者数一数波形峰谷,就知道轮数,甚至能推断出密钥比特。

防护思路其实不复杂:让所有操作的功耗看起来一样。我习惯用「功耗隐藏」技术,比如插入 dummy 操作,或者用双轨逻辑——每条信号线都配一条互补线,保证每次翻转都消耗相同能量。

4.1.2 差分功耗分析(DPA)

DPA 比 SPA 狠得多。它不直接看波形,而是用统计方法。攻击者采集几千、几万条功耗曲线,然后按一个假设的密钥比特分组,做差分统计。如果假设对了,波形上就会出现一个明显的尖峰。

为什么会这样?因为正确的假设能准确预测某个中间值的翻转概率,从而和实际功耗对齐。错误的假设就是一堆噪声。

攻击类型所需样本数攻击难度典型防护
SPA1 ~ 10 条低操作隐藏、双轨逻辑
DPA1000 ~ 100000 条中掩码、随机延时、功耗平衡
高阶 DPA10万+ 条高高阶掩码、动态重计算

避坑指南:我曾经在一个项目中只做了 SPA 防护,觉得 DPA 离我太远。结果第三方评测机构用 5000 条曲线就破了我的 AES 引擎。从那以后,我所有安全模块都默认上掩码。

掩码是 DPA 防护的基石。简单说,就是把每个敏感值和一个随机数做异或,让攻击者猜不准中间值。但要注意,掩码不是万能的——高阶 DPA 能同时分析多个中间值,所以掩码阶数也要跟着提高。

4.2 电磁辐射分析与屏蔽

电磁辐射和功耗分析本质是一回事。芯片工作时会向周围辐射电磁波,辐射强度和内部电流变化直接相关。攻击者拿一个 EM 探针贴近芯片表面,就能采集到和功耗类似的信号。

EM 攻击有个优势:空间分辨率高。探针可以定位到芯片的某个具体模块,甚至某条总线。我见过一个案例,攻击者用 EM 探针直接读出了 AES 的轮密钥,因为密钥寄存器的辐射信号太强了。

4.2.1 屏蔽技术

防护 EM 攻击,最直接的办法就是加屏蔽罩。金属罩子把芯片包起来,电磁波出不去。但屏蔽罩不是万能的——探针可以从电源引脚、封装缝隙里捡到信号。

  • 顶层金属屏蔽层:在芯片最上层铺一块完整的金属层,接地。能挡住大部分垂直方向的 EM 辐射。
  • 差分布线:关键信号走差分线,两条线辐射互相抵消。我习惯在 AES 数据路径上用差分对。
  • 去耦电容:在电源引脚附近加电容,滤掉高频辐射成分。

注意:屏蔽层不能有缝隙。哪怕一条细缝,都可能成为 EM 泄漏的天线。我曾经吃过这个亏——屏蔽层上有个过孔没盖住,结果 EM 信号从那个孔里全漏出来了。

4.3 故障注入攻击与检测

故障注入,就是故意让芯片出错。攻击者用激光、电磁脉冲、时钟毛刺、电压毛刺等手段,在芯片执行关键操作时制造一个错误。比如,让 AES 的最后一轮少算一次,或者让 RSA 的签名跳过某个校验。

为什么这能破密码?因为错误的计算结果会泄露密钥信息。最经典的例子是 Bellcore 攻击——对 RSA 签名注入一个故障,然后对比正确和错误的签名,就能算出私钥。

4.3.1 常见故障注入手段

注入方式精度成本典型效果
激光注入微米级高单比特翻转
电磁脉冲毫米级中多比特翻转
时钟毛刺全局低时序违规
电压毛刺全局低逻辑错误

4.3.2 检测与防护

防护故障注入,核心思路就两条:检测到故障就报警,或者让故障不影响结果。

  • 冗余计算:把关键运算算两遍,结果不一致就报错。我建议用时间冗余(同一模块算两次)和空间冗余(两个模块同时算)结合。
  • 错误检测码:在数据路径上加 CRC 或奇偶校验,能检测到单比特翻转。
  • 传感器:在芯片上集成光敏、电压、频率传感器。激光打过来,光敏传感器先报警,芯片直接复位。

实战经验:我在一颗安全 MCU 上做过故障注入防护。用了双核锁步——两个 CPU 核执行相同代码,每个周期比较结果。一旦不一致,立即触发安全中断。代价是面积翻倍,但安全等级直接拉满。

4.4 时序攻击与恒定时间实现

时序攻击,说白了就是「看时间猜密钥」。如果某个操作的执行时间依赖于输入数据,攻击者就能通过测量时间推断出密钥比特。

最经典的例子是 RSA 的模幂运算。如果实现中用到了「如果当前比特为 1 就执行乘法,为 0 就跳过」,那么执行时间就和密钥的汉明重量相关。攻击者测几次时间,就能把密钥比特猜个七七八八。

4.4.1 恒定时间实现

防护方法很简单:让所有路径的执行时间都一样。这就是恒定时间实现。

// 不安全的实现:时间依赖数据
if (secret_bit) {
    result = multiply(a, b);
} else {
    // 什么都不做
}

// 恒定时间实现:总是执行乘法,但用掩码选择结果
mask = -secret_bit;  // 0 或 0xFFFFFFFF
result = (multiply(a, b) & mask) | (result & ~mask);

你看,第二个版本不管 secret_bit 是 0 还是 1,都执行了乘法。时间就固定了。

小技巧:我写恒定时间代码时,会刻意避免所有条件分支和查表操作。查表的时间依赖于索引,索引如果是密钥相关,那就等于给攻击者送情报。

4.4.2 其他时序防护手段

  • 固定循环次数:不管数据多少,循环都跑满固定次数。
  • 随机延时插入:在操作中插入随机等待,让攻击者测不准时间。但注意,这只能增加采样量,不能彻底消除信息泄露。
  • 缓存无关算法:防止缓存命中率泄露数据。比如用位切片技术,让所有内存访问模式和数据无关。

重要提醒:恒定时间实现不是万能的。编译器优化可能会把你的精心设计打回原形。比如,编译器可能把「看起来没用的乘法」优化掉。我建议每次编译后都反汇编检查一下,确保恒定时间逻辑没被优化掉。

嗯,物理攻击这块内容不少,但核心思想就一个:消除侧信道信息泄露。不管是功耗、电磁、故障还是时序,攻击者都是在利用芯片的物理行为。我们的任务,就是让这些物理行为和密钥彻底脱钩。