我最早被问到“芯片硬件加密和软件加密到底啥区别”,是在接一个智能门锁项目的时候。客户拿着需求文档,上面写着“必须支持硬件加密”,但追问下去,对方其实也说不清硬件加密到底硬在哪儿,软件加密又软在哪里。这个问题在嵌入式圈子里特别常见,尤其是这几年物联网设备越来越多,大家开始关心固件保护、通信安全、防抄板,自然就会碰到这个概念。
先说结论:硬件加密和软件加密不是“同一个算法用两种方式写一遍”那么简单,而是密钥存放、计算位置、防攻击能力、性能开销这几个维度上的系统性差异。这篇内容我就用自己实际调过的芯片和踩过的坑,把这两条路的底层逻辑、安全边界和选型方法一次讲清楚。
1. 硬件加密和软件加密的底层逻辑差异
1.1 先搞懂“加密”到底在做什么
不管是AES、RSA还是国密SM4,加密本质上都是数学运算。以AES-128为例,就是把128位明文数据,用128位密钥,经过若干轮“字节代换、行移位、列混淆、轮密钥加”的计算,最后得到128位密文。整个过程对计算单元的要求就是:能算加法和查表,能存数据,能按顺序执行操作。
所以在最底层,加密并不“神秘”,它需要的资源是三个:算法逻辑、密钥、运行环境。软件加密和硬件加密的差别,其实就藏在这三个资源的位置和属性上。
这里有个常见的理解误区:很多人觉得“用C语言调一个AES函数”是软件加密,“芯片支持AES指令集或者有AES外设”就是硬件加密。这个说法方向对,但不完整。硬件加密的精髓不只在“算得快”,更在于“密钥和运算过程被包在一个外界碰不到的保护壳里”。
1.2 软件加密:通用CPU上跑数学函数
软件加密,就是在MCU或者SoC的通用CPU核心里,通过软件代码来实现密码算法。你在STM32F103上调用mbedTLS库里的AES函数,在ESP32上跑TinyCrypt做HMAC,在Linux服务器上用OpenSSL算RSA,本质上都属于软件加密。
软件加密的特点非常直白:
- 密钥以明文形式存在Flash或内存里。哪怕你用一个全局数组存密钥,编译器把它放在某个地址上,调试器一读就能看到。
- 运算过程发生在CPU流水线里,功耗、执行时间都和具体数据、当前执行的指令强相关,这给侧信道攻击留下了空间。
- 算法是通用的,可以灵活换,想用AES就AES,想换国密SM4就SM4,只要能编译过就都能跑。
- 代价是占用CPU时间,尤其是非对称算法(RSA、ECC),运算量大到会在低主频MCU上卡几十毫秒甚至几百毫秒。
不是说软件加密不能用。很多场景下,比如设备只做一次性鉴权、数据不涉及高价值机密、攻击者也完全接触不到设备外壳,那软件加密完全够用。它的安全问题更多发生在“攻击者能拿到设备、能读Flash、能上调试器”的场合。
1.3 硬件加密:专用引擎加上隔离边界
硬件加密这个词在不同语境下指的东西不完全一样,但在芯片层面,它通常指一条相对独立的安全“生产线”。这条生产线上有专用的密码算法引擎(比如AES加速器、RSA协处理器)、有独立的密钥存储(比如OTP、eFuse、安全Flash区,或者安全RAM),还可能带真随机数发生器(TRNG)、篡改检测、总线加密这些配套模块。
以我经常用的ATECC608A这种独立安全芯片来说,密钥一旦写入芯片内部的保险丝存储区,主控CPU只能向它下发“用密钥X对数据做签名”这样的指令,它算完之后把结果返回,但密钥本身读不出来。主MCU不碰密钥,这就是硬件隔离的价值。另一种形态是MCU片内集成加密引擎,比如STM32系列里带AES外设的型号、GD32部分带国密算法加速的型号,运算在专门电路里完成,但密钥存储方式需要看具体实现,有的芯片有安全密钥区,有的只是“运算加速器”,密钥还是要放在Flash里,那安全等级就差一些。
顺便提一句,现在不少SoC芯片,比如RK3588这一类带TrustZone安全岛、TEE可信执行环境的处理器,它的“硬件加密”又复杂一层:既有芯片底层的密码学引擎,也有运行在安全世界的OP-TEE固件,密钥由安全子系统统一管理,普通Linux应用完全碰不到。这种属于上一级的“硬件信任根”方案,安全性更强,但开发和调试难度也明显更高。
1.4 一张表看懂核心差异
| 对比维度 | 软件加密 | 硬件加密 |
|---|---|---|
| 运算执行位置 | 通用CPU核心 | 专用密码学引擎/协处理器 |
| 密钥存储位置 | Flash/内存明文存储 | 安全存储区(OTP/eFuse/安全RAM) |
| 密钥是否可被主控读出 | 可以 | 通常不可读 |
| CPU占用率 | 高,特别是非对称算法 | 低,硬件引擎独立完成 |
| 抗侧信道攻击能力 | 弱 | 强(固定时间执行、掩码、功耗均衡设计) |
| 抗物理攻击能力 | 弱 | 强(有金属屏蔽层、篡改检测等) |
| 灵活性 | 高,算法可随时改 | 低,受限于硬件支持的算法集 |
| 功耗 | 高(CPU高负荷) | 低(专用电路效率高) |
| 成本 | 零额外成本 | 增加芯片面积或独立芯片成本 |
2. 实际芯片场景中的硬件加密形态
2.1 MCU内置密码学外设:STM32、GD32、ESP32上的真实情况
很多嵌入式工程师第一次接触硬件加密,就是从MCU自带的加密外设开始的。以STM32为例,STM32L0、L4等系列带独立的AES硬件外设,STM32H723这类高性能型号上CRYP外设支持AES-128/192/256和更多算法。这个外设的作用是把AES的轮运算从CPU代码里搬到一个固定电路里完成。这样做带来的直接好处是加密16字节数据,CPU只需要往数据寄存器里写东西,然后等待结果标志位,整个过程几乎是微秒级,主内核可以去跑别的事情。
不过MCU内置AES外设有个非常容易踩的坑:它只加速“运算”,不保证“密钥安全”。如果密钥数组还是写死在Flash里,那攻击者照样用SWD调试接口或者读固件的方式把密钥翻出来。这时候你只能说“使用了硬件加速的AES”,不能说“硬件加密保护了我的密钥”。
更实用的做法是配合MCU的读保护(RDP)、唯一ID、一次性编程eFuse等手段。比如把某一把密钥烧录到芯片不可读的OTP区,启动时让固件去读并协助AES外设做运算,这样密钥才真正和外界隔离。
GD32系列很多型号也集成了加密加速引擎,特别是一些面向国密场景的芯片会直接支持SM3、SM4硬件计算,在需要合规的场合非常省事。ESP32-C3、ESP32-S3这些Wi-Fi/蓝牙SoC同样内置AES、SHA、RSA加速器,但它们的安全模型偏TEE方向,使用时要配合Secure Boot和Flash加密一起用,单独调用加密引擎也很难说得上完整的硬件保护。
2.2 外置独立安全芯片:密钥焊死在保险柜里
如果说MCU内置AES外设更像是“家里雇了一个算账很快的助手,但账本放在桌上”,那独立安全芯片就是“账本锁在银行的保险柜里,你需要查询时只能是银行帮你看完把结果告诉你”。
ATECC608A是我用得最多的独立安全芯片之一。它的核心设计思路是:密钥在出厂前或产线阶段写入芯片,写入之后,从任何接口都读不回来。主机可以通过I2C请求它用内部密钥对一段数据做ECDSA签名,或者做AES加密,但主机永远拿不到密钥本体。
这种方案特别适合防抄板、固件版权保护、配件认证这类场景。比如做一个医疗配件,主机的MCU在开机时给安全芯片发一个随机数,安全芯片用内部密钥签名后返回,主机校验通过才继续工作。哪怕仿造者把整个MCU固件都复制走了,他没有主芯片内部对应的公钥或者没有安全芯片里的私钥,照样仿不出来。
独立安全芯片的代价是:多一颗物料、多一条I2C或SPI总线、多一段产线烧录密钥的管理流程。BOM成本增加几块钱,但对高价值产品来说,这可能是整个产品线最划算的安全投入。类似方案还有NXP的SE050、英飞凌的OPTIGA系列,原理大同小异,选择时主要看算法支持、温度等级、供货稳定性和产线工具链。
2.3 SoC内部的TrustZone安全世界:RK3588这类高级形态
RK3588这类应用处理器上的“硬件加密”又不一样了。它的CPU核心支持TrustZone技术,芯片内部有多个安全启动只读存储器、OTP密钥存储、Crypto Extension加密扩展,同时还运行一个单独的TEE操作系统(比如OP-TEE)。
在这种架构里,普通Linux系统跑在“非安全世界”,密钥相关的操作放在“安全世界”执行。即使Linux内核被攻破、应用被植入恶意代码,攻击者拿到的也只是非安全世界的内存视图,隔离的安全世界根本进不去。加上Secure Boot机制,启动过程中每一级代码都要验签,芯片只运行签名正确的固件,这等于把从设备上电到应用运行整条链路的信任基础都建立在了硬件上。
但这种方案的开发复杂度也是三档里最高的。光是把密钥烧进eFuse、配置Security TrustZone Controller、调试可信固件(TF-A)这几个环节,就足够让一个团队忙上几周。而且一旦安全启动配置完成,普通调试器可能连芯片都连不上,很多不熟悉安全机制的工程师会在这时候卡壳。我的建议是:除非产品确实需要跑Linux系统、而且要防的是“有能力拆机并尝试读写Flash甚至注入攻击”的对手,否则用普通MCU加独立安全芯片可能更容易达到安全目标。
3. 性能、密钥存储和被攻破难度:到底差在哪
3.1 性能对比:CPU占用、吞吐量和功耗
做过通信加密的朋友应该对性能差异有直观感受。我曾在72 MHz的Cortex-M3芯片上用纯软件实现AES-128-CBC,单次加密1 KB数据大概耗时1~2毫秒左右,取决于编译器优化级别和查表策略。这听起来不多,但如果是持续传输几百KB传感器数据,CPU基本就一直在做加密运算,主业务逻辑和通信协议栈都得被迫降低优先级。
同样一块芯片,如果内置AES硬件外设,同样的1 KB数据加密耗时能降到几十微秒量级,而且整个过程由DMA搬运,CPU几乎不参与。两者的吞吐差距可以达到几十倍甚至上百倍。当然,这个数字和具体芯片主频、总线时钟、AES外设时钟配置都有关系,不同MCU差异很大,不要拿某个型号的极限值去套另一个型号。
更明显的性能差距出现在非对称算法上。比如用软件在MCU上做一次RSA-2048签名,耗时常常在几百毫秒到秒级,这不仅影响用户体验,高负荷下还可能引发看门狗超时。改用带RSA硬件加速或者独立安全芯片后,一次签名可以缩短到几十毫秒甚至几毫秒。功耗方面,专用硬件电路比通用CPU执行同一运算的效率高得多,对电池供电设备来说,完成一次签名的时间越短,平均功耗越低,这也是我在低功耗产品上优先选硬件加密的原因之一。
3.2 密钥会不会被读走:Flash明文存储是个大问题
软件加密最大的软肋,是密钥的存放方式。大多数MCU的Flash并不防读。只要攻击者能通过调试接口(SWD/JTAG)、Bootloader漏洞、或者直接拆下Flash芯片物理读取,就能拿到里面的固件镜像,再用binwalk一类的工具提取字符串和数组,AES密钥、API密钥基本就暴露了。
有人会想“那我把固件整体加密行不行”,这就又需要一个解密的密钥,兜兜转转还是回到“密钥放哪”的问题。还有人试图通过混淆数组、拆开存储、异或一个常数来藏密钥,这些办法只能防住最简单的静态分析,对能动态调试的人来说基本形同虚设。
硬件加密解决的就是这个问题。独立安全芯片和带eFuse/OTP安全区的MCU,都把密钥放在只能被内部安全状态机访问的存储单元里。CPU只能“用”这个密钥,不能“读”这个密钥。就算调试器能读全部内存,能dump全部Flash,看到的也只能是经密钥加密后的结果,而不是密钥本身。
3.3 物理攻击与侧信道防护:硬件到底“硬”在哪
这个层面是普通项目里最容易忽视、但安全研究里最看重的部分。攻击者如果拿到设备本体,可以做功耗分析(DPA/SPA)、电磁辐射分析、电压/时钟毛刺注入、激光切割芯片内部结构等操作,这类统称为侧信道攻击和物理攻击。
软件实现加密时,CPU的功耗和电磁辐射会随着当前指令和数据变化而波动,攻击者采集大量加密波形,再结合已知明文统计建模,有可能把密钥反推出来。这就是为什么密码学教材里反复强调“常数时间实现”。很多软件库做得好的(如mbedTLS的某些版本)会尽量做常数时间运算,但通用CPU流水线、Cache命中率、分支预测这些硬件行为很难完全控制。
硬件密码学引擎在设计时就把侧信道防护纳入考量,比如固定执行周期、内部随机掩码、功耗均衡、故障检测。芯片物理层还可能做屏蔽层、防探测走线、主动篡改检测网。这不是说硬件加密绝对安全——任何安全方案都有被实验室级攻击手段破解的可能——但攻击成本会高好几个数量级,对绝大多数商业产品来说,这个成本已经足以劝退盗版者。
4. 怎么选,怎么落地:实操与避坑
4.1 选型决策树:别盲目追求“最硬”方案
安全设计和性能优化一样,第一步永远是定义威胁模型。我见过最典型的问题就是:做一个普通物联网传感器,数据只是温度湿度,也非要上一颗独立安全芯片。这属于把好钢用在了刀背上。反过来,做一个几千元的工业控制器,固件是整个产品的核心资产,结果连Flash读保护都没开,这就属于风险敞口太大。
我一般会按下面几条线来决策:
- 只是为了防止误连接、保住通信链路的保密性,设备本身不涉及高价值资产,软件AES/ChaCha20加TLS就够了。
- 固件算法有较高商业价值,担心被抄板,至少要用带AES硬件外设和读保护的MCU,配合唯一ID做签名认证。
- 产品需要做配件认证、防伪验证、或者有明确的合规要求,直接上独立安全芯片。
- 跑Linux/Android系统且需要Secure Boot,选带TrustZone和OTP密钥的SoC,配置TEE环境。
- 车规、工业控制等高安全等级场景,查一下EVITA/ISO 21434相关要求,大概率要上HSM硬件安全模块,那不是普通加密外设能替代的。
4.2 看似“硬件加密”但实际不安全的三种情况
第一种是只有加密引擎、没有安全密钥存储。芯片支持AES加速,但密钥明文存在Flash里。这种情况硬件只起了加速作用,安全性和软件加密差别不大。
第二种是安全功能默认关闭。不少芯片的安全启动、读保护、TrustZone功能默认是开着的,或者提供了配置选项之后,要主动去固化。很多项目为了方便调试,把调试接口一直开着,把安全启动机制临时关掉甚至从未打开,产品量产时就直接裸奔了。
第三种是密钥注入环节出了问题。就算用了ATECC608A这种安全芯片,如果产线在写密钥的时候用的是临时编写的上位机脚本,没有加密传输、没有脱机工具、参与人员能随意导出密钥文件,那再好的硬件也白搭。安全是整条链路的工程,不是单点芯片能兜底的。
4.3 密钥注入与产线管理:容易被忽略的环节
密钥注入这块我确实吃过亏。有次替客户做安全认证方案,硬件选型、匹配流程都走完了,最后卡在产线上:安全芯片的密钥需要由服务器生成,通过产测软件写入,但产线电脑本身就联网,还装了各种不明软件,密钥文件在电脑上放了很久。这等于直接把保险柜密码贴在了柜子上。
正确的做法一般是这样:密钥生成和存储放在离线环境或者专用HSM里,产线通过加密协议把“待烧录的密钥密文”下发,烧录工具只支持写入,不支持读取,烧完之后立即做一次校验并清除本地缓存。再进一步,按批次拆封密钥,每台设备拿到不同的密钥,避免一个泄露全盘皆输。另外,烧录环节要记录日志查审计,数量要对得上芯片出库数量,防止多余的、带密钥的芯片流向不可控渠道。
5. 常见问题与排查技巧实录
5.1 常见问题快查表
| 现象 | 可能原因 | 排查与解决思路 |
|---|---|---|
| 调用硬件AES外设后程序跑飞 | 未使能AHB/APB总线时钟或未正确复位 | 检查RCC寄存器,确认外设时钟开启,在初始化时先复位模块再配置 |
| 加密结果和软件加密不一致 | 字节序/数据对齐方式不同,或密钥字节序处理错误 | 对比两边的密钥存储顺序(大端/小端),确认AES模式(ECB/CBC/CTR)和填充方式一致 |
| 使用ATECC608A等安全芯片通信失败 | I2C地址、总线速度、延时参数不对 | 看数据手册的时序要求,I2C频率别拉太高,确认唤醒序列是否正确 |
| 开了读保护后调试器连不上MCU | RDP级别设置过高或设置后未全片擦除 | 需要全片擦除才能降级,量产前先确认调试策略;建议做成可配置开关 |
| 安全启动配置后固件无法启动 | 密钥烧录顺序或签名工具链版本不匹配 | 先烧key,再烧签名固件,确认校验证书和烧录密钥ID对应;保留一级回退bootloader |
| 实测硬件加密功耗不降反升 | 加密外设时钟一直全速跑,没有门控 | 只在需要时打开加密外设时钟,完成后立刻关闭,尽量用DMA减少唤醒次数 |
5.2 几个真实调试经验
第一个经验来自STM32系列。之前用STM32L4的AES外设做GCM模式数据加密,一开始怎么都不通过,最后发现是数据寄存器是32位的,而我的数据缓冲区是按字节对齐的。把输入数据改成uint32_t数组、按手册要求做字节序翻转之后,问题就消失了。所以遇到硬件加密结果不对,先别怀疑芯片,优先检查数据格式、密钥格式和算法模式。
第二个经验是ESP32上的Secure Boot和Flash加密配合。默认情况下ESP32的Flash加密只加密代码段,如果应用层在NVS(非易失存储)里存了敏感数据,那部分是不受保护的。我当时在NVS里放了通信用的预共享密钥,后来才意识到,Fortune-flash backup或者攻击者直接读出NVS分区,密钥照样泄露。这类问题不是硬件不支持,是“硬件能力”和“使用方式”没有对齐。
第三个经验是调试独立安全芯片的时候,特别容易被外部的上拉电阻坑到。I2C总线上ATECC608A需要在地址脚上正确处理上下拉,有的开发板上默认上了拉,导致芯片地址漂移,怎么都枚举不到设备。花了一个下午查I2C波形才发现的。所以硬件安全方案出问题时,先把物理层和电源时序排干净,别一头扎进密码学细节里。
还有个提醒,不少硬件加密模块在低功耗模式下是不工作的。你在Sleep模式下调一次签名请求,芯片可能一直等不到回应,造成了莫名的唤醒电流。产品设计时一定要把“进入低功耗前关掉加密外设、唤醒后重新初始化”这个流程写清楚。
选型的时候也别忽略了工具链的成本。独立安全芯片的配置工具、密钥管理软件、产线烧录方案,这些不是免费送的。ATECC608A有配套的CryptoAuthLib,看起来还不错,但真要集成到自己的安全启动和通信协议里,需要花时间读API文档和参考设计。ROI要算清楚,别安全等级上去了,开发周期也跟着上去了。
我自己的习惯是:产品定义阶段先把“我要防谁”写清楚,再根据威胁选择安全等级,最后才去翻芯片选型表。方案落地时,一定会专门留一块时间验证密钥注入流程和产线工具链,因为这块的隐藏问题,往往比算法代码本身多得多。