如何为CVN与CALID计算CRC32调和因子及统一CRC值的算法
CVN/CALID CRC32/CRC16调和因子计算问题
需求背景
需要为CVN(校准车辆网络标识)和CALID计算CRC32及CRC16调和因子,实现以下目标:
- 两个结构体包含相同的10个参数定义,但参数值不同
- 给每个结构体各自添加一个校准因子后,两者的CRC32校验和完全一致
- 未知结构体的具体参数值
现有CRC32相关代码未能实现预期效果,需排查代码遗漏点,并明确如何获取偏移量与调和因子以确保CRC结果一致。
现有CRC32代码
#include <stdio.h> #define CRCPOLY 0xEDB88320 #define CRCINV 0x5B358FD3 // inverse poly of (x ^N) mod CRCPOLY #define INITXOR 0xFFFFFFFF #define FINALXOR 0xFFFFFFFF void make_crc_revtable ( unsigned int * crc_revtable ) ; int crc32_bitoriented ( unsigned char * buffer , int length ); unsigned int crc_table[256]; unsigned char buffer[]= { 0x0, 0x1, 0x2, 0x3, 0x4,0x5, 0x6, 0x7, 0x8, 0x9,0xA, 0xB, 0xC, 0xD, 0xE,0xF, 0x0, 0x1, 0x2, 0x3,0x0, 0x0, 0x0, 0x0, 0x0 }; unsigned int crc_revtable [256]; unsigned int tcrcreg ; unsigned int CRC_32 ; unsigned int fix_pos = 21; unsigned int length = 256; void fix_crc_pos ( unsigned char * buffer ,int length ,unsigned int tcrcreg ,int fix_pos ,unsigned int * crc_table ,unsigned int * crc_revtable ) { int i; // make sure fix_pos is within 0..( length -1) fix_pos = ((fix_pos % length) + length) % length; // calculate crc register at position fix_pos ; this is essentially crc32 () unsigned int crcreg = INITXOR ; for (i = 0; i < fix_pos ; ++i) { crcreg = (crcreg >> 8) ^ crc_table[((crcreg ^ buffer [i]) & 0xFF)]; } // inject crcreg as content for (i = 0; i < 4; ++i) { buffer[fix_pos + i] = ((crcreg >> i * 8) & 0xFF); } // calculate crc backwards to fix_pos , beginning at the end tcrcreg = (tcrcreg ^FINALXOR) ; for (i = length - 1; i >= fix_pos ; --i) { tcrcreg = ((tcrcreg << 8) ^ (crc_revtable[tcrcreg >> 3*8] ^ buffer[i])); } // inject new content for (i = 0; i < 4; ++i) { buffer[fix_pos + i] = (tcrcreg >> i * 8) & 0xFF; } } void make_crc_revtable ( unsigned int *crc_revtable ) { unsigned int c; int n , k; for (n = 0; n < 256; n ++) { c = n << 3*8; for (k = 0; k < 8; k ++) { if (( c & 0x80000000 ) != 0) { c = ((( c ^ CRCPOLY ) << 1) | 1); } else { c = (c <<1); } } crc_revtable [n] = c; } } void make_crc_table ( unsigned int * table ) { unsigned int c; int n , k; for (n = 0; n < 256; n ++) { c = n ; for (k = 0; k < 8; k ++) { if (( c & 1) != 0) { c = CRCPOLY ^ ( c >> 1); } else { c = c >> 1; } } table [n] = c; } } int crc32_bitoriented ( unsigned char * buffer , int length ) { int i , j; unsigned int crcreg = INITXOR ; for (j = 0; j < length ; ++ j ) { unsigned char b = buffer [ j ]; for (i = 0; i < 8; ++ i) { if (( crcreg ^ b ) & 1) { crcreg = ( crcreg >> 1) ^ CRCPOLY ; } else { crcreg >>= 1; } b >>= 1; } } return crcreg ^ FINALXOR ; } int main() { length = sizeof(buffer); CRC_32 = crc32_bitoriented( buffer , length ); printf("\nCRC_32 :%x ",CRC_32); make_crc_table(&crc_table[0]); make_crc_revtable(&crc_revtable[0]); fix_crc_pos(buffer, length, tcrcreg, fix_pos, &crc_table[0], &crc_revtable[0]); printf("\nModified Buffer:\n"); for(int i=1;i<=length ;i++) { printf("0x%x ",buffer[i-1]); if(0== (i%5)) { printf("\n"); } }printf("\n"); CRC_32 = crc32_bitoriented( buffer , length ); printf("\nFinal CRC_32 :%x ",CRC_32); return 0; }
未修改的Buffer数据
0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xA 0xB 0xC 0xD 0xE 0xF 0x0 0x1 0x2 0x3 0x0 0x0 0x0 0x0 0x0
代码问题排查与解决方案
核心问题点
- 目标CRC未初始化:
fix_crc_pos函数的tcrcreg参数未赋值,必须明确指定最终要得到的目标CRC值(比如0x00000000或任意固定值),否则函数无法计算出正确的调和因子。 - 反向CRC计算逻辑错误:当前反向CRC的移位和查表逻辑与正向CRC不匹配,导致无法正确逆向推导调和因子。
- 调和因子位置越界风险:当前
fix_pos=21,Buffer总长度为25,fix_pos+3=24刚好是最后一个索引,但如果Buffer长度变化,极易出现越界,需确保预留连续4字节的调和因子空间,即fix_pos + 3 < length。 - 正向CRC与表驱动计算一致性问题:
crc32_bitoriented是比特级计算,而fix_crc_pos中用的是字节表驱动计算,需先验证两者结果是否完全一致,确保CRC参数(初始值、多项式、最终异或)完全统一。
正确实现步骤
1. 明确目标CRC值
在main函数中给tcrcreg赋值为你想要的固定CRC结果,比如:
unsigned int tcrcreg = 0x00000000; // 指定目标CRC值
2. 修正反向CRC计算逻辑
反向CRC需要对应正向CRC的逆运算,正确的反向处理逻辑如下(替换fix_crc_pos中的反向循环):
tcrcreg = tcrcreg ^ FINALXOR; // 先处理调和因子之后的所有字节 for (i = length - 1; i >= fix_pos + 4; --i) { // 反向CRC运算:从后往前逐个字节逆推 tcrcreg = (tcrcreg >> 8) ^ crc_revtable[tcrcreg & 0xFF]; tcrcreg ^= (unsigned int)buffer[i] << 24; }
同时需确保crc_revtable的生成逻辑正确,反向表对应正向CRC的逆多项式运算。
3. 推导调和因子的核心逻辑
利用CRC的线性性质,调和因子的计算需满足:
- 设
C_pre为计算到调和因子位置前的CRC值 - 设
C_post为从目标CRC反向推导到调和因子起始位置的逆CRC值 - 调和因子
X需满足:CRC(C_pre, X) = C_post - 通过正向CRC的逆运算可直接解出
X,即X = CRC_INV(C_pre, C_post)
4. CRC16适配方案
针对CRC16,只需调整以下几点:
- 替换多项式(比如常用的
0x8005)、初始值和最终异或值 - 将调和因子长度改为2字节
- 生成对应的正向/反向CRC16表
- 调整所有涉及CRC长度的计算(比如从4字节改为2字节)
内容的提问来源于stack exchange,提问作者Mehul
相关产品推荐
相关产品推荐

