1. 项目概述:当加密算法遇上“隔墙有耳”
在数字安全的世界里,我们常常把加密算法想象成一个坚不可摧的保险箱。无论是保护你的在线支付密码,还是确保国家间的机密通信,这些基于复杂数学难题的算法(如AES、RSA、ECC)理论上几乎无法被正面攻破。然而,现实世界中的密码设备并非运行在理想的数学真空里。它们是由晶体管、导线和硅片构成的物理实体,在执行加密运算时,会不可避免地与外部环境产生物理交互。这就好比一个顶级保险箱,虽然锁芯无比复杂,但窃贼却可以通过倾听你转动密码盘时齿轮发出的细微声响,或者观察你输入密码时手指的颤抖,来推测出密码。在密码学领域,这种通过分析密码设备在运行过程中泄露的物理信息(而非攻击算法逻辑本身)来窃取密钥的方法,就叫做侧信道攻击。
我从事硬件安全研究有十来年了,亲眼见证了侧信道攻击从一个学术界的“奇技淫巧”,演变为如今对物联网设备、智能卡、甚至高端服务器处理器都构成现实威胁的“隐形杀手”。侧信道攻击的魅力(或者说可怕之处)在于,它完全绕过了密码算法的数学强度。你的AES密钥可能长达256位,理论上穷举需要宇宙毁灭的时间,但攻击者通过分析你的芯片在加密时消耗的电流波形,可能只需要几百次加密操作,就能在几分钟内把密钥完整地还原出来。这听起来像魔法,但背后是严谨的信号处理、统计学和密码学知识。
侧信道攻击的种类繁多,其中电磁侧信道攻击因其非接触、高精度、难以察觉的特性,成为研究和实战中的“明星”手段。简单来说,任何流经集成电路的电流都会产生环绕的磁场,变化的电流则会产生辐射的电磁场。当芯片内部的晶体管开关,进行与或非等逻辑运算时,其电流的瞬态变化会像一个小型无线电发射器一样,向外辐射出微弱的电磁波。而加密操作,特别是涉及密钥位的运算,会引发特定的电流模式。通过使用一个靠近芯片的微型探头(甚至可以是改装后的收音机天线),捕捉并分析这些电磁辐射,攻击者就能像“窃听”芯片的“脑电波”一样,提取出密钥信息。
这篇文章,我将以一个资深硬件安全工程师的视角,为你彻底拆解电磁侧信道攻击。我不会停留在概念层面,而是会深入到:攻击需要什么样的实验环境(你的“黑客工坊”该有哪些装备)、如何从嘈杂的电磁信号中提取出与密钥相关的“蛛丝马迹”、最核心的差分能量分析和相关性能量分析攻击是如何一步步实现的,以及最重要的——作为开发者,我们该如何从芯片设计、算法实现到系统集成层面,构建起防御的“马奇诺防线”。无论你是嵌入式开发者、安全研究员,还是对硬件安全好奇的爱好者,这篇文章都将为你提供一套从理论到实践的完整认知地图和实操参考。
2. 电磁侧信道攻击的核心原理与物理基础
要理解如何攻击,必须先理解信号从何而来。这需要我们暂时跳出代码和协议的世界,回到物理层面。
2.1 电磁辐射的源头:芯片内部的电流瞬变
现代数字芯片(CPU、MCU、FPGA、ASIC)的基本构建单元是CMOS(互补金属氧化物半导体)晶体管。其核心工作原理可以简化为:通过控制栅极电压,来导通或关断源极和漏极之间的通道,从而决定电流是否流过。
- 逻辑切换产生电流脉冲:当晶体管的输出从逻辑‘0’(低电平)切换到‘1’(高电平)时,它需要给连接的下一个晶体管栅极电容充电。这个充电过程会产生一个从电源到地的电流脉冲。反之,从‘1’切换到‘0’时,栅极电容通过晶体管对地放电,也会产生一个电流脉冲。
- 电流脉冲产生磁场:根据麦克斯韦方程组,任何变化的电流都会产生变化的磁场。这个电流脉冲虽然微小(通常在毫安甚至微安量级),但因其变化极快(纳秒级),产生的磁场变化足以被探测。
- 辐射与传导:这些磁场变化会以两种主要方式泄露:
- 近场辐射:在芯片表面附近(几个厘米内),磁场占主导。这就像变压器初级线圈产生的磁场,可以被紧贴的次级线圈(我们的探测探头)感应到。
- 远场辐射:部分能量会以电磁波的形式辐射到更远的地方,但强度随距离急剧衰减,通常不是侧信道攻击的主要信号源。
关键在于,电流脉冲的强度与同时发生状态翻转的晶体管数量成正比。在执行一条“异或”指令时,如果操作数的某一位是1,对应的电路单元就会发生翻转,消耗电流;如果是0,则可能保持静态。因此,芯片的瞬时功耗(从而产生的电磁辐射强度)与正在处理的数据(包括密钥和明文/密文)直接相关。这就是所有能量分析攻击(包括电磁分析)的理论基石。
2.2 攻击模型与假设
电磁侧信道攻击通常基于一个标准的威胁模型,理解这个模型是设计攻击和防御的前提:
- 攻击者能力:攻击者能够物理接近目标设备(如一台POS机、一个物联网网关、一张智能卡),并能在设备执行加密操作时,使用探测设备测量其电磁辐射。攻击者无法直接篡改设备硬件或软件(即非侵入式攻击),也无法直接读取内存中的密钥。
- 攻击者目标:获取设备中存储的长期密钥(如AES-128密钥、RSA私钥)。
- 设备行为:攻击者可以控制或观察设备的部分输入(如发送特定的明文进行加密),并收集对应的输出(密文)以及同步采集的电磁轨迹。
- 核心假设(汉明重量/汉明距离模型):这是最常用且被广泛验证的假设。它认为芯片泄露的电磁信号强度与数据处理过程中寄存器或总线上的数据位变化量相关。
- 汉明重量模型:假设泄露与某个中间值(如S盒输出)中‘1’的个数(汉明重量)成线性关系。适用于静态功耗占主导或信号采集点位于数据总线的情况。
- 汉明距离模型:假设泄露与寄存器从上一个时钟周期的值切换到当前值所改变的位数(汉明距离)成线性关系。这更贴近实际,因为CMOS电路的主要功耗产生于状态切换。例如,一个8位寄存器从
0x55(01010101) 变为0xAA(10101010),每一位都翻转了,汉明距离为8,预计会产生较强的电磁辐射。
注意:这个线性关系假设是攻击成功的关键,也是防御的突破口。在实际中,由于工艺偏差、噪声、探头位置等因素,关系可能是复杂和非线性的,但线性模型在大多数情况下提供了一个强大且有效的近似。
3. 攻击实验室搭建:从探头到示波器
纸上谈兵终觉浅。要真正理解电磁侧信道攻击,我们必须看看攻击者的“工具箱”里有什么。搭建一个基础的电磁侧信道分析平台,其核心成本已经从数十万美元下降到数千美元,使得这类攻击的门槛大大降低。
3.1 核心装备清单与选型考量
一个典型的攻击平台包含以下部分:
- 目标设备:通常是运行着未加防护加密算法的微控制器开发板(如STM32、Arduino Due)或智能卡。为了简化,我们常使用软件实现(而非硬件加速)的加密算法,因为其操作与时钟同步性好,泄露更规律。
- 电磁探头:这是攻击的“耳朵”。主要有两种类型:
- 磁场探头(近场探头):最常见。它是一个小型环形线圈,用于感应磁场变化。商用探头(如Langer、Beehive)灵敏度高,但价格昂贵(数千元)。自制替代方案:你可以用同轴电缆剥开外屏蔽层,将中心导体绕成直径1-3mm的小环,屏蔽层单点接地。这种自制探头成本极低,在近距离(1-2mm)内效果惊人。
- 电场探头:是一个小金属针,用于感应电场变化。在电磁侧信道中不如磁场探头常用。
- 选型心得:探头面积越小,空间分辨率越高,能定位到芯片上特定的功能模块(如ALU、S盒电路),但捕获的信号总量也越小,信噪比低。初学者建议从直径2-3mm的自制环形探头开始,性价比最高。
- 示波器:这是攻击的“眼睛”,用于将探头感应的模拟电压信号数字化并记录下来。关键参数:
- 带宽:至少需要目标设备时钟频率的3-5倍。如果芯片运行在16MHz,示波器带宽最好在50MHz以上。对于高速芯片(>100MHz),可能需要500MHz甚至1GHz带宽的示波器。
- 采样率:根据奈奎斯特采样定理,至少是信号最高频率的2倍,但实践中需要5-10倍以获得良好波形。对于16MHz时钟,100MS/s(每秒百万采样点)的采样率是起步要求。
- 存储深度:决定了能连续记录多长时间的波形。一次AES-128加密可能需要几百个时钟周期,为了捕捉整个过程的细节,需要足够的存储深度(例如1M点)。
- 实操建议:对于入门级攻击,一台二手的100MHz带宽、1GS/s采样率的示波器(如某些品牌的DS1104Z)是性价比之选。务必开启示波器的高分辨率模式或平均模式,这能有效降低噪声。
- 同步与触发:如何让示波器在加密操作开始的精确时刻开始采集?这是成功的关键。
- 硬件触发:最可靠的方式。从目标设备引出一根GPIO线,在加密函数开始和结束时将其拉高。将这根线接入示波器的外部触发通道。这是必须建立的机制。
- 软件触发:通过串口/UART在加密前后发送特定字符,示波器通过解码串口信号来触发。这种方式有延迟,精度较差。
- 控制与采集计算机:用于控制目标设备(发送明文、启动加密)和示波器(设置参数、读取波形数据)。通常用Python脚本通过USB-TTL、GPIO或LAN(对于网络示波器)进行自动化控制。
3.2 实验设置与信号优化技巧
把设备买回来只是第一步,如何摆放和设置才能抓到“干净”的信号,才是真正的经验所在。
- 探头定位:这是最影响结果的一步。将探头非常缓慢地在芯片表面上方(1mm内)移动,同时让设备持续执行加密操作。观察示波器上的波形,你会看到某些位置的信号幅度突然增大,波形中出现清晰的周期性脉冲(对应时钟信号)。这个位置下方很可能就是芯片的核心逻辑区域或电源引脚。记录下信号最强的几个点,后续攻击在这些点上进行。
- 接地的重要性:探头的屏蔽层必须良好接地,否则会引入巨大的工频(50/60Hz)噪声。将接地夹夹在目标设备板子的地线焊盘上。如果使用自制探头,确保同轴电缆屏蔽层只在探头端接地。
- 示波器设置:
- 垂直刻度:调整到使信号幅度占据屏幕垂直方向的2/3左右,以充分利用ADC的动态范围。
- 触发设置:使用“边沿触发”,源选择外部触发通道,设置在上升沿触发。将触发电平设置为触发信号幅度的中间值。触发模式务必设为“单次”,然后由控制脚本每次加密前“武装”一次触发。
- 带宽限制:如果示波器有20MHz带宽限制功能,可以开启以滤除高频噪声。
- 采集模式:使用“高分辨率”或“平均”模式(平均8-16次),能显著提高信噪比,但注意“平均”模式要求每次加密的泄露完全相同(使用相同的明文和密钥),这只在 profiling 阶段适用。
- 环境降噪:
- 使用电池给目标设备供电,以隔离电网带来的噪声。
- 将整个实验装置放在一个接地的金属盒(法拉第笼)里,可以屏蔽环境中的无线电干扰。
- 关闭附近的手机、Wi-Fi路由器等潜在干扰源。
实操心得:信号采集是“三分设备,七分调试”。花一两个小时耐心地调整探头位置、接地和示波器设置,得到的信号质量差异可能是天壤之别。一个好的信号波形,其时钟边沿应该清晰锐利,背景噪声毛刺很少。我曾在一个项目中,仅仅因为探头接地线松了,导致一整天的攻击实验失败,排查了所有代码和算法后才发现问题所在。
4. 攻击实战:差分能量分析攻破AES-128
理论装备都已就绪,现在让我们发动一次真实的攻击。我们以最经典的差分能量分析攻击AES-128的最后一轮加密为例。这是侧信道攻击的“Hello World”,理解了它,你就掌握了最核心的武器。
4.1 AES算法回顾与攻击点选择
AES-128加密共有10轮。攻击最后一轮(第10轮)的优点是:
- 其输入是第9轮的输出,攻击者不知道,但其输出就是最终的密文,攻击者已知。
- 最后一轮的操作不包括
MixColumns,结构更简单,只有SubBytes(S盒替换)、ShiftRows和AddRoundKey。
我们攻击的目标是最后一轮的轮密钥。在AES-128中,最后一轮的轮密钥就是整个加密密钥经过密钥扩展后得到的第10个轮密钥。通过DPA攻破它,再反向推导出原始主密钥是轻而易举的。
攻击的目标运算选择S盒的输出。设密文的一个字节为C,猜测的最后一轮轮密钥对应字节为K_guess。那么,在最后一轮AddRoundKey和SubBytes操作中,计算出的中间值V为:V = Sbox(C ⊕ K_guess)这里⊕表示异或运算。我们假设泄露的电磁信号与V的汉明重量(即V中二进制‘1’的个数)相关。
4.2 DPA攻击的详细步骤
假设我们已经采集了N条电磁轨迹(例如N=1000),每条轨迹对应一个不同的随机明文加密后得到的密文。我们有以下数据:
T_i[t]:第i条轨迹在时间点t的采样值(电压)。C_i:第i条轨迹对应的密文(我们已知)。
步骤1:选择泄露点首先,我们需要在一条轨迹上确定哪个时间点t的泄露与密钥操作相关。将探头放在信号强的位置,采集一条轨迹。观察波形,找到那些与时钟同步的、规律性出现的尖峰脉冲。AES的每轮操作消耗时间大致固定,最后一轮操作发生在一段特定的时间窗口内。通常,我们会粗略估计这个窗口,然后对窗口内的所有时间点都进行后续分析。
步骤2:对密钥字节进行暴力猜测对于一个字节的轮密钥K_guess,共有256种可能(0x00 到 0xFF)。对于每一种猜测,我们进行以下操作:
- 计算假设的中间值:对于每一条轨迹
i,用猜测的密钥K_guess和已知的密文字节C_i,计算假设的中间值V_i = Sbox(C_i ⊕ K_guess)。 - 将轨迹分组:根据
V_i的汉明重量,或者更简单粗暴地,根据V_i的某一个特定位(比如最高位MSB)是0还是1,将所有的N条轨迹分成两组:G0和G1。- 简单分组法:如果
V_i的MSB为0,轨迹i归入G0;如果为1,归入G1。这种方法基于“某一数据位为1时功耗可能不同”的假设。 - 汉明重量分组法:计算
HW(V_i)。设定一个阈值T(例如4,对于一个字节,汉明重量范围是0-8),如果HW(V_i) > T,归入G1,否则归入G0。这种方法利用了更多信息。
- 简单分组法:如果
- 计算差分轨迹:对于时间点
t,分别计算G0组和G1组所有轨迹在t点的平均值:A0[t] = mean(T_i[t] for i in G0),A1[t] = mean(T_i[t] for i in G1)。 - 计算差分值:差分轨迹
D[t] = |A0[t] - A1[t]|。这个D[t]反映了在t时刻,根据我们猜测的密钥进行分组后,两组轨迹的平均泄露差异。
步骤3:识别正确密钥我们对256种K_guess都重复步骤2,得到256条差分轨迹D_Kguess[t]。
- 关键洞察:如果
K_guess是错误的,那么我们用这个错误密钥计算的V_i实际上是随机值。因此,分组G0和G1是随机划分的,两组轨迹来自同一个总体,它们的平均值A0[t]和A1[t]应该非常接近。所以,对于所有时间点t,D[t]的值会很小,接近零,并且波形看起来像噪声。 - 反之,如果
K_guess是正确的,那么我们计算的V_i就是芯片内部真实计算出的中间值。根据泄露模型,V_i的位或汉明重量确实影响了功耗。因此,G0和G1是根据真实的泄露特性划分的。在中间值V被计算或使用的那个精确时间点t_key,G0和G1的平均功耗会出现显著差异。这会导致在D[t]曲线上,在t_key附近出现一个明显的尖峰。
因此,攻击过程就是:遍历所有256个密钥猜测,绘制它们的差分轨迹。观察哪一条差分轨迹在某个时间点出现了显著高于其他轨迹的尖峰。这个尖峰对应的密钥猜测,就是正确的密钥字节。
步骤4:扩展到全部密钥AES-128有16个字节的密钥。我们对密文的第0个字节进行上述攻击,得到第0个字节的轮密钥K[0]。然后对密文的第1个字节进行攻击(注意,攻击时使用的密钥猜测是针对第1个字节的),得到K[1]。重复此过程,直到得到全部16个字节的最后一轮轮密钥。最后,通过AES的密钥扩展算法进行逆推,即可得到原始的128位主密钥。
4.3 实操脚本与结果解读
下面是一个高度简化的Python伪代码,演示DPA的核心循环:
import numpy as np from Crypto.Cipher import AES # 仅用于生成模拟数据 # 假设我们已经有了: # traces: 一个 N x M 的矩阵,N条轨迹,每条M个时间点 # ciphertexts: 一个 N x 16 的数组,每条轨迹对应的16字节密文 # 我们攻击密文的第一个字节 (byte_idx = 0) N, M = traces.shape dpa_results = np.zeros((256, M)) # 存储256种猜测的差分轨迹 for kguess in range(256): group0, group1 = [], [] for i in range(N): # 获取对应密文字节 c = ciphertexts[i, 0] # 计算假设的中间值(假设攻击S盒输出) v = sbox[c ^ kguess] # sbox是预计算的S盒查找表 # 根据中间值的最高位分组 (简单分组法) if (v >> 7) & 1: # 检查最高位是否为1 group1.append(traces[i]) else: group0.append(traces[i]) # 转换为numpy数组以便计算均值 group0 = np.array(group0) group1 = np.array(group1) # 计算平均轨迹 mean0 = np.mean(group0, axis=0) if len(group0) > 0 else np.zeros(M) mean1 = np.mean(group1, axis=1) if len(group1) > 0 else np.zeros(M) # 计算差分轨迹 dpa_results[kguess] = np.abs(mean0 - mean1) # 寻找正确密钥:对于每个时间点,找出哪个kguess的差分值最大 # 通常我们关注差分轨迹的最大值 peak_power = np.max(dpa_results, axis=1) # 每个猜测对应的差分峰值 correct_guess = np.argmax(peak_power) # 峰值最大的那个猜测 print(f"DPA推测的密钥字节 (idx 0) 是: {correct_guess:02x}")在真实攻击中,你需要用实际采集的traces和ciphertexts替换模拟数据。运行后,你可以绘制dpa_results[correct_guess]这条差分轨迹,应该能看到一个或多个清晰的尖峰。同时,绘制peak_power随kguess变化的曲线,正确的猜测会像一个孤立的针尖一样突出,而错误的猜测则聚集在底部的一条水平线附近。
注意事项与心得:
- 轨迹对齐:上述攻击假设所有轨迹在时间上是完美对齐的。现实中,由于时钟抖动、触发微小延迟,轨迹可能需要先进行对齐预处理(如基于同步时钟信号进行互相关对齐)。
- 噪声处理:如果信噪比太低,差分尖峰可能被淹没。增加轨迹数量
N是最直接的方法(因为噪声的均值会趋于0,而信号不变)。通常,攻击一个未加防护的软件AES实现,几百到几千条轨迹足矣。- 选择位:上述例子使用了最高位(MSB)分组。在实践中,可以尝试用不同的位(如最低位LSB)或汉明重量阈值进行分组,看哪个能产生最明显的差分尖峰。有时,泄露可能与特定的位线相关。
- 不止一个尖峰:正确的差分轨迹上可能出现多个尖峰,这对应了芯片内部多个与密钥相关的操作(如读密钥、S盒查表、写回结果)。这是好事,进一步确认了正确性。
5. 进阶攻击:相关性能量分析与模板攻击
DPA虽然经典,但需要较多的轨迹(数千条)。在实际攻击中,我们追求用更少的轨迹、更短的时间完成攻击。这就引出了更强大的工具。
5.1 相关性能量分析
CPA可以看作是DPA的“升级版”和“理论完善版”。它不再使用简单的分组和差分,而是直接计算电磁轨迹与一个基于密钥猜测的泄露模型值之间的相关系数。
- 泄露模型:我们定义一个泄露模型函数
L(K_guess, C)。例如,最常用的就是汉明重量模型:L = HW(Sbox(C ⊕ K_guess))。这个函数计算了在给定密钥猜测和密文下,我们预期的中间值的汉明重量。 - 计算相关系数:对于每个时间点
t和每个密钥猜测k,我们计算所有N条轨迹在该时间点的采样值T_i[t]与对应的泄露模型值L_i(k) = L(k, C_i)之间的皮尔逊相关系数ρ(t, k)。- 皮尔逊相关系数衡量了两个变量之间的线性相关程度,范围从-1到1。绝对值越大,相关性越强。
- 识别正确密钥:如果密钥猜测
k是正确的,那么L_i(k)就是芯片内部真实中间值的汉明重量。根据假设,轨迹T_i[t]在中间值被处理的时间点t_key应该与L_i(k)高度线性相关。因此,在ρ(t, k)矩阵中,对于正确的k,我们会在t_key附近看到一个相关系数绝对值接近1的尖峰。对于错误的k,L_i(k)是随机值,与T_i[t]没有相关性,ρ(t, k)会接近0。
CPA的优势:
- 更高效:通常比DPA需要更少的轨迹就能得到显著结果,因为它利用了更多的统计信息。
- 更鲁棒:对泄露模型与真实泄露之间的线性关系拟合得更好。
- 量化结果:相关系数提供了一个统计显著性的度量,我们可以设定一个阈值(如 |ρ| > 0.5)来判断攻击是否成功。
其实操流程与DPA类似,只是将分组差分计算替换为相关系数计算。Python中可以用numpy.corrcoef函数方便地计算。
5.2 模板攻击:已知最强非侧信道攻击
如果说CPA是“狙击步枪”,那么模板攻击就是“制导导弹”。它是已知最强大的非侧信道攻击,理论上可以用一条轨迹就恢复密钥。其核心思想是“建模与匹配”。
攻击分为两个阶段:
阶段一:模板构建(分析阶段)
- 攻击者拥有一台与目标设备完全相同的、密钥已知的“分析设备”。
- 在分析设备上,固定密钥,输入大量(数万)不同的明文,采集每条明文对应的电磁轨迹。
- 关键步骤:对于每条轨迹,攻击者知道内部计算的所有中间值(因为密钥已知)。攻击者选择感兴趣的中间值(如S盒输出
V)。 - 攻击者将所有产生相同中间值
V的轨迹归类为一组。例如,对于8位中间值,有256种可能,就建立256个组。 - 对每个组(即每个特定的
V),计算该组内所有轨迹的平均向量(模板均值)和协方差矩阵(模板噪声)。这个(均值,协方差)对,就构成了该中间值V的一个“模板”。它描述了当芯片计算这个特定值V时,其电磁轨迹的“特征”是什么样的。
阶段二:模板匹配(攻击阶段)
- 攻击者现在面对未知密钥的目标设备,采集一条或少数几条加密轨迹。
- 对于目标轨迹,攻击者枚举所有可能的密钥猜测
k。对于每个猜测,可以计算出对应的假设中间值V(基于已知的密文)。 - 然后,攻击者从第一阶段构建好的模板库中,取出对应中间值
V的模板(均值和协方差)。 - 计算目标轨迹属于这个模板的概率(通常使用多元高斯分布的概率密度函数)。这个概率越高,说明目标轨迹的特征与该模板越匹配。
- 选择使概率最高的那个密钥猜测
k,即为正确密钥。
为什么模板攻击如此强大?因为它不假设一个简单的线性泄露模型(如汉明重量),而是通过海量数据,直接学习并建模了芯片在计算每一个特定数据值时产生的真实、复杂的电磁特征。它考虑了所有非线性因素和芯片特有的物理特性。
模板攻击的局限性:
- 需求苛刻:需要一台同型号、同批次的设备进行模板构建。工艺偏差可能导致模板不通用。
- 计算量大:构建模板需要海量数据(数万至数十万条轨迹)和存储空间,匹配阶段的计算(涉及高维矩阵求逆)也较复杂。
- 对对齐要求极高:轨迹必须在样本级别精确对齐,任何微小的偏移都会导致匹配失败。
在实际中,CPA是平衡了效率与复杂度的最佳选择,而模板攻击则代表了侧信道攻击的理论上限,常用于评估芯片或算法实现的脆弱性等级。
6. 防御之道:从算法到系统的多层次防护
了解了攻击者的手段,作为设计者,我们的任务就是筑起高墙。防御侧信道攻击是一个系统工程,需要从多个层面协同考虑。
6.1 算法级防护:让泄露与密钥无关
这是最根本的防护思路,即修改加密算法的实现方式,使得功耗/电磁辐射与密钥的相关性降到最低。
- 隐藏:目标是在所有可能的数据和密钥上,使功耗看起来是随机的、恒定的。
- 布尔掩码:最常用的技术。将敏感的中间值
x与一个随机数m(掩码)进行异或:x_m = x ⊕ m。在后续的所有运算中,都使用掩码后的值x_m和掩码m本身。在运算结束时,再通过逆操作去除掩码,得到正确结果。这样,攻击者观测到的始终是x_m和m,而它们单独都与x无关。实现掩码需要设计“掩码版”的S盒等非线性组件,复杂度较高。 - 随机化操作顺序:如果算法中有可以交换顺序的操作(如某些模式下的独立加密块),随机化它们的执行顺序,打乱功耗轨迹的时间结构。
- 布尔掩码:最常用的技术。将敏感的中间值
- 扰乱:向功耗中注入噪声,降低信噪比。
- 随机延迟:在算法执行中插入随机数量的空操作指令,使每次加密的轨迹长度和形状都不同,增加对齐和平均的难度。
- 伪操作:在执行真实操作的同时,并行执行一些不产生实际效果但消耗功耗的“假操作”,用无用的信号淹没有用的信号。
- 均衡:设计电路或指令,使得无论处理‘0’还是‘1’,其功耗都尽可能相同。
- 双轨预充电逻辑:一种电路设计技术,每个信号都用一对互补的信号线表示,并且每个时钟周期都进行预充电,使得‘0’到‘1’和‘1’到‘0’的翻转功耗对称。
- 恒定权重编码:用特定编码表示数据,确保每个码字中‘1’的个数恒定(如均衡码),这样汉明重量就恒定,直接破除了汉明重量模型。
实操心得:算法级防护有效,但会带来性能开销(20%-300%不等)和面积开销。在资源受限的物联网设备上需要仔细权衡。一个常见的误区是只使用简单的随机延迟,这只能增加攻击者所需的轨迹数量,但无法抵御基于多条轨迹平均的DPA/CPA。掩码是目前公认最有效的算法级防护手段之一。
6.2 电路与系统级防护:物理隔离与噪声压制
- 片上传感器与主动对抗:
- 功耗传感器:集成在芯片内的传感器,实时监测电流或电压的异常波动。如果检测到可能被侧信道攻击利用的规律性模式,可以触发警报、重置或注入噪声。
- 时钟抖动:让系统时钟的频率随机轻微变化,使电磁辐射的频谱扩散,让攻击者难以进行精确的时间对齐。
- 内部随机电源调制:在芯片内部,通过电路随机调制核心逻辑的供电电压,使得即使处理相同数据,功耗也会随机变化。
- 物理屏蔽:
- 电磁屏蔽罩:在芯片封装外加装金属屏蔽罩,可以有效衰减电磁辐射。但高级攻击者可能会尝试移除或绕过屏蔽罩。
- 保形涂层与封装:用环氧树脂等材料覆盖芯片表面,增加探头物理接触的难度,并可能吸收部分辐射。
- 金属网格:在芯片的上层金属层设计致密的网格,并连接到固定的电位(如电源或地),形成一个局部的法拉第笼,吸收和短路掉产生的电磁场。
- 系统级策略:
- 密钥管理:定期更换密钥,限制单个密钥的使用次数或时间,即使密钥被破解,损失也有限。
- 访问控制:将加密操作放在需要物理认证或特权权限才能访问的安全区域内执行。
- 环境监测:检测是否有异常的物理探测设备(如检测探头接近的电容传感器、检测外壳被打开的光传感器)。
6.3 开发与测试实践:将安全融入流程
- 使用经过安全认证的库:对于大多数开发者,最实际的做法是使用像ARM Mbed TLS、Libsodium或芯片厂商提供的、经过侧信道安全评估的加密库。切勿自己实现加密核心算法,尤其是没有防护措施的实现。
- 侧信道安全测试:在产品开发周期中,引入侧信道分析测试。可以使用开源工具(如ChipWhisperer平台、Jupyter分析库)或商用工具,对自己的设备进行DPA/CPA攻击测试,量化其抵抗能力。
- 代码审查与静态分析:检查代码中是否存在与密钥相关的分支条件(如
if (key_byte == 0x80)),这类条件语句会直接导致明显的功耗差异。确保所有与密钥相关的操作都是恒定时间的。
7. 常见问题与排查实录
在实际进行电磁侧信道攻击实验或部署防御时,你会遇到各种各样的问题。以下是我和同行们踩过的一些坑和解决方案。
| 问题现象 | 可能原因 | 排查与解决思路 |
|---|---|---|
| 差分轨迹没有尖峰,全是噪声 | 1. 探头位置不对,没捕捉到信号。 2. 触发不同步,轨迹没有对齐。 3. 轨迹数量 N太少,信噪比不足。4. 泄露模型选择错误(如实际是汉明距离,用了汉明重量)。 5. 目标算法有基础防护(如随机延迟)。 | 1.重新定位探头:在芯片表面缓慢扫描,同时观察示波器原始波形,找到时钟信号清晰、幅度大的点。 2.检查触发:确保硬件触发线连接牢固,在示波器上能看到干净、稳定的触发信号。对采集到的轨迹进行对齐预处理(如基于固定同步信号进行互相关对齐)。 3.增加轨迹数量:从1000条增加到5000或10000条。检查单条轨迹的噪声水平,如果单条噪声就很大,需优化实验环境(屏蔽、接地、电池供电)。 4.尝试不同的泄露模型:分别用汉明重量、汉明距离、单个数据位进行攻击测试。 5.观察单条轨迹:如果每次加密的轨迹长度和形状差异巨大,很可能有随机延迟。需要更强大的攻击(如弹性对齐算法)或更多轨迹来平均掉随机性。 |
| 差分尖峰出现在多个错误的密钥猜测上 | 1. 轨迹中存在与密钥无关但强相关的周期性噪声(如时钟信号本身)。 2. 分组方式导致“虚警”(例如,用MSB分组时,某些错误密钥巧合地产生了与数据相关的分组)。 | 1.滤波:对轨迹进行高通滤波,去除低频的周期性成分。或者,在计算差分前,减去每条轨迹的平均值(去除直流偏移和公共噪声)。 2.使用CPA代替DPA:CPA的相关系数是更鲁棒的统计量,能更好地区分正确和错误密钥。或者,尝试使用汉明重量模型进行DPA分组。 |
| CPA攻击中,正确密钥的相关系数峰值很低(<0.3) | 1. 信噪比太低。 2. 泄露模型与真实泄露相关性弱。 3. 存在非线性失真。 | 1.优化信号采集(同上一问题)。尝试积分:对轨迹进行滑动窗口平均,将多个采样点合并为一个点,有时能提升信噪比。 2. 尝试不同的中间值:不攻击最后一轮的S盒输出,可以尝试攻击第一轮的S盒输入,或者轮密钥加操作。 3. 考虑使用模板攻击或机器学习方法(如深度学习),它们能自动学习复杂的非线性特征。 |
| 攻击成功,但需要极多的轨迹(>10万条) | 目标实现有较强的防护措施,如轻量级掩码或噪声注入。 | 1. 确认是否使用了安全库。如果是,这可能是预期结果,说明防护有效。 2. 尝试高阶攻击:如果是一阶掩码,攻击者需要同时结合掩码值 m和掩码后数据x_m的泄露点进行分析(二阶DPA/CPA),这需要更多的轨迹和更复杂的分析。3. 寻找其他泄露源:除了电磁,尝试分析功耗、执行时间甚至声音。 |
| 自制探头信号微弱 | 1. 线圈匝数太少或面积太小。 2. 探头未调谐。 | 1. 增加线圈匝数(如绕5-10圈),或稍微增大线圈直径(到3-5mm)。注意,匝数增加会增大电感,可能影响高频响应。 2. 在探头末端并联一个小电容,与线圈电感形成LC谐振电路,调谐到目标芯片的时钟频率或其谐波,可以显著放大信号。这需要实验调整电容值。 |
电磁侧信道攻击是一个理论与实践深度结合的领域。它要求你既理解密码学的抽象代数,又懂得示波器的旋钮该怎么调。防御它则更需要一种系统性的安全思维,从最底层的晶体管到最上层的协议都要考虑周全。对于开发者而言,最关键的启示是:永远不要假设你的“黑盒”是密不透风的。任何物理实现都会泄露信息,安全在于如何管理和控制这种泄露,并将攻击的成本提升到不可接受的高度。