代码签名基础:数字签名的原理与算法选择

聊到物联网安全更新,绕不开的一个基础就是代码签名。说白了,代码签名就是给固件或软件包贴上一张「防伪标签」。这张标签能证明两件事:第一,这东西确实是你发布的;第二,这东西在发布后没被人动过手脚。

我刚开始接触物联网安全时,觉得签名就是个「加个密」的事。后来踩了坑才明白,这里面的门道比想象中多得多。咱们今天就把这块掰开揉碎了讲清楚。

数字签名的核心原理:哈希 + 非对称加密

数字签名不是把整个文件加密,那样太慢了。它用的是「哈希 + 非对称加密」的组合拳。流程其实很清晰:

  1. 对固件做哈希:用 SHA-256 这类算法,把任意大小的固件压缩成一个固定长度的摘要(比如 32 字节)。
  2. 用私钥加密哈希值:只有你持有的私钥能完成这一步,加密后的哈希值就是「签名」。
  3. 打包发布:固件 + 签名 + 你的公钥证书,一起发给设备。
  4. 设备验签:设备用你的公钥解密签名,拿到原始哈希值;再对收到的固件重新算一次哈希。两个哈希一比对,一致就通过。

这里有个关键点:哈希是单向的。你从固件算出哈希很容易,但从哈希反推固件几乎不可能。这就保证了攻击者没法伪造一个「看起来一样」的恶意固件。

核心逻辑:私钥签名 = 身份证明,哈希校验 = 完整性证明。两者缺一不可。

我在项目中见过有人只做哈希校验,不做签名。结果攻击者替换了固件和哈希值,设备照单全收。嗯,这种坑踩一次就记住了。

签名算法的选择:RSA vs ECDSA

选算法是架构设计阶段就要定的事。目前主流就两个阵营:RSA 和 ECDSA。我个人的经验是,没有绝对的好坏,关键看你的设备资源。

对比维度 RSA(如 RSA-2048) ECDSA(如 P-256)
密钥长度 2048 位(约 256 字节) 256 位(约 32 字节)
签名长度 256 字节 64 字节
验签速度 较快 更快(约快 3-5 倍)
生成签名速度 较慢 较快
硬件支持 几乎所有安全芯片都支持 较新芯片支持,老芯片可能没有
安全性(当前) 2048 位等效于 112 位对称安全 P-256 等效于 128 位对称安全

你想想看,物联网设备很多是资源受限的——MCU 可能只有几十 KB 的 RAM,Flash 也捉襟见肘。ECDSA 的签名短、验签快,天然适合这种场景。但有个前提:你的安全芯片或 MCU 必须硬件支持 ECDSA 运算。纯软件实现 ECDSA 在低端 MCU 上跑,慢得让人抓狂。

我曾经在一个项目里选了 ECDSA,结果发现设备用的老款 STM32 没有硬件加速。验签一次要 2 秒多,用户升级固件时体验极差。后来被迫切回 RSA-2048,虽然签名长了点,但验签只要 200 毫秒。所以我的建议是:先确认硬件能力,再选算法。

我的建议:如果设备有独立安全芯片(如 ATECC608A),优先用 ECDSA。如果只是 MCU 内置的软件库,RSA 更稳妥。

签名时间戳的作用

时间戳这东西,很多人容易忽略。但它其实是个「救命」的设计。为什么?因为证书会过期。

假设你的代码签名证书有效期是 2023 年到 2025 年。你在 2024 年签了一个固件,设备验签通过。到了 2026 年,证书过期了,设备还能不能安装这个固件?

如果没有时间戳,设备会检查证书有效期,发现已过期,直接拒绝安装。这就尴尬了——固件本身没问题,只是证书过期了。

时间戳的作用就是:证明签名是在证书有效期内完成的。具体做法是:

  1. 签名时,把当前时间发给一个可信的时间戳机构(TSA)。
  2. TSA 返回一个带时间戳的签名,证明「这个签名发生在 2024 年 3 月 15 日 10:00:00」。
  3. 设备验签时,只要确认时间戳本身有效,就不管证书是否过期。

说白了,时间戳把「签名时刻」和「验签时刻」解耦了。你 2024 年签的固件,设备 2030 年照样能装。

注意:时间戳服务本身也要可信。如果 TSA 的证书被攻破,攻击者可以伪造任意时间戳。所以时间戳机构的根证书必须预置在设备中,且要定期更新。

我在做智能电表 OTA 时,就吃过没加时间戳的亏。电表部署后 5 年没更新,第 6 年想推送一个安全补丁,结果发现签名证书已经过期了。最后只能远程更新证书,再推送固件,折腾了整整两周。从那以后,我所有签名流程都强制加时间戳。

一张图看懂代码签名流程

下面这张 SVG 图把整个流程串起来了,从签名到验签,一目了然。

代码签名与验签流程 代码签名与验签流程 签名方(开发者) ① 对固件做 SHA-256 哈希 ② 用私钥加密哈希 → 生成签名 ③ 请求 TSA 添加时间戳 ④ 打包:固件 + 签名 + 时间戳 + 证书 网络传输 验签方(设备) ⑤ 验证证书 ⑥ 验证时间戳 ⑦ 用公钥解密签名 ⑧ 比对哈希值 ✅ 通过 / ❌ 拒绝 关键说明: • 步骤 ③ 时间戳由可信时间戳机构(TSA)生成,证明签名发生在证书有效期内。 • 步骤 ⑥ 设备验证时间戳时,不检查签名证书是否过期,只检查时间戳本身是否有效。 • 哈希比对(步骤 ⑧)确保固件未被篡改,公钥解密确保签名来自持有私钥的开发者。

实际部署中的几个坑

理论讲完了,说几个我实际踩过的坑,希望能帮你少走弯路。

  • 私钥保管:私钥一旦泄露,整个信任体系就崩了。我见过有人把私钥放在 CI 服务器的环境变量里,结果 CI 被入侵,所有固件都得重新签名。建议用硬件安全模块(HSM)或云 KMS 服务。
  • 证书链长度:物联网设备资源有限,证书链太长会导致验签慢、占用 Flash 多。我一般控制在 2-3 级(根 CA → 中间 CA → 代码签名证书)。
  • 哈希算法选择:SHA-1 已经不安全了,别用。SHA-256 是当前最低要求。如果设备性能允许,可以考虑 SHA-384 或 SHA-512。
  • 时间戳的时钟同步:设备如果没有 RTC 或 NTP 同步,时间戳验证可能出问题。我的做法是:设备只验证时间戳的签名有效性,不验证时间戳的「时间值」是否在合理范围内。

重要提醒:代码签名不是「签一次就完事」。证书会过期,算法会变弱,密钥可能泄露。你需要建立一套完整的证书生命周期管理机制,包括定期轮换、吊销和更新。