密码学基础(上):对称加密与非对称加密、哈希函数(SHA256)、数字签名原理(RSA/ECDSA)

说实话,很多做嵌入式固件开发的朋友,一听到「密码学」三个字就头大。我当年也一样,觉得这东西是数学家的玩具,跟我写C代码有什么关系?直到我第一次接手一个OTA升级项目,客户要求固件必须签名验证,否则不让跑……嗯,那段时间我恶补了不少密码学知识。

今天这节,咱们就把固件签名里最核心的几个密码学概念讲清楚。不扯太深的理论,重点是你得知道它们怎么用、为什么这么用。

对称加密 vs 非对称加密

先说说加密这件事。你想想看,你要给设备发一条指令,不想被别人偷看,怎么办?最简单的办法就是加密。

对称加密,说白了就是加密和解密用同一把钥匙。就像你家里的大门,用钥匙锁上,再用同一把钥匙打开。常见的算法有AES、DES。优点是快,特别快。我在做低功耗MCU项目时,AES-128硬件加速几乎是标配,几微秒就能加解密一个数据块。

但对称加密有个致命问题——钥匙怎么安全地交给对方?你总不能明文发过去吧?那跟没加密有啥区别?

非对称加密就解决了这个痛点。它有一对钥匙:公钥和私钥。公钥可以公开,谁都能拿到;私钥自己藏好,打死也不给别人。用公钥加密的数据,只有对应的私钥能解开。反过来,用私钥签名的数据,公钥可以验证真伪。

我习惯把非对称加密比作一个带锁的邮箱。任何人都可以把信塞进邮箱(用公钥加密),但只有邮箱主人能打开取信(用私钥解密)。

常见的非对称加密算法有RSA和ECC(椭圆曲线密码学)。RSA比较老,但生态成熟;ECC用更短的密钥达到同等安全强度,对嵌入式设备更友好。

实际项目中的选择:

  • 固件加密传输:用对称加密(AES)加密固件本身,用非对称加密(RSA/ECC)加密AES密钥。这叫「混合加密」,兼顾安全性和性能。
  • 固件签名验证:只用非对称加密。私钥签名,公钥验签。

哈希函数与SHA256

哈希函数是个神奇的东西。你给它一段数据,它给你一个固定长度的「指纹」。这个指纹有几个特点:

  • 不可逆:从指纹推不出原始数据。你想想看,这就像把鸡蛋打成蛋花,你没法再变回一个完整的鸡蛋。
  • 抗碰撞:很难找到两个不同的数据,算出相同的哈希值。
  • 雪崩效应:原始数据改一个比特,哈希值就面目全非。

SHA256是SHA-2家族的一员,输出256位(32字节)的哈希值。我在项目中几乎只用SHA256,原因很简单:安全强度够用,硬件支持广泛。很多MCU都内置了SHA256硬件加速器,算一个1MB的固件,也就几百毫秒的事。

哈希函数在固件签名里扮演什么角色?

你想想看,固件可能几兆甚至几十兆,直接用非对称加密签名,效率太低了。所以实际做法是:先对固件算一个SHA256哈希值,然后只对这个32字节的哈希值做签名。验签时,同样先算固件的哈希值,再验证签名是否匹配。

避坑指南:我曾经遇到过一个坑——固件里包含了签名本身的数据。算哈希时把签名也算了进去,结果验签永远失败。后来我养成了习惯:签名数据必须从固件哈希计算中排除,或者放在固定位置,计算哈希时跳过那个区域。

数字签名原理(RSA / ECDSA)

数字签名,说白了就是给固件盖个章。这个章只有你有(私钥),但任何人都能验证(公钥)。

流程是这样的:

  1. 签名方(你): 计算固件的SHA256哈希值 → 用私钥对哈希值加密 → 得到签名数据 → 把签名附加到固件里。
  2. 验证方(设备): 收到固件 → 计算固件的SHA256哈希值 → 用公钥解密签名 → 得到原始哈希值 → 对比两个哈希值是否一致。

如果一致,说明固件确实是私钥持有者签发的,而且没有被篡改过。

RSA签名:基于大整数分解难题。密钥越长越安全,但计算也越慢。嵌入式设备上,RSA-2048是常见选择。签名操作比较慢(因为要用私钥),但验签相对快一些。

ECDSA签名:基于椭圆曲线离散对数难题。同样的安全强度下,密钥比RSA短得多。比如256位的ECDSA,安全等级相当于3072位的RSA。这对存储空间有限的嵌入式设备来说,优势很明显。

我个人更倾向ECDSA,尤其是做IoT设备时。密钥短、签名短、计算快。但要注意,ECDSA的实现比RSA复杂,容易出安全漏洞。比如随机数生成器如果不够随机,私钥就可能泄露。嗯,这里要特别小心。

重要提醒: 签名 ≠ 加密。签名用的是私钥,验证用的是公钥。加密用的是公钥,解密用的是私钥。这两个流程千万别搞混了。我见过有人把签名说成「用私钥加密」,虽然意思差不多,但容易误导新人。

知识体系总览

下面这张图,把今天讲的核心逻辑串起来了。你可以看到,固件签名和验证,本质上就是哈希函数 + 非对称加密的组合拳。

固件签名与验证核心流程 签名方(开发者) 固件文件 原始固件(如 firmware.bin) ↓ SHA256 哈希计算 32字节哈希值(H) 私钥 签名运算 签名数据(S) 打包:固件 + 签名数据 → 签名固件 传输 验证方(设备) 收到签名固件 提取固件 + 签名数据 ↓ SHA256 哈希计算 32字节哈希值(H') 公钥 验签运算 对比 H' 与解密后的 H 一致 → 固件可信 ✅ 核心:哈希函数(SHA256)+ 非对称加密(RSA/ECDSA) 私钥签名,公钥验签,固件不可篡改 签名方 验证方 密钥

实际项目中的选择建议

场景 推荐算法 密钥长度 备注
资源受限MCU(如Cortex-M0) ECDSA(P-256) 256位 签名短,验签快,适合小Flash
高性能处理器(如Cortex-A) RSA-2048 或 ECDSA 2048位 / 256位 RSA生态好,工具链成熟
需要兼容旧设备 RSA-2048 2048位 很多老设备只支持RSA
安全等级要求极高 ECDSA(P-384)或 RSA-4096 384位 / 4096位 计算开销大,慎用

我的个人习惯: 新项目一律用ECDSA P-256。密钥短、签名短、性能好。唯一要注意的是,确保随机数生成器足够安全。我曾经在一个项目里,因为硬件随机数生成器有缺陷,导致ECDSA签名时重复使用了随机数,结果私钥被算出来了……那真是血的教训。

好了,这一节的内容就到这儿。密码学基础是固件签名的地基,地基不稳,上面盖的房子再漂亮也没用。下一节咱们会深入具体的签名工具链和命令行操作,到时候手把手带你走一遍完整的签名流程。

可可精品资料库