CRC 校验值计算

一次算出 CRC-8、CRC-16/CCITT-FALSE、CRC-16/MODBUS 和 CRC-32,输入可以是文本或十六进制字节。

输入文本后自动计算

CRC 在算什么

把要发送的数据看成一个很长的大整数,再约定一个生成多项式,用模 2 除法(加减都是异或,不产生进位)去除它,得到的余数就是 CRC 校验值。发送方在数据末尾附上这个余数,接收方用同样的参数重算一遍并比对,就能发现传输过程中有没有比特被翻转。它本质上是一段带余除法,硬件上可以用移位寄存器和几个异或门实现,开销很小。

同一个「CRC-16」其实是一族算法,差别在五项参数:多项式、初始值(init)、输入字节是否按位反转(refin)、输出寄存器是否反转(refout)、最后是否再异或一个值(xorout)。参数不同就是两种互不兼容的 CRC。例如 CRC-16/CCITT-FALSE 用多项式 0x1021、初始值 0xFFFF、不反转;CRC-16/MODBUS 用多项式 0x8005、初始值 0xFFFF、输入输出都反转,所以两者对同一段数据的结果完全不同。

CRC 和 MD5、SHA 这类密码学哈希是两回事。CRC 的输出很短(8、16、32 位),速度快,目标是发现传输中的随机比特错误:单比特、双比特、奇数个错误和一定长度内的突发错误都能被检出。哈希的输出长(128 到 512 位),并且是单向、雪崩的,改一个比特结果面目全非,用来做完整性校验和防篡改。CRC 是线性的,很容易被人为构造出让校验值不变的数据,所以它只防意外、不防攻击。

实际使用里最容易踩的坑是字节顺序。协议文档给的 CRC-16 值通常是数值,但写进报文时要看约定用大端还是小端;Modbus RTU 就是把 16 位校验值的低字节放在前面传输,所以抓包时看到的两字节和计算出的数值是反的。另外 CRC-16 有 CCITT、XMODEM、IBM、DNP 一大堆变体,参数表对不上时结果自然对不上,先用「123456789」这串标准输入分别验证实现和参数再排查更省事。