数据校验与CRC"

admin 2026-10-17 07:39:57 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

数据校验与CRC

内存泄漏

2026年8月22日 00:19
河南

在小说阅读器读本章

去阅读

以下文章来源于嵌入式软件客栈
,作者Psyducking

嵌入式软件客栈
.

嵌入式开发加速器,作为嵌入式、Linux、物联网、C/C++等技术分享平台,提供更多实战指南,让嵌入式技术应用更简单高效。欢迎关注,一起交流探索无限可能!

校验不是可选项,是嵌入式通信的基本防线。

为什么和校验不够

最朴素的办法是把所有字节相加,取低字节附在帧尾。实现简单,却挡不住一类常见错误:两个字节同时出错且增减相互抵消,或者数据整体移位。

// 和校验:易实现,但漏检率高
uint8_t checksum(uint8_t *p, int n)
{
    uint8_t s = 0;
    for (int i = 0; i < n; i++) s += p[i];
    return s;
}

和校验只覆盖\"加法\"维度,对突发错误(burst error,线路干扰常连续错几位)几乎无能为力。工业通信(Modbus、CAN、以太网)普遍选择 CRC,因为它对连续多位错误有极强的检出能力。

CRC 到底在算什么

CRC 不是\"循环冗余\"这个名字体现的数学玄学,本质是把数据当作一个很大的二进制多项式,除以一个固定的生成多项式,取余数。余数就是校验值。接收方用同样的多项式除一遍,余数不为 0 即说明传输有误。

生成多项式决定了检错能力。Modbus RTU 用 CRC-16/MODBUS(多项式 0x8005,初始值 0xFFFF,输入反转、输出反转、异或输出 0x0000);CAN 用 CRC-15;以太网用 CRC-32。多项式不同,同一段数据算出的 CRC 完全不同——两端必须用同一个参数定义,否则永远对不上。

参数陷阱

当照搬一段 CRC-16 代码,和对方设备对不上,排查半天发现是参数没对齐。CRC 有六个关键参数,缺一不可:

  • • Width:校验位宽(16/32)
  • • Poly:生成多项式
  • • Init:寄存器初始值
  • • RefIn:每个输入字节是否按位反转
  • • RefOut:输出余数是否整体反转
  • • XorOut:最终异或值
// Modbus RTU 的 CRC-16,参数缺一不可
uint16_t crc16_modbus(uint8_t *data, int len)
{
    uint16_t crc = 0xFFFF;            // Init
    for (int i = 0; i < len; i++) {
        crc ^= data[i];               // 这里隐含了 RefIn=true(逐字节处理时等价)
        for (int b = 0; b < 8; b++) {
            if (crc & 0x0001)
                crc = (crc >> 1) ^ 0xA001;  // 0xA001 是 0x8005 的反转形式
            else
                crc >>= 1;
        }
    }
    return crc;                        // XorOut=0x0000,无需再异或
}

注意 0xA001 不是随便写的,它是多项式 0x8005 按位反转后的结果——这一项就对应 RefIn/RefOut 都为 true 的约定。如果对方设备 RefOut 为 false,你就该用 0x8005 直接算,结果会不同。对接任何 CRC 设备,先把这六个参数和白皮书逐一对齐,不要凭\"都是 CRC-16\"就假设一致。

字节

算出的 16 位 CRC 在帧尾有两个字节,先放高字节还是低字节?Modbus 规定低字节在前(little-endian on the wire)。

// 发送:低字节在前
frame[tail]   = crc & 0xFF;        // 低字节
frame[tail+1] = (crc >> 8) & 0xFF; // 高字节

// 接收端校验:取出后按同样顺序重组再算
uint16_t rx_crc = frame[tail] | (frame[tail+1] << 8);
uint16_t calc   = crc16_modbus(frame, tail);
if (rx_crc != calc) { /* 帧错误,丢弃 */ }

字节序搞反是最常见的对接故障,现象是\"本地自算自校验 OK,和对方设备一通信就全错\"。先核对协议文档里 CRC 的传输顺序,再写收发代码。

用硬件 CRC 外设加速

软件逐位计算在大批量数据下很占 CPU。STM32 等 MCU 内置 CRC 外设,一条指令算完一个字,且是 CRC-32(以太网多项式)。

// 使能并配置硬件 CRC(以 STM32 HAL 为例)
__HAL_RCC_CRC_CLK_ENABLE();
hcrc.Instance = CRC;
HAL_CRC_Init(&hcrc);                 // 默认 CRC-32 0x04C11DB7

// 按 32 位字计算,注意数据需 4 字节对齐
uint32_t calc = HAL_CRC_Calculate(&hcrc, (uint32_t *)buf, len_words);

硬件 CRC 多固定为某一种参数(常是 CRC-32),和 Modbus 的 CRC-16 不是一回事,不能直接替代 Modbus 校验。它适合做固件完整性检查、Flash 数据校验这类场景;对接标准 Modbus 仍用上面软件实现的 CRC-16/MODBUS。别为了\"用硬件\"硬套不匹配的多项式。

校验在通信帧里的位置

否

是

应用数据

组帧: 地址+功能码+数据

计算 CRC 附帧尾

发送

接收 收齐一帧

用同参重算 CRC

一致?

丢弃/请求重传

提交上层

校验的边界要划在\"整帧有效载荷\"上,不能只覆盖数据段漏掉地址和功能码——否则从机地址被干扰成别的设备,校验却通过,会造成错误响应。CRC 计算范围必须和协议定义完全一致,包括帧头里的每个字段。


数据校验与CRC" 网络安全文章

数据校验与CRC"

本文解析嵌入式通信数据校验技术,指出和校验无法抵御突发错误,引入CRC多项式取余原理。文章揭示CRC对接三大陷阱:六项关键参数须与协议完全对齐;帧尾字节序错误极易导致联调失败;硬件CRC外设无法直接替代特定协议的CRC-16。建议确保CRC计算覆盖完整帧字段,防止篡改引发错误响应。
JADX接入AI:jadx-mcp极简教程" 网络安全文章

JADX接入AI:jadx-mcp极简教程"

本文介绍在JADX中安装jadx-ai-mcp插件并配置MCP服务,使AI能直接分析反编译代码。核心步骤包括下载JADX-GUI、安装插件、下载MCP服务脚本、配置MCP(推荐stdio模式),最后启动服务后AI即可调用。该教程为安全分析人员提供了将AI集成到逆向工作流的实用方法。
Web渗透实战:站点指纹、目录、接口信息收集" 网络安全文章

Web渗透实战:站点指纹、目录、接口信息收集"

本文是Web渗透测试信息收集的实战指南,聚焦站点指纹识别、目录扫描与接口信息收集。核心结论是信息收集决定渗透效率,需先摸清目标技术栈。关键发现包括指纹识别可获取CMS、中间件等特征,目录扫描能发现敏感路径,接口收集可挖掘隐藏API。可操作建议是结合工具(如Wappalyzer、WhatWeb、Dirsearch)与手动分析,交叉验证结果,并强调所有操作需在授权环境下进行。
评论:0   参与:  0