我需要尝试验证CRC-16值的帮助(也需要有关CRC-32值的帮助)。我试图坐下,了解CRC的工作原理,但我正在空白。
[我的第一个问题是,当尝试使用在线计算器将消息[BD001325E032091B94C412AC
]计算为CRC16 = 12AC时。文档指出最后两个八位位组是CRC16值,因此我在站点BD001325E032091B94C4
中输入“ http://www.lammertbies.nl/comm/info/crc-calculation.html”,并接收5A90作为结果,而不是12AC。
有人知道为什么这些值不一样,以及在哪里可以找到有关如何计算CRC16和CRC32值的代码(我打算稍后再学习如何执行此操作,但现在不允许这样做)?
一些其他消息如下:
16000040FFFFFFFF00015FCB
3C00003144010405E57022C7
BA00001144010101B970F0ED
3900010101390401B3049FF1
09900C800000000000008CF3
8590000000000000000035F7
00900259025902590259EBC9
0200002B00080191014BF5A2
BB0000BEE0014401B970E51E
3D000322D0320A2510A263A0
2C0001440000D60000D65E54
-编辑-
我提供了更多信息。我参考的文档是TIA-102.BAAA-A(来自TIA标准)。以下是文档说明的内容(试图尽可能避免侵犯版权):
数据包中的最后一个块包含用户信息和/或填充八位字节,然后进行4字节CRC奇偶校验。这称为包CRC。
数据包CRC是一个4字节的循环冗余校验,编码在所有数据上中间块中包含的八位字节和用户信息的八位字节最后一块。具体计算如下。
让k为用户信息和填充包的填充位的总数CRC将被计算。将k个消息位视为a的系数k–1的多项式M(x),与第零个消息的MSB相关联具有x ^ k–1的八位位组和具有x ^ 0的最后一个消息八位位组的LSB。定义生成多项式GM(x)和反多项式IM(x)。
GM(x)= x ^ 32 + x ^ 26 + x ^ 23 + x ^ 22 + x ^ 16 + x ^ 12 + x ^ 11 + x ^ 10 + x ^ 8 + x ^ 7 + x ^ 5 +x ^ 4 + x ^ 2 + x + 1
IM(x)= x ^ 31 + x ^ 30 + x ^ 29 + ... + x ^ 2 + x +1
然后根据以下公式计算数据包CRC多项式FM(x)。
FM(x)=(x ^ 32 M(x)mod GM(x))+ IM(x)模2,即在GF(2)中]
FM(x)的系数位于第零位的MSB的CRC字段中CRC的八位位组与x ^ 31和CRC的第三位八位组的LSB对应对应于x ^ 0。
在上面的引用中,我已经输入^
来显示幂,因为引用时的格式并不相同。我不确定会发生什么,但这有帮助吗?
阅读Ross Williams tutorial on CRCs以更好地理解CRC,定义特定CRC的内容及其实现。
reveng website具有出色的已知CRC目录,并且具有每个测试字符串的CRC(九个字节:ASCII / UTF-8中的“ 123456789”)。请注意,这里定义了22个不同的16位CRC。
同一站点上的reveng软件可用于对多项式进行逆向工程,初始化,后处理和位逆向,如您对16位CRC所提供的几个示例。 (因此,名称为“ reveng”。)我遍历了您的数据并得到:
./reveng -w 16 -s 16000040FFFFFFFF00015FCB 3C00003144010405E57022C7 BA00001144010101B970F0ED 3900010101390401B3049FF1 09900C800000000000008CF3 8590000000000000000035F7 00900259025902590259EBC9 0200002B00080191014BF5A2 BB0000BEE0014401B970E51E 3D000322D0320A2510A263A0 2C0001440000D60000D65E54
width=16 poly=0x1021 init=0xc921 refin=false refout=false xorout=0x0000 check=0x2fcf name=(none)
如“(none)”所示,16位CRC并不是reveng列出的22位CRC中的任何一个,尽管它类似于其中的几个,仅在初始化方面有所不同。
您提供的附加信息适用于reveng目录中的32位CRC编码,即CRC-32或CRC-32 / BZIP,具体取决于这些位是否反转。
我有一个从Internet上找到的C ++转换而来的类,它使用long来计算CRC32。它符合标准,是PKZIP,WinZip和以太网的一种用途。要测试它,请使用Winzip并压缩文件,然后使用此类计算相同的文件,它应返回相同的CRC。它对我有用。
public class CRC32
{
private int[] iTable;
public CRC32() {
this.iTable = new int[256];
Init();
}
/**
* Initialize the iTable aplying the polynomial used by PKZIP, WINZIP and Ethernet.
*/
private void Init()
{
// 0x04C11DB7 is the official polynomial used by PKZip, WinZip and Ethernet.
int iPolynomial = 0x04C11DB7;
// 256 values representing ASCII character codes.
for (int iAscii = 0; iAscii <= 0xFF; iAscii++)
{
this.iTable[iAscii] = this.Reflect(iAscii, (byte) 8) << 24;
for (int i = 0; i <= 7; i++)
{
if ((this.iTable[iAscii] & 0x80000000L) == 0) this.iTable[iAscii] = (this.iTable[iAscii] << 1) ^ 0;
else this.iTable[iAscii] = (this.iTable[iAscii] << 1) ^ iPolynomial;
}
this.iTable[iAscii] = this.Reflect(this.iTable[iAscii], (byte) 32);
}
}
/**
* Reflection is a requirement for the official CRC-32 standard. Note that you can create CRC without it,
* but it won't conform to the standard.
*
* @param iReflect
* value to apply the reflection
* @param iValue
* @return the calculated value
*/
private int Reflect(int iReflect, int iValue)
{
int iReturned = 0;
// Swap bit 0 for bit 7, bit 1 For bit 6, etc....
for (int i = 1; i < (iValue + 1); i++)
{
if ((iReflect & 1) != 0)
{
iReturned |= (1 << (iValue - i));
}
iReflect >>= 1;
}
return iReturned;
}
/**
* PartialCRC caculates the CRC32 by looping through each byte in sData
*
* @param lCRC
* the variable to hold the CRC. It must have been initialize.
* <p>
* See fullCRC for an example
* </p>
* @param sData
* array of byte to calculate the CRC
* @param iDataLength
* the length of the data
* @return the new caculated CRC
*/
public long CalculateCRC(long lCRC, byte[] sData, int iDataLength)
{
for (int i = 0; i < iDataLength; i++)
{
lCRC = (lCRC >> 8) ^ (long) (this.iTable[(int) (lCRC & 0xFF) ^ (int) (sData[i] & 0xff)] & 0xffffffffL);
}
return lCRC;
}
/**
* Caculates the CRC32 for the given Data
*
* @param sData
* the data to calculate the CRC
* @param iDataLength
* then length of the data
* @return the calculated CRC32
*/
public long FullCRC(byte[] sData, int iDataLength)
{
long lCRC = 0xffffffffL;
lCRC = this.CalculateCRC(lCRC, sData, iDataLength);
return (lCRC /*& 0xffffffffL)*/^ 0xffffffffL);
}
/**
* Calculates the CRC32 of a file
*
* @param sFileName
* The complete file path
* @param context
* The context to open the files.
* @return the calculated CRC32 or -1 if an error occurs (file not found).
*/
long FileCRC(String sFileName, Context context)
{
long iOutCRC = 0xffffffffL; // Initilaize the CRC.
int iBytesRead = 0;
int buffSize = 32 * 1024;
FileInputStream isFile = null;
try
{
byte[] data = new byte[buffSize]; // buffer de 32Kb
isFile = context.openFileInput(sFileName);
try
{
while ((iBytesRead = isFile.read(data, 0, buffSize)) > 0)
{
iOutCRC = this.CalculateCRC(iOutCRC, data, iBytesRead);
}
return (iOutCRC ^ 0xffffffffL); // Finalize the CRC.
}
catch (Exception e)
{
// Error reading file
}
finally
{
isFile.close();
}
}
catch (Exception e)
{
// file not found
}
return -1l;
}
}
CRC计算有很多参数:多项式,初始值,最终XOR ...有关详细信息,请参见Wikipedia。您的CRC似乎不适合您所使用的站点,但是您可以尝试从文档中找到正确的参数,并使用其他计算器,例如this one(尽管我担心它不支持十六进制输入)。
要记住的一件事是,CRC-16通常是对应该校验和的数据加上两个零字节进行计算的,例如您可能正在寻找CRC16
函数,其中CRC16(BD001325E032091B94C40000) == 12AC
。以此方式计算出校验和后,附加校验和的数据的CRC将计算为0,这使得校验更加容易,例如CRC16(BD001325E032091B94C412AC) == 0000