尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

硬件安全必修课:功率分析攻击如何攻破ECC实现

硬件安全必修课:功率分析攻击如何攻破ECC实现 如果你在一间硬件安全评估实验室里待过大概率见过这样的场景一台示波器、一根探头、一块正在跑加密算法的开发板。操作员把探头往芯片电源引脚附近一放屏幕上的电流波形像心跳一样起伏几分钟后旁边电脑上跳出一串十六进制字符串——私钥就这样被读出来了。没有拆芯片没有暴力穷举甚至没有接触内部总线。这就是功率分析Power Analysis攻击一种针对密码硬件实现的经典侧信道攻击。这篇文章要聊的就是它在ECC椭圆曲线密码学硬件实现上怎么打、为什么能打穿以及防御方该怎么堵。1. 先分清两个ECC本文说的是椭圆曲线密码学不是纠错码搜索资料时最容易踩的第一个坑是ECC这个词本身。硬件领域里ECC最常见的意思其实是 Error Correction Code——内存纠错码大家常说的“ecc校验”“服务器内存带ECC”指的就是它。SAP系统里的“ECC”又是另一个东西指 ERP Central Component跟密码学半点关系没有。而本文要讨论的ECC是 Elliptic Curve Cryptography也就是椭圆曲线密码学。这三个完全不同的概念共用同一个缩写检索的时候建议直接用全称否则很容易翻到一堆内存条评测。椭圆曲线密码学之所以在硬件安全场景里这么常见是因为它用更短的密钥长度提供足够的安全性。P-256曲线的256位密钥安全强度大致相当于3072位RSA。这就让ECC在资源受限的设备上特别吃香——智能卡、安全芯片、车规MCU、物联网安全模块、硬件钱包到处都能看到它的身影。也正因为这些设备往往是物理可接触的功率分析攻击的路子就走得通。功率分析利用的是CMOS电路一个非常朴素的特征动态功耗与信号翻转挂钩。寄存器里0变1、1变0会有充电放电电流翻转的比特数越多功耗越高。于是外部电源引脚上的电流波形就是芯片内部状态变化的“心电图”。攻击者的思路很简单密钥一旦参与运算就会影响中间值中间值的变化会体现在功耗波形上。只要用统计方法建立“假设的中间值”和“实测功耗”之间的相关性就能逐位猜出密钥。关键的问题在于ECC在硬件上做的是什么样的运算为什么恰好能被功耗波形出卖这就要从标量乘法说起。2. 标量乘法是侧信道攻击的“震中”先从运算层面理解密钥是怎么漏出去的2.1 一个私钥一层层累出来的公钥ECC的数学基础就不展开公式了只讲攻击必须理解的模型。椭圆曲线上有一个公开的基点G私钥k是一个随机整数公钥Q kG也就是私钥乘以基点得到曲线上的另一个点。所有ECC协议——ECDH密钥交换、ECDSA签名——底层都离不开这个标量乘法给定k和G计算kG。攻击目标一目了然从功耗波形里把k还原出来。k是256位整数如果每一位都能从功耗上区分出来那么整条密钥就相当于写在波形上了。2.2 从不带防的Double-and-Add开始看最简单的标量乘法实现是Double-and-Add思路跟二进制幂运算一样从最高位开始逐位扫描k每一位都做一次点倍Double计算2R如果当前位是1就再做一次点加Add计算R G。写成伪代码是这样R 0 for i from n-1 down to 0: R 2R # Double每一位都做 if k_i 1: R R G # Add仅当当前比特为1 return R问题就出在这个 if 上。点倍和点加在硬件上需要不同数量的有限域运算。以Jacobian投影坐标为例点倍大约需要10次模乘/模平方操作点加大约需要16次左右。如果硬件里的模乘器是串行复用的那么点加的功耗包络就明显比点倍更宽、峰值模式也不一样。示波器上看到的波形会是一串近乎等间隔的“双倍”脉冲中间偶尔插入一簇更复杂的“加法”脉冲。你只要在波形上数一数哪些位置多了加法脉冲私钥的二进制表示就出来了——这就是教科书级的简单功率分析SPA。我最早在FPGA上跑这个实验时第一次看到那条波形上清晰多出来的“鼓包”说实话是有点震撼的安全芯片守了这么多年的私钥在功耗面前根本没有秘密可言一条trace就全招了。2.3 Montgomery阶梯SPA的对手但不是终点Double-and-Add的if语句太招摇了所以很多实现会改用Montgomery阶梯。它的特点是不管密钥位是0还是1每一轮都固定执行一次点倍加一次点加运算序列完全固定R0 0 R1 G for i from n-1 down to 0: if k_i 0: R1 R0 R1 R0 2 * R0 else: R0 R0 R1 R1 2 * R1 return R0这里的具体赋值顺序不同实现有差异但总模式是每轮都做一个点加一个点倍。这样SPA读波形的方法基本失效了——波形上看不到“多出来的add”。但注意点加和点倍的功耗特征差异并没有消失只是不再直接对应密钥位。每个循环里哪个时刻执行点加、哪个时刻执行点倍仍然取决于当前比特是0还是1。换句话说密钥位被编码成了“操作顺序”而不是“操作是否存在”。这种顺序信息在单条trace上可能不好读但配合统计方法依然能被恢复出来。更深一层的问题在于有些Montgomery阶梯实现在做R0R1时需要先判断哪个点是无穷远点或者需要对R0、R1做条件交换这些条件操作如果依赖密钥位功耗上照样会留缝。所以结论是标量乘法是整个ECC硬件里最容易泄漏密钥的路径。接下来的问题就是在实际攻击实验里波形和数据到底怎么采、怎么处理。3. 一次完整的功率分析攻击从实验布设到Trace采集很多刚接触功率分析的人把注意力全放在算法和统计上结果上了实验台发现波形一团糟什么信号都看不出来。问题往往出在采集环节。采集质量决定了攻击成败这步值得花大篇幅说清楚。3.1 实验环境清单一套能跑的ECC功率分析攻击环境通常包含这些目标设备最可控的是FPGA开发板 ECC点乘IP核或者带硬件加速器的MCU比如STM32系列跑软件ECC也行但信噪比不如硬件实现高。我推荐从FPGA开始练手因为时钟可控、功耗信号干净、代码可观测性强。ChipWhisperer这一系列开源硬件安全工具也值得关注它把目标板和同步采集做了很好的集成适合快速验证。功耗测量手段侵入式方案是在核心供电轨上串联一个小电阻1Ω到10Ω用差分探头测电阻两端电压非侵入式方案是用近场电磁探头靠近芯片表面。侵入式信号最强但需要改板子电磁探头用起来方便但对探头摆放位置极其敏感每一次微调都会改变波形形状。示波器带宽建议500MHz以上采样率至少5GS/s深内存模式一定要有。以P-256为例一次标量乘法约256轮迭代每轮1~2微秒取决于时钟频率和乘法器设计总时长约512微秒。10GS/s采样率下全程采集需要512万个采样点也就是5.12M点。示波器如果内存不够会自动降采样高频细节全没了后面做统计就白搭。触发信号最好能在目标板上拉一根IO引脚在标量乘法开始时拉高、结束时拉低作为示波器触发源。没有触发信号的话波形起点会有随机抖动需要后期对齐麻烦很多。3.2 采集流程“一条trace一条命”采集的目标是拿到N条功耗波形每条trace对应一次标量乘法运算。这N条有两种来源同一把密钥下重复执行相同输入或者同一把密钥下输入不同的公开数据比如不同的基点/消息。后者在CPA里更重要因为要用输入明文来建模假设功耗。具体操作一般是这样的先用Python通过pyvisa或其他仪器控制库让示波器按触发信号捕获一条波形然后向目标板发送新的输入再触发下一条。循环几百到几千次。这个过程看着机械但有几个细节能直接影响数据可用性对齐问题。CRT触发信号如果和实际运算开始之间存在抖动或者板子上有中断、DMA等干扰每条trace里标量乘法的起点就可能错位。DPA/CPA对时间错位非常敏感——就像测心率时手表没戴稳数据点错了一位相关性就散了。解决方法是采集后做对齐先选一条参考trace用滑动窗口中互相关系数找到每条trace相对于参考trace的偏移再做线性插值重采样。这一步是预处理里最重要的操作。噪声问题。板上的DC-DC电源噪声、数字逻辑开关噪声都会叠加到功耗信号上。改善手段包括用低噪声LDO单独给核心供电、探头尽量短、示波器开带宽限制比如20MHz以上信号不需要就直接滤掉、对同一条trace做多次采集平均前提是输入不变能触发多次。如果只做SPA平均几次就能看到明显改善做CPA的话只要每次采集的是不同输入就不能靠平均解决得靠统计量本身。采样率与内存取舍。如果示波器深内存不够另一个思路是分段采集只采每一轮迭代的那一小段时间窗口丢掉中间空隙。代价是触发逻辑复杂但能保住采样率。对硬件实现来说点加和点倍的区别可能就体现在几十纳秒到几百纳秒的细节里采样率掉到1GS/s以下特征基本就糊了。3.3 一个判断数据质量的土办法采集完第一批trace别急着跑算法。先把几条trace画出来看看有没有明显的周期性结构、有没有和标量乘法迭代次数匹配的重复节拍。如果波形看起来就是一团毛刺说明要么触发没对齐要么采集环节有问题。我会先做一次FFT看主频谱分量在哪里判断系统主时钟再放大看单轮迭代的波形确认能看到运算的边界。这个习惯能省下大量排错时间。4. 读出密钥的两种姿势SPA直接判读与CPA统计爆破4.1 SPA一条trace肉眼读KEYSPA是最直观的攻击方式。前提是算法实现没有做针对性的侧信道防护比如还是那个朴素的Double-and-Add。拿到一条干净的trace后先画出波形大概长这样一串相似的脉冲每个脉冲代表一轮Double在若干位置上脉冲后面多了一段更长的波形那就是Add。你只需要人工或脚本标记出每一个Add出现的位置对应到密钥的比特索引上私钥就出来了。实操里有个小技巧如果单条trace噪声太大看不清Add可以在相同输入下重复采集几十条做算术平均随机噪声会被压掉信号成分保留。对SPA来讲几十条平均已经非常够用了。SPA最大的优点是“快”几乎不需要统计计算最大的局限是只对特定实现有效。Montgomery阶梯、随机延迟、伪操作插入都能让它失效。4.2 CPA用相关系数说话当单条trace读不出来了就轮到统计方法上场。这里只讲最实用的相关功率分析CPA因为它在实操中比传统的差分功率分析DPA更容易用、判读也更直接。CPA的基本思想是硬件在执行某个与密钥相关的中间计算时功耗和中间值的汉明权重HW即二进制表示里1的个数近似成正比。原因前面说过CMOS翻转功耗跟翻转比特数挂钩。于是攻击者可以猜一个密钥候选值用这个猜测值去计算某个已知输入的中间值算出这个中间值的汉明权重求这个汉明权重向量和实测功耗迹线每个时间点之间的皮尔逊相关系数如果相关系数出现明显尖峰说明这个猜测值就是对的如果曲线平平的继续猜下一个。伪代码大概长这样import numpy as np # traces: 二维数组形状 (N, T)N条trace每T个采样点 # inputs: 形状 (N,) 的公开输入数据 # key_guesses: 待猜测的密钥候选列表 def hamming_weight(x): return bin(x).count(1) best_guess None best_corr 0 for guess in key_guesses: # 1. 用猜测值计算每个trace对应的中间值 mid [intermediate_func(inp, guess) for inp in inputs] # 2. 转成汉明权重假设功耗模型 hw np.array([hamming_weight(m) for m in mid], dtypefloat) # 3. 和每一条trace的每个时间点求相关系数 corr np.array([ np.corrcoef(hw, traces[:, t])[0, 1] for t in range(traces.shape[1]) ]) # 4. 找这个猜测下的最大相关峰 peak np.max(np.abs(corr)) if peak best_corr: best_corr peak best_guess guess print(恢复的密钥字节:, best_guess, 相关峰:, best_corr)这里的intermediate_func要根据具体攻击目标来设计。针对ECDSA签名可以攻击临时私钥nonce的某个字节针对ECDH可以攻击点乘迭代中某个域乘法输出值。选择中间值的原则是它必须是输入数据的函数又必须和密钥有关而且必须在硬件里真实参与过计算。选错中间值的话相关系数永远起不来。判读标准正确密钥候选下相关系数峰值通常明显高于其他候选。具体数值取决于信噪比硬件实现信噪比高正确候选峰值0.3以上很正常错误候选往往在0.1以下。如果正确和错误候选的差距不明显一般要先怀疑对齐问题或中间值选得不对。需要的trace数量对一个大裸的硬件ECC实现几百条trace经常就够了加了一点随机化之后可能就要上万条。这个数量用公式可以粗略估算但实践中大家更多是“采一批试一下不行再加”。注意采集trace是整套流程里最耗时的环节动辄几万条的话最好用自动化脚本跑一段时间期间人别闲着——去检查下一次攻击用什么中间值。5. 攻击者的绊脚石也是评估者的考点对策、绕过和常见坑5.1 防御方怎么堵漏做安全评估的时候我见过不少自称“抗侧信道”的ECC实现实侧之后发现只是挡了一层。真正的防御得从几个层面同时下手算法层使用固定操作序列的Montgomery阶梯避免因密钥位产生不同的运算路径。这能挡掉最基本的SPA。数据层加随机化让功耗和真实中间值脱钩。常见做法是标量盲化比如计算 k’ k r·ord(G)其中r是随机数ord(G)是基点阶计算用k’完了再对结果处理。还有点盲化随机取一个点R先算(kP R)再把R减掉。这两种方法都会让功耗迹线每次都不一样攻击者需要的trace数量急剧上升。物理层门级掩码、双轨逻辑Dual-Rail通过让电路无论处理什么数据都保持恒定翻转数量来抹掉相关性时钟随机化让trace对不齐噪声注入用电源毛刺去掩盖信号。关键是不要以为上了某个单一对策就安全了。蒙哥马利阶梯防了SPA但没防住数据相关性随机化提高了CPA难度但搞不定高阶分析。真正的评估一定是在实际采集的trace上实际跑一遍多阶攻击才知道防护到位没有。5.2 评估视角的绕过思路作为评估者你不能只测一阶CPA就下结论。常见需要测试的绕过手段包括高阶统计分析对掩码实现虽然一阶功耗和中间值不相关了但中间值可能和两个时间点的功耗组合相关。一阶掩码的典型弱点就是“组合泄漏”用二阶方差或联合分布就能恢复相关性。预处理增强先对trace做中心化、带通滤波、PCA降噪把目标信号从噪声里先捞出来再跑CPA经常能在trace数量不足时救回一命。模板攻击在可控的“相似设备”上先建立功耗模型再对目标设备用极大似然分类。这个对随机化实现的威胁很大因为特征不一定在“均值”里而是在“分布”里。这里补充一句做这类攻击测试请务必在自己的实验设备、自己的实验室里进行用于安全评估和学术研究。行业里相关标准和指南可以参考ISO 17825以及Common Criteria的侧信道评估框架它们定义了从采集到分析再到结果判定的一套规范流程。5.3 实操中踩过的一些坑最后集中说说实操里最容易翻车的地方这些坑我基本都踩过坑一密钥硬编码在固件里。有些同行搭建验证实验时图省事把测试密钥直接写死在代码里最后攻击脚本恢复出来的密钥和源码里一字不差还以为是bug调了半天。密钥请务必从外部随机生成、通过串口下发这样攻击结果才可信。坑二示波器触发到信号之间有随机延迟。用功耗信号本身做触发时尤其明显每次触发的点不在同一相位。处理办法是采集后做互相关对齐或者干脆用板上专用IO做硬件触发。坑三采样率被悄悄降了。深内存模式下很多示波器会自动切到4GS/s甚至更低屏幕上看着波形挺漂亮细节已经丢了。检查一下示波器的实际采样率和内存深度设置确保和你的采集时长匹配。坑四算法仿真和硬件行为不匹配。你在软件仿真里验证了攻击模型以为硬件也是这个行为模式结果CPA相关性上不去。先别急着怀疑攻击算法回到示波器上看真实波形里点加/点倍的位置用实际数据修正你的中间值模型。坑五术语搜错方向。ECC、ecc校验、SAP ECC三个词一定要分开不然检索出来的资料大概率是内存条和ERP系统越查越迷糊。建议直接用“Elliptic Curve Power Analysis”或者“SPA/CPA on ECC”作为关键词搜索。我在实际做这个项目过程中的体会是功率分析对ECC硬件实现的威胁本质上不是算法数学层面的问题而是“物理实现是否忠实于数学抽象”的问题。密码学教科书写得很干净功耗不参与运算但真实芯片在每一纳秒都在翻转电容、消耗电流任何与密钥有关的操作都会在物理世界留下痕迹。攻击者做的事情不过是把这个痕迹放大、统计、还原而已。最后再分享一个小技巧当你准备在一颗新的目标芯片上跑CPA时先做一个“已知密钥测试”——把密钥设置成已知值采一批trace用你的脚本恢复看能否恢复出来。如果这步都失败说明采集链路或中间值模型有问题别急着挑战更复杂的防护实现。这个习惯能帮你节省大量调试时间。
返回列表