第四节:签名算法基础

好,咱们进入正题。签名算法这块,说白了就是OTA安全的基石。你想想看,如果连签名都搞不明白,那后面的校验、升级全都是空中楼阁。我刚开始做IoT安全那会儿,也踩过不少坑,今天就把这些经验掰开了揉碎了讲给你听。

4.1 对称加密与非对称加密

先聊加密。加密这事儿,其实没那么玄乎。我习惯把加密比作「锁箱子」——你有一把钥匙,把东西锁进去,别人没钥匙就打不开。

对称加密,就是加密和解密用同一把钥匙。比如AES、DES这些算法。优点是快,特别快。我做过测试,在Cortex-M4上跑AES-128,加密1KB数据也就几十微秒。但问题来了——钥匙怎么安全地传给对方?

对称加密的核心痛点:密钥分发

你在深圳,设备在纽约。你怎么把密钥安全地传过去?走网络?可能被截获。走快递?可能被拆包。这就是所谓的「密钥分发问题」。

非对称加密就不一样了。它用一对钥匙:公钥和私钥。公钥可以公开,私钥自己藏着。你用公钥加密,只有对应的私钥能解开。反过来,你用私钥签名,别人用公钥验证。

典型的算法有RSA、ECC。RSA我用的比较多,但ECC在资源受限的IoT设备上更吃香——密钥短、算得快。我记得有个项目,设备只有64KB Flash,跑RSA-2048太吃力,换成ECC-256就舒服多了。

特性 对称加密 非对称加密
密钥数量 1个(共享密钥) 2个(公钥+私钥)
速度 快(硬件加速常见) 慢(比对称慢100-1000倍)
典型算法 AES, DES, SM4 RSA, ECC, SM2
适用场景 大量数据加密 密钥交换、数字签名

我的建议:实际项目中,很少只用一种。通常是「混合加密」——用非对称加密传对称密钥,然后用对称密钥加密实际数据。这样既安全又高效。

4.2 哈希函数

哈希函数,说白了就是「数字指纹」。你给它一段数据,它给你一个固定长度的摘要。哪怕数据改了一个比特,摘要就完全变了。

常见的哈希算法有MD5、SHA-1、SHA-256、SM3。MD5和SHA-1现在基本被淘汰了——碰撞攻击太容易。我建议至少用SHA-256,安全级别够用。

避坑指南:我曾经在一个项目里看到有人用MD5做固件完整性校验。结果呢?攻击者伪造了一个固件,MD5值一模一样。从那以后,我所有项目都强制要求SHA-256起步。

哈希函数有几个关键特性:

  • 单向性:从哈希值反推原始数据,几乎不可能。你想想看,SHA-256输出256位,可能的输入却是无限的,怎么反推?
  • 抗碰撞性:找到两个不同输入但哈希值相同,计算上不可行。嗯,这里要注意,MD5已经被攻破了,SHA-1也快了。
  • 雪崩效应:输入改1比特,输出大约一半的比特会翻转。这个特性在签名校验里特别有用。

在OTA升级里,哈希函数主要干两件事:

  1. 固件完整性校验:下载完固件后,算一下哈希值,跟服务器给的对比。不一样?说明传输过程中被篡改了。
  2. 数字签名的预处理:先对固件做哈希,再对哈希值签名。这样签名速度快,而且安全。

4.3 数字签名原理

数字签名,你可以理解为「电子印章」。它解决了三个问题:

  • 身份认证:这个固件到底是不是官方发布的?
  • 完整性:固件有没有被篡改过?
  • 不可否认性:发布者不能事后说「我没发过这个固件」。

签名流程其实不复杂:

  1. 服务器对固件做哈希,得到摘要H
  2. 服务器用私钥对H加密,得到签名S
  3. 服务器把固件和签名S一起发给设备
  4. 设备收到后,用公钥解密S,得到H'
  5. 设备对收到的固件做哈希,得到H''
  6. 比较H'和H'',一致则签名验证通过

关键点:设备上只存公钥,不存私钥。私钥一旦泄露,整个系统就完了。我见过有人把私钥硬编码在固件里...嗯,那基本等于把家门钥匙贴在门上。

代码示例(伪代码,实际项目中用OpenSSL或mbedTLS):

// 服务器端签名
hash = SHA256(firmware_data)
signature = RSA_private_encrypt(hash, private_key)
send(firmware_data, signature)

// 设备端验证
hash_received = SHA256(firmware_data)
hash_decrypted = RSA_public_decrypt(signature, public_key)
if (hash_received == hash_decrypted) {
    // 签名验证通过,可以升级
} else {
    // 签名验证失败,拒绝升级
}

个人经验:实际项目中,我习惯在签名前加一个「盐值」(salt)。比如哈希时把固件版本号、设备ID也加进去。这样即使两个设备刷同一个固件,签名也是不同的。可以防止重放攻击。

4.4 签名算法在OTA中的实战考量

讲完理论,咱们聊聊实战。我做过十几个OTA项目,有些坑是共通的:

1. 密钥管理

公钥怎么安全地烧录到设备里?我建议在产线上用专门的烧录工具,通过安全通道写入。千万别用OTA方式下发公钥——那等于自己给自己挖坑。

2. 算法选择

资源受限的设备(比如ESP8266、STM32F0),跑RSA-2048签名验证可能要几秒钟。这时候ECC-256就香了,速度快、密钥短。我有个项目,从RSA切到ECC后,签名验证时间从3秒降到了0.3秒。

3. 防回滚

签名验证通过还不够。攻击者可能拿一个旧版本的固件(有已知漏洞)来刷。所以签名里一定要包含版本号,设备要检查版本号是否大于当前版本。

我曾经踩过的坑:有个项目,签名验证都做了,但忘了检查版本号。结果攻击者刷了一个有漏洞的旧版本固件,绕过了所有安全机制。从那以后,我每个OTA项目都强制要求版本号检查。

4. 性能优化

签名验证是计算密集型操作。我建议:

  • 只在关键节点做签名验证(比如升级前、启动时)
  • 用硬件加速(很多MCU有硬件加密引擎)
  • 缓存验证结果,避免重复计算

好了,签名算法的基础就这些。说白了,对称加密管速度,非对称加密管安全,哈希函数管完整性,数字签名管认证。把这四样组合好,OTA安全就稳了一大半。下一节咱们讲具体的签名校验实现,到时候我会带大家手写一个完整的校验流程。