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

各位同学,欢迎来到《安全启动固件签名完整方案》的第二讲。今天我们要啃的这块骨头,是整个安全启动体系的基石——密码学基础。说实话,我当年刚接触嵌入式安全时,觉得这些数学概念离我太远了。直到第一次被要求给一个Bootloader做签名校验,才发现不懂这些,连需求文档都看不懂。

这一章我们只讲最核心的四个概念:对称加密、非对称加密、哈希函数、数字签名。别怕,我会用项目里的实际例子帮你理解。

核心观点:安全启动的本质,就是「验证身份 + 验证完整性」。对称加密管保密,非对称加密管身份,哈希函数管完整性,数字签名把后两者合二为一。

密码学基础核心知识体系 密码学基础 对称加密 非对称加密 哈希函数 数字签名 AES / DES RSA / ECC SHA-256 签名验证 安全启动 = 非对称加密(身份) + 哈希(完整性) → 数字签名 对称加密主要用于固件传输加密,启动链中较少直接使用

1. 对称加密:一把钥匙开一把锁

对称加密,说白了就是加密和解密用同一个密钥。就像你家里的门锁,用同一把钥匙锁门和开门。我最早接触对称加密是在做OTA升级包加密时,当时用的就是AES-128。

它的工作流程很简单:

  1. 发送方用密钥K加密明文P,得到密文C
  2. 接收方用同样的密钥K解密密文C,还原出明文P

常见的对称加密算法有:

算法 密钥长度 特点 我的建议
AES 128 / 192 / 256 bit 速度快,硬件加速普遍 嵌入式首选,尤其AES-128
DES 56 bit 已不安全,易被暴力破解 别用了,真的
3DES 112 / 168 bit 慢,兼容旧系统 能不用就不用
SM4 128 bit 国密标准,国内项目要求 国内客户指定时再用

项目经验:我在一个IoT网关项目里,用AES-128-CBC模式加密固件包。当时踩了个坑——IV向量写死了全零。结果安全审计直接被标记为高风险。记住:IV必须随机,每次加密都要不同。

对称加密最大的问题是什么?密钥分发。你想想看,如果我要给1000台设备发密钥,怎么保证密钥在传输过程中不被窃取?这就引出了非对称加密。

2. 非对称加密:公钥锁、私钥开

非对称加密用一对密钥:公钥和私钥。公钥可以公开,私钥必须保密。用公钥加密的数据,只有对应的私钥能解密;反过来,用私钥签名的数据,公钥可以验证。

我习惯把公钥想象成一个「锁盒」:谁都可以把东西放进去锁上,但只有持有私钥的人才能打开。

常见的非对称加密算法:

算法 典型密钥长度 速度 适用场景
RSA 2048 / 4096 bit 慢 签名验证、密钥交换
ECC 256 bit (相当于RSA 3072) 较快 资源受限设备,安全启动
SM2 256 bit 较快 国密替代ECC

避坑指南:我曾经在一个项目里用了RSA 1024位密钥做固件签名。两年后客户要求过FIPS认证,才发现1024位已经被NIST禁止了。现在做新项目,RSA至少2048位,ECC至少256位。别给自己挖坑。

非对称加密虽然解决了密钥分发问题,但计算量太大。加密1MB的固件用RSA?那得等到天荒地老。所以实际项目中,我们通常用「混合加密」——用非对称加密传输对称密钥,再用对称加密加密实际数据。

3. 哈希函数:数据的指纹

哈希函数能把任意长度的数据,压缩成固定长度的摘要。这个摘要就像数据的「指纹」——内容变了,指纹一定变。

哈希函数有三个核心特性:

  • 单向性:从摘要反推原始数据,理论上不可能
  • 抗碰撞性:很难找到两个不同数据有相同摘要
  • 雪崩效应:输入改一个bit,输出一半以上的bit都会变

我在安全启动里最常用的哈希算法是SHA-256。为什么是256位?因为128位已经不够安全了,MD5和SHA-1都被攻破过。

关键理解:哈希函数不加密数据,它只生成「校验和」。在安全启动中,我们先用SHA-256计算固件的哈希值,然后对这个哈希值做签名。这样既保证了完整性,又避免了直接对大文件做非对称加密的性能开销。

来看一个实际例子,计算固件哈希的伪代码:

// 假设固件数据在 firmware_buf 中,长度 fw_len
uint8_t hash[32];  // SHA-256 输出 32 字节

sha256_context_t ctx;
sha256_init(&ctx);
sha256_update(&ctx, firmware_buf, fw_len);
sha256_final(&ctx, hash);

// 此时 hash 数组里就是固件的指纹
// 任何对固件的修改,都会导致 hash 完全不同

4. 数字签名:签名 + 验证的完整流程

数字签名把非对称加密和哈希函数结合起来。它解决两个问题:

  1. 身份认证:这个固件确实是厂商发布的
  2. 完整性校验:固件没有被篡改过

签名流程(在安全的生产服务器上执行):

  1. 计算固件的SHA-256哈希值
  2. 用厂商的私钥对哈希值加密,生成签名
  3. 把签名附加到固件后面,一起发布

验证流程(在设备端Bootloader中执行):

  1. 从固件中提取签名
  2. 计算固件本身的SHA-256哈希值
  3. 用厂商的公钥解密签名,得到原始哈希值
  4. 比较两个哈希值:一致则通过,不一致则拒绝启动

个人经验:我做过一个项目,Bootloader里验证签名时,忘了把签名本身从固件哈希计算中排除。结果每次验证都失败——因为签名变了,哈希就变了,哈希变了签名又不对,死循环了。嗯,这种低级错误,犯过一次就记住了。

用代码表示签名验证的核心逻辑:

// Bootloader 中的签名验证
int verify_firmware(const uint8_t* fw, uint32_t fw_len,
                    const uint8_t* signature, uint32_t sig_len,
                    const public_key_t* pub_key) {
    uint8_t hash[32];
    
    // 1. 计算固件哈希
    sha256(fw, fw_len, hash);
    
    // 2. 用公钥解密签名,得到原始哈希
    uint8_t decrypted_hash[32];
    rsa_verify(pub_key, signature, sig_len, decrypted_hash);
    
    // 3. 比较两个哈希
    if (memcmp(hash, decrypted_hash, 32) == 0) {
        return VERIFY_SUCCESS;  // 签名验证通过
    } else {
        return VERIFY_FAILED;   // 固件被篡改或签名无效
    }
}

5. 四种技术的对比总结

最后,我用一个表格帮你理清这四种技术的关系:

技术 密钥 主要用途 安全启动中的角色 性能
对称加密 单密钥 数据加密 固件传输加密(可选) 快
非对称加密 公钥 + 私钥 身份认证、密钥交换 签名/验证的核心 慢
哈希函数 无密钥 完整性校验 生成固件指纹 快
数字签名 私钥签名 + 公钥验证 身份 + 完整性 安全启动的核心机制 中等

重要提醒:安全启动中,公钥必须被安全地存储在设备中。如果攻击者能替换公钥,那整个签名体系就形同虚设。我见过一个产品,公钥存在外部Flash里,没有任何保护。结果被逆向后,攻击者用自己的公钥替换了原厂公钥,轻松刷入了恶意固件。公钥存储,我们会在后面的章节详细讲。