嵌入式系统中的签名验证:设计与原理解析(C/C++代码实现)
在嵌入式系统中,固件的完整性和合法性至关重要。例如,智能设备的 bootloader 若加载了被篡改的固件,可能导致系统崩溃甚至被植入恶意代码。Chrome OS 的 “vboot” 系统提供了一套轻量高效的签名验证方案,其核心逻辑可被抽离并应用于各类嵌入式场景。本文将从设计思路、实现原理和相关技术知识点展开,解析这套基于 RSA 和 SHA256 的签名验证机制。
一、核心功能:验证 “谁的” “什么数据” 未被篡改
这套代码的核心目标是验证一段数据(如固件)的完整性和来源合法性。具体来说,它要回答两个问题:
- 这段数据是否与签名时的原始数据一致(未被篡改)?
- 这段数据是否确实由持有对应私钥的主体(如设备厂商)签名(来源合法)?
在嵌入式场景中,最典型的应用是 “固件更新验证”:设备在加载新固件前,通过该机制检查固件是否被篡改、是否来自可信厂商,只有验证通过才允许执行,以此防止恶意固件攻击。
二、设计思路:分层验证与轻量适配
为了在资源受限的嵌入式系统(如 ARM 微控制器)中高效实现安全验证,这套方案采用了 “分层设计” 和 “轻量适配” 思路,具体可拆解为三个核心考量:
1. 分层验证:先哈希,再签名
直接对原始数据(可能很大,如几 MB 的固件)进行加密签名会导致计算量过大,不适合嵌入式设备。因此方案采用 “哈希+签名” 的分层逻辑:
- 第一步:用哈希算法(SHA256)对原始数据计算固定长度的哈希值(256 位)。哈希值可理解为数据的 “数字指纹”,即使原始数据微小改动,哈希值也会完全不同。
- 第二步:用私钥对哈希值进行加密(即 “签名”),验证时用公钥解密签名得到哈希值,再与原始数据的哈希值对比。
这种设计将大文件的签名问题转化为对短哈希值的处理,大幅降低了计算和存储开销,适配嵌入式系统的资源限制。
2. 结构化校验:确保数据格式合规
为了避免解析错误或恶意构造的签名/密钥数据,方案引入了结构化校验逻辑(对应代码中的 vb21_packed_key
和 vb21_signature
结构)。这些结构包含:
- 魔术字(如
VB21_MAGIC_PACKED_KEY
):快速验证数据是否为预期格式,避免解析错误。 - 算法标识(如
sig_alg
、hash_alg
):确保签名和哈希算法与验证逻辑匹配(例如 RSA 对应 SHA256)。 - 偏移量和长度信息:准确定位密钥和签名在二进制数据中的位置,防止越界访问。
这种结构化设计相当于给数据加了一层 “格式防火墙”,确保输入到核心验证逻辑的数据是合规的。
3. 可移植性:适配嵌入式硬件特性
嵌入式系统通常内存小、算力有限(如无硬件加密加速)。方案通过以下方式适配:
- 复用内存:代码中
rsa_workbuf
作为工作缓冲区,避免频繁动态分配内存,减少内存碎片。 - 轻量算法实现:选用 RSA(2048 位)和 SHA256,两者在软件实现上复杂度较低,且 2048 位 RSA 既能提供足够安全性,又不会带来过大计算负担(相比 4096 位更适合嵌入式)。
三、实现原理:从哈希到签名验证的完整链路
...
struct sha256_ctx {uint32_t h[8];uint32_t tot_len;uint32_t len;uint8_t block[2 * SHA256_BLOCK_SIZE];uint8_t buf[SHA256_DIGEST_SIZE];
};void SHA256_init(struct sha256_ctx *ctx);
void SHA256_update(struct sha256_ctx *ctx, const uint8_t *data, uint32_t len);
uint8_t *SHA256_final(struct sha256_ctx *ctx);void hmac_SHA256(uint8_t *output, const uint8_t *key, const int key_len,const uint8_t *message, const int message_len);
int rsa_check_signature(const uint8_t *rwdata, unsigned int rwlen, const struct rsa_public_key *key, const uint8_t *sig
);int vblock_check_signature(const uint8_t *rwdata,const struct vb21_packed_key *vb21_key,const struct vb21_signature *vb21_sig
);
...
struct rsa_public_key {uint32_t size;uint32_t n0inv; uint32_t n[RSANUMWORDS]; uint32_t rr[RSANUMWORDS];
};int rsa_verify(const struct rsa_public_key *key,const uint8_t *signature,const uint8_t *sha,uint32_t *workbuf32);
...int main(int argc, char *argv[])
{
...FILE *f = fopen(argv[1], "r");fseek(f, 0, SEEK_END);rwlen = ftell(f);rewind(f);rwdata = (uint8_t *)malloc(rwlen);if (1 != fread(rwdata, rwlen, 1, f)) {printf("Couldn't load %s\n", argv[1]);return -1;}fclose(f);status = vblock_check_signature(rwdata, (const struct vb21_packed_key *)key_vbpubk2, (const struct vb21_signature *)signature);if (status)printf("Signature matches!\n");elseprintf("Signature does not match :-(\n");return status;
}
If you need the complete source code, please add the WeChat number (c17865354792)
整套验证机制的核心流程可分为 “数据哈希计算” 和 “RSA 签名验证” 两大步骤,环环相扣确保安全性。
1. 哈希计算:生成数据的 “数字指纹”
哈希函数(此处为 SHA256)是验证数据完整性的基础,其核心特性是:
- 确定性:相同输入必然产生相同输出。
- 抗碰撞性:难以找到两个不同输入产生相同输出。
- 单向性:从输出无法反推输入。
在代码中,SHA256_init
、SHA256_update
、SHA256_final
依次完成哈希初始化、增量计算(适合大文件)和最终哈希值生成。例如,对固件数据 rwdata
计算哈希后,得到的 hash
就是这段固件的唯一 “指纹”。
2. RSA 签名验证:确认来源合法性
RSA 是一种非对称加密算法,基于 “公钥加密、私钥解密” 或 “私钥签名、公钥验证” 的特性。在签名验证场景中:
- 签名者(如厂商)用私钥对数据的哈希值加密,生成 “签名”(
sig
)。 - 验证者(如设备)用对应的公钥解密签名,得到一个哈希值,再与自己计算的原始数据哈希值对比。
若两者一致,则说明:
- 数据未被篡改(哈希值匹配);
- 签名确实来自持有私钥的主体(只有对应公钥能解密)。
代码中 rsa_verify
函数即实现了这一过程:用公钥 key
解密签名 sig
,对比解密得到的哈希值与 SHA256_final
生成的哈希值,最终返回验证结果。
四、相关领域知识点:构建安全验证的技术基石
这套方案涉及多个信息安全和嵌入式领域的核心知识点,理解它们有助于深入掌握设计本质。
1. 非对称加密与 RSA
- 核心思想:通过一对数学相关的密钥(公钥、私钥)实现加密/签名。公钥可公开,私钥必须保密。
- 安全性基础:基于大整数分解问题(将大质数乘积分解为原始质数的计算复杂度极高)。2048 位 RSA 目前被认为能抵抗常规攻击,是嵌入式场景的主流选择。
2. 哈希函数与 SHA256
- 作用:将任意长度数据映射为固定长度(256 位)输出,用于验证数据完整性。
- 优势:相比 MD5(已被破解)、SHA1(安全性不足),SHA256 目前仍被广泛认可,且计算过程适合软件优化(如循环展开),适配嵌入式 CPU。
3. 可信启动(Trusted Boot)
- 概念:设备启动时,从最底层的可信代码(如硬件固化的 ROM)开始,逐层验证下一级代码的签名,确保每一步加载的软件都是可信的。
- 关联:本文方案是可信启动的关键环节——验证固件签名,防止恶意代码在启动过程中被加载。Chrome OS 的 vboot 系统正是通过类似机制确保设备启动链的安全。
4. 嵌入式系统安全特性
- 资源限制:嵌入式设备通常内存(KB 级)和算力有限,无法运行复杂加密算法(如 AES-256-GCM 或 4096 位 RSA 的完整实现)。
- 安全需求:需抵御物理攻击(如固件提取)、通信攻击(如中间人篡改更新包),因此签名验证必须轻量化且抗篡改(例如,公钥需固化在只读存储中)。
五、总结:嵌入式安全验证的设计启示
这套从 Chrome OS vboot 抽离的签名验证方案,为嵌入式系统提供了一套 “够用且高效” 的安全验证模板。其设计思路可总结为:
- 用 “哈希+非对称加密” 平衡安全性与效率,适配嵌入式资源限制;
- 通过结构化数据校验(魔术字、算法标识)提升鲁棒性,防止恶意输入;
- 基于成熟算法(SHA256、RSA)确保安全性,同时简化实现以适配硬件。
在实际应用中,开发者可根据场景调整细节(如改用 ECC 算法替代 RSA 进一步减小密钥长度),但核心思路——“先验证数据完整性,再确认来源合法性”——是嵌入式安全验证的通用准则。无论是智能家电的固件更新,还是工业控制器的程序校验,这套设计理念都能为系统安全提供坚实基础。
Welcome to follow WeChat official account【程序猿编码】