CRC32是一种检测嵌入式系统中意外的数据损坏的实用方法,尤其适用于固件映像和与安全相关的通信路径中。
概述
• CRC32是一种高效且低成本的检测器,用于检测存储和传输过程中发生的意外数据损坏(如位翻转、突发错误)。它并非完整的安全解决方案。
• CRC32必须明确其变体参数(多项式、初始值、反射规则、最终异或值),并界定其覆盖的具体字节流范围,否则会出现结果不匹配的问题。
• 对于固件镜像完整性与安全的端到端(E2E)保护,CRC32通常作为基础组件,结合消息元数据(ID/长度/序列号)以及系统级处理(超时、重试、回滚、安全状态)共同使用。
背景
CRC32在嵌入式系统中随处可见:引导加载程序、更新包、闪存记录、通信载荷。其速度快、占用空间小,还能检测出许多常见的数据损坏模式。
真正棘手的并非“如何计算CRC”,而是:其一,你实际要应对的故障模型是什么;其二,所有参数与集成层面的细节,这些细节决定了通信两端能否得到一致的32位结果。
CRC32的限制
CRC32是一种错误检测码:它是一个确定性函数,可将字节流映射为一个32位校验值。如果接收方针对相同字节计算出的CRC32与传输/存储的CRC不一致,就说明数据发生了变更。
CRC32不能:
• 纠错(不会提示具体哪一位出错,也无法修复数据)。
• 身份验证(无法证明数据的创建者身份)。
• 防篡改能力(能够修改数据的攻击者通常也可以调整CRC)。
如果需要保证真实性,就需要配套密码学机制(例如签名或MAC/HMAC)以及威胁模型。仅靠CRC32无法实现这一点。
CRC32适用场景
(1)固件镜像与更新包
典型用途:
• 在将映像存储到闪存时检测损坏情况。
• 在更新包传输过程中检测损坏情况。
• 在启动或安装前提供一个快速的完整性检查关口。
(2)Flash/NVM记录
CRC32通常按每条记录或每个块使用,用于检测位腐化、掉电/写入中断的影响,或是写入非预期字节的软件错误。
(3)安全端到端(E2E)保护信封
在分布式嵌入式系统中,CRC32通常是消息信封中的一个字段,用于检测传输过程中的意外损坏。但功能安全E2E通常需要的不只是损坏检测。
CRC32的擅长之处
CRC码的设计初衷是捕获简单校验和(例如字节求和)无法检测到的模式,尤其是多个相邻比特翻转的突发错误。其核心逻辑是CRC的结构能够用很小的校验值检测出多种常见类型的数据损坏。
尽管如此:CRC32仍然是一种32位校验方式。损坏的载荷仍存在一定的残余概率会生成相同的CRC,而“概率”的确切含义取决于你所采用的误差模型。
最大的陷阱:
“CRC32”存在不同变体
即便两种实现都属于“CRC32”,仍可能出现结果不一致的情况。
最小CRC32规范
请在你的规范文档中记下以下字段:
• 多项式(你所指的具体是哪一个CRC32系列)
• 初始值
• 输入反射/输出反射(位反射)
• XorOut(异或)
• 字节流定义:所涵盖的字节及其顺序
• 已知答案测试(KATs):带已知CRC的测试向量
如果你拿不出那份列表,就说明你根本没有明确的CRC32定义,未来集成的时候肯定会出问题。
硬件CRC单元:速度快,但容易配置错误
硬件CRC外设虽然能提升吞吐量,但会放大配置错误的影响。如果MCU配备了CRC外设,这也能成为降低运行时开销的简便方法。但该方法仅在你将外设配置视为CRC32变体定义的一部分时才有效。
需要注意的硬件CRC配置错误:
• 反射设置错误
• 多项式选择错误
• 初始值/异或行为异常
• 按词投喂VS按字节投喂(流定义不匹配)
调试方法:先从短的KAT(例如4–16字节)开始,使用选定的参数在软件中计算,然后将完全相同的字节输入硬件单元并进行对比。
固件镜像完整性:
一种便于审查的模式
本节旨在防范镜像/软件包出现的意外损坏。若需要防篡改能力(抵御恶意更新),则还需搭配密码学层面的身份验证机制。
数据布局模式
一种简单实用的布局如下:
• `header`(魔数字、版本、镜像长度、算法ID)
• `payload`(图像字节)
• `crc32`(基于明确定义的区域计算得出)
规则:明确CRC的覆盖范围是仅头部、仅有效载荷,还是二者均覆盖。将其记录下来并进行测试。
伪代码:计算+验证
常见故障模式(固件完整性)
故障模式:“覆盖字节”定义错误(例如,仅在一侧包含填充字节)
• 症状:仅在部分工具链/构建版本中出现CRC不匹配
• 缓解措施:定义规范字节流;包含KAT;基于显式`length`计算CRC
故障模式:主机工具与引导加载程序之间CRC不匹配
• 症状:“在开发环境正常,在目标环境失败”
• 缓解措施:锁定变体参数;添加供主机与目标端共用的测试向量文件
故障模式:在最终映像处理步骤(对齐、加密、压缩)之前计算CRC
• 现象:封装后出现CRC不匹配
• 缓解措施:对实际存储/传输的最终字节计算CRC
端到端安全:
CRC32是必要条件但非充分条件
如果系统的安全目标是“检测损坏字节”,那么CRC32通常就足够了。
如果安全目标是“检测错误、过时、重复或路由错误的信息”,那么仅使用CRC32通常是不够的,因为这类故障的发生并不会导致有效载荷字节发生变化。
仅靠CRC32无法覆盖的故障模式
故障模式:重放(旧消息重复)
• 症状:有效载荷有效但已过期
• 缓解方案:序列计数器+超时/存活状态监控
故障模式:重排/重复
• 症状:接收方看到消息顺序错乱或重复收到消息
• 缓解措施:序列计数器规则(单调递增、间隙处理)
故障模式:路由错误/发件人错误
• 症状:有效载荷字节完整,但属于其他来源/通道
• 缓解措施:在受保护的信封中包含消息ID/源ID;在接收方验证ID
故障模式:长度解析错误
• 症状:接收器在不同长度的数据上计算CRC(或以不同方式解析字段)
• 缓解措施:将长度纳入受保护字段范围;对序列化进行规范化处理
极简端到端(E2E)封装(与协议无关)
一个实用的基线信封如下所示:
• `msg_id`(本条消息的含义)
• `length`(有效载荷长度)
• `seq`(序列计数器)
• `payload`(数据)
• `crc32`(基于`msg_id || length || seq || payload`计算得出)
接收方补充:
• 超时/存活规则(可接受陈旧数据的时长)
伪代码:构建+校验E2E
注意事项:
• 明确定义序列策略:循环复用、允许的间隙、重置行为。
• 一旦你添加了序列/超时规则,就意味着你已经从“比特完整性”阶段进入了“信息完整性”阶段——这通常才是安全评审真正关注的核心。
CRC32不具备安全性(security)
CRC32是确定性的无密钥校验算法。如果攻击者能够修改有效载荷,通常他们就能为修改后的有效载荷计算出匹配的CRC32值。
如果需要检测蓄意篡改行为,需使用与威胁模型及密钥管理约束相匹配的加密机制(MAC/HMAC或签名)。
检查清单
1. 我们是否有书面的CRC32变体定义(多项式/初始值/输入反转/输出反转/输出异或值)?
2. 通信双方是否会基于完全相同的字节流(标准序列化形式)来计算CRC?
3. 我们是否有可在主机与目标端之间通用的已知答案测试?
4. 若使用硬件CRC:是否已通过短KATs验证反转、初始值、异或输出及输入顺序?
5. 固件:我们是否要对不匹配的情况定义处理方式(拒绝/回滚/重试)?
6. E2E:我们是否会对msg_id+length+seq+负载进行保护(而非仅保护负载本身)?
7. E2E:我们是否定义了序列号策略以及超时/存活规则?
8. 若需要防篡改:我们是否具备真实性机制(MAC/签名)?
结论
CRC32是检测意外损坏的实用工具,但在集成过程中很容易出错。请将CRC定义视为接口:明确变体参数、定义精确字节流,并通过共享测试向量将其固定。
如果需要适用于CRC与E2E通信的即用型模块,可从Safety AddOns入手,该模块包含可选多项式与参数,且根据所用MCU的不同,还可支持硬件加速。
Flexible Safety RTOS是μC/OS-II扩展的功能安全预认证操作系统,包含安全的CRC及E2E附加模块。麦克泰技术是Flexible Safety RTOS在中国的代理商,具有丰富的RTOS应用与安全认证方面的知识和经验,更多功能安全操作系统的支持和授权信息,欢迎咨询麦克泰info@bmrtech.com。
功能安全文章推荐
产品购买(麦克泰)
产品购买(贝尼思)
线上课程(网校)
欢迎关注微信公众号【麦克泰技术】,回复 “加群” 按提示可加入技术交流群
产品咨询:
北京:010-62975900
上海:021-62127690
深圳:0755-82977971
分享、在看与点赞,至少我要拥有一个吧
点森科技 - 科技资讯_数码产品_互联网观察_智能硬件
