我使用这个简单的函数来计算给定文件的CRC校验和:
long i, j = 0;
int k = 0;
uint crc = 0xFFFFFFFF;
FileInfo file_info = new FileInfo(file);
byte[] file_buffer = new byte[32768];
FileStream file_stream = new FileStream(@file, FileMode.Open);
while ((i = file_stream.Read(file_buffer, 0, file_buffer.Count())) > 0)
{
for (j = 0; j < i; j++)
{
uint before = crc;
k = (int)((crc ^ file_buffer[j]) & 0x000000FFL);
uint after = (uint)((crc >> 8) & 0x00FFFFFFL) ^ crc32_table[k];
crc = after;
uint test = (uint)((crc << 8) & 0x00FFFFFFL) …Run Code Online (Sandbox Code Playgroud) 我正在尝试逐字节计算以太网数据包的帧校验序列(FCS).多项式是0x104C11DB7.我确实遵循了这里所见的XOR-SHIFT算法http://en.wikipedia.org/wiki/Cyclic_redundancy_check或http://www.woodmann.com/fravia/crctut1.htm
假设假定具有CRC的信息仅为一个字节.假设它是0x03.
步骤:向右打32位
0x0300000000
将多项式和左侧的数据与它们的第一个非零和xor对齐
0x300000000 xor 0x209823B6E = 0x109823b6e
取余数对齐和xor
0x109823b6e xor 0x104C11DB7 = 0x0d4326d9
由于没有剩下的位,0x03的CRC32应该是 0x0d4326d9
不幸的是,所有的软件实现都告诉我我错了,但是我做错了什么或者他们做了什么不同的事情?
Python告诉我:
"0x%08x" % binascii.crc32(chr(0x03))
0x4b0bbe37
Run Code Online (Sandbox Code Playgroud)
这里的在线工具http://www.lammertbies.nl/comm/info/crc-calculation.html#intr获得了相同的结果.我的手计算与上述软件使用的算法有什么区别?
更新:
事实证明堆栈溢出已经存在类似的问题:
你在这里找到一个答案Python CRC-32的问题
虽然这不是很直观.如果您想要更正式地描述如何为以太网帧完成,您可以查看以太网标准文档802.3第3部分 - 第3.2.9章帧校验序列字段
让我们继续上面的例子:
反转邮件的位顺序.这代表了他们逐点进入接收器的方式.
0x03 因此是 0xC0
补充邮件的前32位.请注意,我们再次使用32位填充单个字节.
0xC000000000 xor 0xFFFFFFFF = 0x3FFFFFFF00
再次完成上面的Xor和shift方法.大约6步之后你得到:
0x13822f2d
然后补充上述比特序列.
0x13822f2d xor 0xFFFFFFFF = 0xec7dd0d2
请记住,我们颠倒了位顺序,以便在第一步中获得以太网线上的表示.现在我们必须扭转这一步,我们终于完成了我们的任务.
0x4b0bbe37
想出这种做法的人应该......
很多时候你真的想知道你收到的信息是正确的.为了达到这个目的,您可以收到包括FCS在内的收到的消息,并执行与上述相同的步骤1到5.结果应该是他们所谓的残留物.这是给定多项式的常数.在这种情况下它是0xC704DD7B.
正如mcdowella所提到的那样,你必须玩弄你的位,直到你做对了,这取决于你正在使用的应用程序.
在几个地方我读过crc32是加法的,因此:CRC(A xor B)= CRC(A)xor CRC(B).
我写的以下代码证实了上述陈述:
import zlib
def crc32(data):
return zlib.crc32(data) & 0xffffffff
print crc32(chr(ord("A") ^ ord("B")))
print crc32("A") ^ crc32("B")
Run Code Online (Sandbox Code Playgroud)
节目输出:
1259060791
2567524794
Run Code Online (Sandbox Code Playgroud)
有人能提供一个证明这个理论的正确代码,还是指出我失败的地方?
我正在尝试计算/验证压缩bzip2档案的CRC32校验和.
.magic:16 = 'BZ' signature/magic number
.version:8 = 'h' for Bzip2 ('H'uffman coding)
.hundred_k_blocksize:8 = '1'..'9' block-size 100 kB-900 kB
.compressed_magic:48 = 0x314159265359 (BCD (pi))
.crc:32 = checksum for this block
...
...
.eos_magic:48 = 0x177245385090 (BCD sqrt(pi))
.crc:32 = checksum for whole stream
.padding:0..7 = align to whole byte
Run Code Online (Sandbox Code Playgroud)
http://en.wikipedia.org/wiki/Bzip2
所以我知道CRC校验和在bz2文件中的位置,但我将如何验证它们.我应该用什么块binascii.crc32()来获得两个CRC?我已经尝试逐字节计算各种块的CRC,但还没有设法得到匹配.
谢谢.我将研究bzip2源bz2代码和Python库代码,以便找到一些东西,特别是在decompress()方法中.
更新1:
就我所见,块标题由以下标记标识.但是小的bz2文件不包含ENDMARK文件.(感谢adw,我们发现应该查找ENDMARK的位移值,因为压缩数据没有填充到字节.)
#define BLOCK_HEADER_HI 0x00003141UL
#define BLOCK_HEADER_LO 0x59265359UL
#define BLOCK_ENDMARK_HI 0x00001772UL
#define BLOCK_ENDMARK_LO 0x45385090UL
Run Code Online (Sandbox Code Playgroud)
这是从bzlib2recover.c源,块似乎始终在第80位,就在CRC校验和之前,这应该从CRC计算中省略,因为一个人不能将它自己的CRC校准为相同的CRC(你得到我的观点) …
我从这个答案中获取了一个Python片段(稍加修改)来计算以太网crc32帧检查序列:
msg = '00'
data = bytes.fromhex(msg)
print(data)
print(msg)
crc = zlib.crc32(data)&0xFFFFFFFF
for i in range(4):
b = (crc >> (8*i)) & 0xFF
print('{:02X}'.format(b))
Run Code Online (Sandbox Code Playgroud)
00对于它输出的消息,这是此答案8D EF 02 D2的位反转解决方案。到目前为止,一切都很好。
现在这里说,
对包括 CRC 码的接收帧数据运行 CRC 算法将始终导致无错误接收数据的零值,因为 CRC 是数据除以多项式的余数。然而,这种技术可能无法检测错误,其中带有尾随零的数据也将导致相同的零余数。为了避免这种情况,发送方在将 FCS 附加到有效负载数据的末尾之前对其进行补充(每个位都取反)。这样,当数据正确接收时,算法结果将始终是 0xC704DD7B 的 CRC32 残差。
但如果我输入00 8D EF 02 D2计算器,结果是1C DF 44 21,而不是所说的余数。我还尝试了其他组合,因为通常必须反转字节中的位或其他什么(我实际上对所有这些反转的东西感到困惑,但我希望,尝试几种可能性后的良好结果将引导我走向正确的反转),但没有任何成功:
00 D8 FE 20 2D -> 66 40 C3 4A
00 D2 02 EF 8D -> DF 42 14 …Run Code Online (Sandbox Code Playgroud)