一、前言
很多场景下需要对系统中的文件进行校验,以此来判断该资源是否缺失。比如一些语言资源、图片资源甚至系统固件OTA时。以下将介绍常用的一些校验方法。有时候为了避免CRC碰撞,也会同时使用其他校验方式。
二、CRC校验
1. CRC基本概念
-
算法简介
循环冗余校验(Cyclic Redundancy Check,CRC)是一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种信道编码技术,主要用来检测或校验数据传输或者保存后可能出现的错误。它是利用除法及余数的原理来作错误侦测的。 -
参数模型
有时候同样的CRC多项式,调用不同的CRC计算函数,得到的结果却不一样。因为这里涉及到CRC的参数模型,计算一个正确的CRC校验值,需要知道用的参数模型是哪一种。
一个完整的CRC参数模型应该包含以下信息:WIDTH,POLY,INIT,REFIN,REFOUT,XOROUT。
- NAME:参数模型名称
- WIDTH:宽度,即生成的CRC数据位宽,如CRC-16,生成的CRC为16位
- POLY:十六进制多项式,省略最高位1,如二进制为1 0000 0111,省略最高位1,转换为十六进制为0x07
- INIT:CRC初始值,和WIDTH位宽一致
- REFIN:true或false,在进行计算前,原始数据是否翻转(高位变低位)。如原始数据:0x34 = 00110100,如果REFIN为true,翻转后的结果为00101100 = 0x2c。
- REFOUT:true或false,运算完成之后,得到的CRC值是否进行翻转。
- XOROUTL:计算结果与此参数进行异或运算后得到最终的CRC值,和WIDTH位宽一致。
如果通常只给一个多项式,其他没有说明,则默认:INIT = 0x00, REFIN = false,REFOUT = false,XOROUT = 0x00。
常见参数模型:
2. CRC计算
问题:原始数据:0x34,使用CRC-8/MAXIN参数模型,求CRC值。
根据参数模型,可以知道各个参数值是这样的:
- POLY = 0x31 = 0011 0001(最高位1已经省略)
- INIT = 0x00
- XOROUT = 0x00
- REFIN = TRUE
- REFOUT = TRUE
知道了以上参数,可以开始计算了:
- 原始数据 0x34 = 00110100, 多项式 0x31 = 1 00110001
- INIT = 0, 原始数据高8位和初始值进行异或运算保持不变
- REFIN = TRUE,需要先对原始数据进行翻转:00110100 > 00101100
- 把原始数据左移8位,即后面补8个0:00101100 00000000
- 把处理之后的数据和多项式进行模2除法,多项式1 00110001, 求得余数低8位:1111 1011
- 与XOROUT进行异或,1111 1011 xor 0000 0000 = 1111 1011
- 因为REFOUT为TRUE,对结果进行翻转得到最终的CRC-8值:1101 1111 = 0xDF
- 数据+CRC:0011 0100 1101 1111 = 34DF,相当于原始数据左移8位+余数
3. CRC校验
按照上面CRC计算的结果,最终的数据帧:0011 0100 1101 1111 = 34DF,前8位0011 0100是原始数据,后8位1101 1111 是 CRC结果。
接收端的校验有两种方式,一种是和CRC计算一样,在本地把接收到的数据和CRC分离,然后在本地对数据进行CRC运算,得到的CRC值和接收到的CRC进行比较,如果一致,说明数据接收正确,如果不一致,说明数据有错误。
另一种方法是把整个数据帧进行CRC运算,因为是数据帧相当于把原始数据左移8位,然后加上余数,如果直接对整个数据帧进行CRC运算(除以多项式),那么余数应该为0,如果不为0说明数据出错。而且,不同位出错,余数也不同,可以证明,余数与出错位数的对应关系只与CRC参数模型有关,而与原始数据无关。
三、 CRC的C语言库
这是一个基于C语言的CRC计算库,里面包含了常用的21个CRC参数模型计算函数,可以直接使用,只有crcLib.c和crcLib.h两个文件。
另外推荐一个在线CRC计算工具。
四、总结
CRC校验并不能100%的检查出数据的错误,非常低的概率会出现CRC校验正确但数据中有错误位的情况。这和CRC的位数,多项式的选择等等有很大的关系,所以在实际使用中尽量选择标准CRC参数模型,这些多项式参数都是经过理论计算得出的,可以提高CRC的检错能力。
有些场景可能会出现CRC碰撞的问题,可以使用累计和和异或和一起校验。