4. 校验码与完整性:LRC、CRC、Checksum、MAC
各位同学,咱们今天聊一个很实在的话题——校验码。
说白了,就是怎么保证你收到的数据,跟发送方发出来的数据是同一个东西。别小看这个问题,我在金融系统里见过太多因为校验没做好,导致资金对不上的惨案了。
4.1 为什么需要校验码?
你想想看,数据在网络上传输,就像快递在路上跑。可能遇到信号干扰、路由器缓存溢出、甚至黑客篡改。如果没有校验机制,你收到一笔100万的转账,实际到账可能只有10万——这谁受得了?
校验码的核心作用就两个:
- 检测错误:发现数据在传输过程中是否被破坏
- 验证完整性:确认数据没有被篡改或丢失
我个人习惯把校验码分成两类:一类是防随机错误的,比如LRC、CRC、Checksum;另一类是防恶意篡改的,比如MAC。这两者的设计思路完全不同,咱们一个一个说。
4.2 LRC纵向冗余校验
LRC是最简单的一种校验方式。它的做法很粗暴:把所有字节按位异或(XOR),得到一个校验字节。
举个例子:
数据:0x31 0x32 0x33 0x34
LRC = 0x31 XOR 0x32 XOR 0x33 XOR 0x34 = 0x04
接收方收到数据后,重新计算一遍LRC,跟发送方带过来的LRC对比。如果一致,说明数据没问题。
LRC的优点就是快,计算量极小。适合用在资源受限的嵌入式设备上。但金融系统里,我基本不用它——太容易漏检了。
4.3 CRC循环冗余校验
CRC就比LRC靠谱多了。它的原理是把数据看作一个多项式,然后用一个生成多项式去除,余数就是CRC校验码。
嗯,这里要注意:CRC不是简单的异或,它背后有严谨的数学理论支撑。不同的生成多项式,检错能力天差地别。
| CRC类型 | 生成多项式 | 校验码长度 | 典型应用 |
|---|---|---|---|
| CRC-8 | 0x07 | 8位 | 传感器数据 |
| CRC-16 | 0x8005 | 16位 | Modbus协议 |
| CRC-32 | 0x04C11DB7 | 32位 | 以太网、ZIP文件 |
| CRC-64 | 0x42F0E1EBA9EA3693 | 64位 | 大型文件校验 |
我曾经在一个金融报文交换系统里,遇到过CRC-16碰撞导致报文误判的情况。后来全部升级成CRC-32,再没出过问题。所以我的建议是:金融场景至少用CRC-32,别省那点计算资源。
4.4 Checksum校验和
Checksum是另一种常见的校验方式。它把数据按16位或32位分组,然后求和,取反码或补码作为校验值。
最经典的例子是IP协议头部的Checksum:
// 计算IP头部Checksum的伪代码
uint16_t checksum = 0;
for (int i = 0; i < header_len; i += 2) {
checksum += header[i] << 8 | header[i+1];
}
checksum = ~checksum; // 取反码
Checksum的计算比CRC简单,但检错能力也弱一些。它最大的问题是:如果数据中两个16位字同时出错,且错误量相互抵消,Checksum就检测不出来。
4.5 MAC消息认证码
前面说的LRC、CRC、Checksum,都只能防随机错误。如果有人恶意篡改数据,这些校验码形同虚设——因为攻击者可以重新计算校验码。
MAC就不一样了。它引入了一个密钥,只有知道密钥的人才能计算出正确的MAC值。这样既能防随机错误,又能防篡改。
常见的MAC算法有:
- HMAC:基于哈希函数,比如HMAC-SHA256
- CMAC:基于分组密码,比如AES-CMAC
- Poly1305:基于多项式运算,速度极快
举个例子,HMAC的计算过程:
HMAC(K, M) = H((K' XOR opad) || H((K' XOR ipad) || M))
其中:
K 是密钥
M 是消息
H 是哈希函数
opad、ipad 是固定的填充常量
我在设计一个跨境支付系统时,报文完整性校验就用的HMAC-SHA256。密钥通过硬件安全模块(HSM)管理,每次会话动态生成。这样即使报文被截获,攻击者也无法伪造合法的MAC。
4.6 四种校验码的对比
我把这四种校验码放在一起对比一下,方便你选择:
| 特性 | LRC | CRC | Checksum | MAC |
|---|---|---|---|---|
| 检错能力 | 弱 | 强 | 中等 | 极强 |
| 防篡改 | 否 | 否 | 否 | 是 |
| 计算速度 | 极快 | 快 | 快 | 较慢 |
| 密钥需求 | 无 | 无 | 无 | 有 |
| 典型场景 | 简单串口 | 网络协议 | 协议头部 | 金融报文 |
4.7 知识体系图
下面这张图展示了本章的知识结构,帮你理清思路:
4.8 避坑指南
最后,分享几个我踩过的坑:
- 别混用大小端:CRC和Checksum的计算结果跟字节序有关。我曾经因为大小端不一致,调试了整整两天。
- MAC密钥要定期更换:密钥长期不变,被破解的风险会指数级上升。建议每次会话或每天更换一次。
- 不要只用一种校验:在金融系统里,我通常同时使用CRC和MAC。CRC用来快速过滤随机错误,MAC用来防篡改。双重保险。
好了,关于校验码和完整性,今天就聊到这里。记住一句话:没有校验的数据,就像没有锁的门。在金融系统里,这道门必须锁好。