4、密码学基础(上):对称加密(AES)、非对称加密(RSA/ECC)、哈希函数(SHA256)

做 BootLoader 安全升级,说白了就是解决三个问题:怎么保证升级包不被偷看?怎么保证它确实是官方发的?怎么保证它没被篡改?这三个问题,分别对应着加密、签名和完整性校验。而它们的根基,就是密码学。

这一章我们先啃最核心的三个工具:AES(对称加密)、RSA/ECC(非对称加密)和 SHA256(哈希函数)。别被这些缩写吓到,我会用实际项目里的例子把它们讲透。

核心观点:没有密码学,BootLoader 升级就是裸奔。攻击者可以伪造固件、窃取密钥、植入后门。我见过太多因为「先上线再补加密」导致翻车的项目了。

密码学基础(上)知识体系图 密码学基础(上)核心知识体系 对称加密(AES) 非对称加密(RSA/ECC) 哈希函数(SHA256) ECB / CBC / CTR 模式 128/192/256 位密钥 硬件加速(AES-NI / CRYP) 公钥加密 / 私钥解密 RSA-2048 / ECC-256 对比 数字签名(ECDSA / RSA-PSS) 固定 256 位输出 雪崩效应 / 抗碰撞 固件完整性校验 ⚠️ 实际 BootLoader 升级中,三者协同工作: SHA256 校验固件 → RSA/ECC 签名验证 → AES 解密固件内容

4.1 对称加密:AES 是怎么保护固件内容的?

对称加密,就是加密和解密用同一把钥匙。你想想看,就像你用一把锁锁住箱子,寄给朋友,朋友用同样的钥匙打开。在 BootLoader 场景里,固件在服务器上用密钥加密,设备收到后用同样的密钥解密。

AES(Advanced Encryption Standard)是目前最主流的对称加密算法。我个人的习惯是,只要硬件支持,优先选 AES-256。为什么?因为 AES-128 虽然目前还安全,但量子计算一旦成熟,128 位密钥的强度就不够了。而 AES-256 还能扛一阵子。

AES 的工作模式

AES 本身只处理 16 字节的数据块。要加密一整段固件,就得用「模式」。这里我重点讲三种最常见的:

模式 特点 BootLoader 适用性 我踩过的坑
ECB 每个块独立加密,简单 ❌ 不推荐 相同明文块产生相同密文块,容易被分析
CBC 需要 IV,每个块依赖前一个 ✅ 常用 IV 必须随机且每次不同,否则有风险
CTR 流模式,可并行加解密 ✅ 推荐 计数器不能重复,否则 XOR 密钥流会泄露

⚠️ 千万不要用 ECB 模式加密固件!我曾经接手过一个项目,前任工程师用 ECB 加密升级包,结果固件里有大量重复的 0xFF 填充字节,密文一眼就能看出规律。攻击者不需要破解密钥,光靠模式分析就能定位关键代码段的位置。

我个人最推荐 CTR 模式。原因有三:第一,它可以并行计算,在支持多核或硬件加速的芯片上速度飞快;第二,它不需要填充,固件长度任意;第三,加解密逻辑完全一样,代码量少一半。

AES 在 BootLoader 中的典型用法

/* 伪代码:AES-CTR 解密固件块 */
#define AES_BLOCK_SIZE 16

int aes_decrypt_firmware(uint8_t *ciphertext, uint32_t len,
                         uint8_t *key, uint8_t *iv, uint8_t *plaintext)
{
    AES_CTR_ctx ctx;
    uint32_t offset = 0;

    aes_ctr_init(&ctx, key, iv);

    while (offset < len) {
        uint32_t chunk = MIN(len - offset, 1024); // 每次处理 1KB
        aes_ctr_decrypt(&ctx, ciphertext + offset,
                        plaintext + offset, chunk);
        offset += chunk;
    }

    return 0;
}

💡 小技巧:在 BootLoader 里,IV 通常由两部分组成:一个固定的种子(烧录在芯片 OTP 里)加上固件头部的随机数。这样即使同一份固件,每次升级的 IV 也不同,防止重放攻击。

4.2 非对称加密:RSA 和 ECC 怎么保证固件来源可信?

对称加密有个致命问题:密钥怎么安全地分发给设备?如果密钥在产线里被泄露,或者被逆向工程提取,整个加密体系就崩了。

非对称加密解决了这个问题。它用一对密钥:公钥公开,私钥保密。服务器用私钥签名固件,设备用公钥验证签名。公钥就算被攻击者拿到,他也无法伪造签名。

RSA vs ECC:怎么选?

对比项 RSA-2048 ECC-256(secp256r1)
密钥长度 2048 位 256 位
签名长度 256 字节 64 字节
签名速度 较慢(私钥操作) 快
验签速度 较快(公钥操作) 较快
安全强度 等效 112 位对称密钥 等效 128 位对称密钥
硬件资源消耗 高(大数运算) 低(椭圆曲线运算)

嗯,这里要注意:ECC 在资源受限的 MCU 上优势非常明显。我记得有一次给一个 Cortex-M0 的芯片做安全升级,RSA-2048 验签一次要 2 秒多,换成 ECC-256 后降到 200 毫秒以内。用户按「升级」按钮后的等待感完全不一样。

数字签名流程(以 ECDSA 为例)

  1. 服务器端:计算固件的 SHA256 哈希值 → 用私钥对哈希值签名 → 将签名附加到固件包中。
  2. 设备端:接收固件包 → 计算本地 SHA256 哈希值 → 用公钥验证签名 → 匹配则继续,不匹配则拒绝升级。

关键点:签名验证的是「哈希值」,不是整个固件。因为非对称加密处理大块数据非常慢。先哈希再签名,是工程上的标准做法。

公钥的存储安全

公钥虽然可以公开,但必须保证它没有被篡改。如果攻击者替换了设备里的公钥,他就能用自己的私钥签名恶意固件。

我建议的做法是:

  • 将公钥哈希烧录到芯片的 一次性可编程(OTP)区域。
  • BootLoader 启动时,先验证公钥的哈希是否与 OTP 中的值一致。
  • 如果一致,才用该公钥验证固件签名。

⚠️ 我曾经见过一个产品,公钥直接明文存在外部 Flash 里。攻击者用逻辑分析仪抓取 SPI 通信,轻松替换了公钥,然后签了一个挖矿程序进去。设备变成了肉鸡。这个教训告诉我们:公钥可以公开,但不能被篡改。

4.3 哈希函数:SHA256 如何保证固件完整性?

哈希函数,说白了就是一个「数字指纹」。不管你的固件是 1KB 还是 1MB,SHA256 都会输出一个固定 256 位(32 字节)的摘要。只要固件里改了一个比特,摘要就会变得面目全非——这就是所谓的雪崩效应。

SHA256 在 BootLoader 中的三个用途

  1. 完整性校验:升级前计算固件的 SHA256,与固件头部的声明值对比。不一致则拒绝升级。
  2. 签名的基础:如上一节所说,非对称签名是对哈希值签名,不是对原始固件。
  3. 密钥派生:可以用 SHA256 从主密钥派生出会话密钥,避免主密钥直接暴露。

代码示例:计算固件块的 SHA256

/* 伪代码:分块计算 SHA256,适合内存受限的 BootLoader */
#define SHA256_DIGEST_SIZE 32

int compute_firmware_hash(uint8_t *firmware, uint32_t size,
                          uint8_t hash_out[SHA256_DIGEST_SIZE])
{
    SHA256_CTX ctx;
    uint32_t offset = 0;

    sha256_init(&ctx);

    while (offset < size) {
        uint32_t chunk = MIN(size - offset, 512); // 每次 512 字节
        sha256_update(&ctx, firmware + offset, chunk);
        offset += chunk;
    }

    sha256_final(&ctx, hash_out);
    return 0;
}

💡 实际项目经验:在 BootLoader 里,我习惯把 SHA256 计算和 AES 解密流水线化。一边解密一边算哈希,等解密完成,哈希也出来了。这样既省内存又省时间。不过要注意顺序:先算原始密文的哈希,再解密。如果先解密再算哈希,那验证的是明文,逻辑上就不对了。

4.4 三者如何协同工作?

在真正的 BootLoader 安全升级中,这三个算法不是各自为战,而是打配合的。我画了一张流程图,帮你理清关系:

BootLoader 安全升级密码学协同流程 BootLoader 安全升级密码学协同流程 接收固件包 SHA256 校验 RSA/ECC 验签 AES 解密固件 写入 Flash 升级完成 ✅ 注意顺序 先校验哈希 再验证签名 最后解密 顺序错了 安全漏洞

这个流程里,顺序很重要。先校验哈希,确保固件在传输过程中没有被损坏;再验证签名,确认固件来自合法的发布方;最后用 AES 解密,得到可执行的明文固件。每一步都依赖上一步的结果,环环相扣。

总结一下:

  • AES 负责「保密」—— 固件内容不被窃听。
  • RSA/ECC 负责「认证」—— 固件来源可信。
  • SHA256 负责「完整性」—— 固件未被篡改。

三者缺一不可。少了任何一个,你的 BootLoader 升级就是纸糊的。