如何计算CRC32校验和?

时间:2010-04-06 19:44:51

标签: c checksum crc32

也许我只是没有看到它,但CRC32看起来要么不必要地复杂化,要么在网上找不到任何地方。

我理解它是来自消息值的非基于进位的算术除法的余数除以(生成器)多项式,但它的实际实现逃脱了我。

我读过A Painless Guide To CRC Error Detection Algorithms,我必须说这不是无痛的。它完全超越了理论,但作者从未得到过简单的“就是这样”。他确实说过标准CRC32算法的参数是什么,但是他忽略了如何清楚地列出它。

获得我的部分是当他说“这就是它”然后补充说,“顺便说一句,它可以被逆转或以不同的初始条件开始”,并没有给出明确的答案给出他刚刚添加的所有更改,计算CRC32校验和的最终方法。

  • 是否有更简单的解释CRC32的计算方法?

我试图在C中编写表格的形式:

for (i = 0; i < 256; i++)
{
    temp = i;

    for (j = 0; j < 8; j++)
    {
        if (temp & 1)
        {
            temp >>= 1;
            temp ^= 0xEDB88320;
        }
        else {temp >>= 1;}
    }
    testcrc[i] = temp;
}

但这似乎产生了与我在互联网上其他地方找到的值不一致的值。我可以使用我在网上找到的值,但我想了解它们是如何创建的。

任何帮助清除这些令人难以置信的令人困惑的数字都会被非常赞赏。

7 个答案:

答案 0 :(得分:91)

CRC32的多项式是:

  

0x 04 C1 1D B7

     

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

其中有二进制文件:

  

100 1100 0001 0001 1101 1011 0111

随意计算1和0,但是你会发现它们与多项式匹配,其中1是位0(或第一位)而x是位1 (或第二位)。

为什么这个多项式?因为需要标准的给定多项式,并且标准由IEEE 802.3设置。此外,很难找到有效检测不同位错误的多项式。

您可以将CRC-32视为一系列&#34;二进制算术,无需执行&#34;或基本上&#34; XOR和移位操作&#34;。这在技术上称为多项式算术。

为了更好地理解它,请考虑这种乘法:

(x^3 + x^2 + x^0)(x^3 + x^1 + x^0)
= (x^6 + x^4 + x^3
 + x^5 + x^3 + x^2
 + x^3 + x^1 + x^0)
= x^6 + x^5 + x^4 + 3*x^3 + x^2 + x^1 + x^0

如果我们假设x是基数2,那么我们得到:

x^7 + x^3 + x^2 + x^1 + x^0

为什么呢?因为3x ^ 3是11x ^ 11(但我们只需要1或0个前数字)所以我们继续:

=1x^110 + 1x^101 + 1x^100          + 11x^11 + 1x^10 + 1x^1 + x^0
=1x^110 + 1x^101 + 1x^100 + 1x^100 + 1x^11 + 1x^10 + 1x^1 + x^0
=1x^110 + 1x^101 + 1x^101          + 1x^11 + 1x^10 + 1x^1 + x^0
=1x^110 + 1x^110                   + 1x^11 + 1x^10 + 1x^1 + x^0
=1x^111                            + 1x^11 + 1x^10 + 1x^1 + x^0

但是数学家改变了规则,因此它是mod 2.所以基本上任何二进制多项式mod 2只是在没有进位或XOR的情况下加法。所以我们原来的等式看起来像:

=( 1x^110 + 1x^101 + 1x^100 + 11x^11 + 1x^10 + 1x^1 + x^0 ) MOD 2
=( 1x^110 + 1x^101 + 1x^100 +  1x^11 + 1x^10 + 1x^1 + x^0 )
= x^6 + x^5 + x^4 + 3*x^3 + x^2 + x^1 + x^0 (or that original number we had)

我知道这是一种信仰的飞跃,但这超出了我作为一线程序员的能力。如果你是一名核心的CS学生或工程师,我会挑战打破这种局面。每个人都将从这种分析中受益。

所以要找出一个完整的例子:

   Original message                : 1101011011
   Polynomial of (W)idth 4         :      10011
   Message after appending W zeros : 11010110110000

现在我们使用CRC算法将增强的消息除以Poly。这与以前的划分相同:

            1100001010 = Quotient (nobody cares about the quotient)
       _______________
10011 ) 11010110110000 = Augmented message (1101011011 + 0000)
=Poly   10011,,.,,....
        -----,,.,,....
         10011,.,,....
         10011,.,,....
         -----,.,,....
          00001.,,....
          00000.,,....
          -----.,,....
           00010,,....
           00000,,....
           -----,,....
            00101,....
            00000,....
            -----,....
             01011....
             00000....
             -----....
              10110...
              10011...
              -----...
               01010..
               00000..
               -----..
                10100.
                10011.
                -----.
                 01110
                 00000
                 -----
                  1110 = Remainder = THE CHECKSUM!!!!

除法产生一个商,我们扔掉它,余数,即计算的校验和。这结束了计算。通常,校验和随后附加到消息并传输结果。在这种情况下,传输将是:11010110111110。

仅使用32位数作为除数,并使用整个流作为被除数。丢掉商并保留其余部分。在邮件结尾处填写余数并且您有CRC32。

平均评论:

         QUOTIENT
        ----------
DIVISOR ) DIVIDEND
                 = REMAINDER
  1. 取前32位。
  2. 转移位
  3. 如果32位小于DIVISOR,请转到步骤2.
  4. DIVISOR的XOR 32位。转到第2步。
  5. (请注意,流必须可以被32位分割,或者它应该被填充。例如,必须填充8位ANSI流。同样在流的末尾,分割被暂停。)

答案 1 :(得分:9)

CRC非常简单;您将多项式表示为位和数据,并将多项式除以数据(或者将数据表示为多项式并执行相同的操作)。余数在0和多项式之间是CRC。您的代码有点难以理解,部分原因是它不完整:未声明temp和testcrc,因此不清楚索引的内容以及通过算法运行的数据量。

理解CRC的方法是尝试使用短数据(16位左右)和短多项式(4位)来计算一些数据。如果你以这种方式练习,你会真正理解你如何编写它。

如果您经常这样做,CRC在软件中的计算速度非常慢。硬件计算效率更高,只需几个门。

答案 2 :(得分:5)

除了维基百科Cyclic redundancy checkComputation of CRC文章外,我还发现了一篇名为Reversing CRC - Theory and Practice * 的论文参考。

基本上有三种计算CRC的方法:代数方法,面向位的方法和表驱动方法。在Reversing CRC - Theory and Practice * 中,这三种算法/方法中的每一种都在理论中通过附录中的C编程语言中的CRC32实现进行了解释。 / p>

* PDF链接
逆转CRC - 理论与实践。
胡柏林公开报告
SAR-PR-2006-05
2006年5月
作者:
Martin Stigge,HenrykPlötz,WolfMüller,Jens-Peter Redlich 功能

答案 3 :(得分:5)

对于IEEE802.3,CRC-32。将整个消息视为串行比特流,在消息末尾附加32个零。接下来,必须反转消息的每个字节的位,并对前32位执行1的补码。现在除以CRC-32多项式0x104C11DB7。最后,你必须1对这个除法的32位余数进行补码,对每个剩余的4个字节进行反转。这将成为附加到消息末尾的32位CRC。

这个奇怪程序的原因是第一个以太网实现会一次一个字节地串行化消息,并首先发送每个字节的最低有效位。然后串行比特流经过串行CRC-32移位寄存器计算,该消息在消息完成后被简单地补充并在线路上发送出去。补充消息的前32位的原因是,即使消息全为零,也不会得到全零CRC。

答案 4 :(得分:4)

我花了一些时间试图揭开这个问题的答案,我终于在今天发表了关于CRC-32的教程: CRC-32 hash tutorial - AutoHotkey Community

在这个例子中,我演示了如何计算ASCII字符串'abc'的CRC-32哈希值:

calculate the CRC-32 hash for the ASCII string 'abc':

inputs:
dividend: binary for 'abc': 0b011000010110001001100011 = 0x616263
polynomial: 0b100000100110000010001110110110111 = 0x104C11DB7

011000010110001001100011
reverse bits in each byte:
100001100100011011000110
append 32 0 bits:
10000110010001101100011000000000000000000000000000000000
XOR the first 4 bytes with 0xFFFFFFFF:
01111001101110010011100111111111000000000000000000000000

'CRC division':
01111001101110010011100111111111000000000000000000000000
 100000100110000010001110110110111
 ---------------------------------
  111000100010010111111010010010110
  100000100110000010001110110110111
  ---------------------------------
   110000001000101011101001001000010
   100000100110000010001110110110111
   ---------------------------------
    100001011101010011001111111101010
    100000100110000010001110110110111
    ---------------------------------
         111101101000100000100101110100000
         100000100110000010001110110110111
         ---------------------------------
          111010011101000101010110000101110
          100000100110000010001110110110111
          ---------------------------------
           110101110110001110110001100110010
           100000100110000010001110110110111
           ---------------------------------
            101010100000011001111110100001010
            100000100110000010001110110110111
            ---------------------------------
              101000011001101111000001011110100
              100000100110000010001110110110111
              ---------------------------------
                100011111110110100111110100001100
                100000100110000010001110110110111
                ---------------------------------
                    110110001101101100000101110110000
                    100000100110000010001110110110111
                    ---------------------------------
                     101101010111011100010110000001110
                     100000100110000010001110110110111
                     ---------------------------------
                       110111000101111001100011011100100
                       100000100110000010001110110110111
                       ---------------------------------
                        10111100011111011101101101010011

remainder: 0b10111100011111011101101101010011 = 0xBC7DDB53
XOR the remainder with 0xFFFFFFFF:
0b01000011100000100010010010101100 = 0x438224AC
reverse bits:
0b00110101001001000100000111000010 = 0x352441C2

thus the CRC-32 hash for the ASCII string 'abc' is 0x352441C2

答案 5 :(得分:2)

然后总是有Rosetta Code,它显示了用多种计算机语言实现的crc32。 https://rosettacode.org/wiki/CRC-32并具有许多解释和实现的链接。

答案 6 :(得分:1)

为了减少crc32接收提醒,您需要:

  1. 每个字节取反位
  2. 用0xFF来对前四个字节进行异或运算(这是为了避免前导0出现错误)
  3. 在末尾添加填充(这是为了使最后4个字节参与哈希)
  4. 计算提醒
  5. 再次反转位
  6. 再次将结果相加。

在代码中,这是:


func CRC32 (file []byte) uint32 {
    for i , v := range(file) {
        file[i] = bits.Reverse8(v)
    }
    for i := 0; i < 4; i++ {
        file[i] ^= 0xFF
    }

    // Add padding
    file = append(file, []byte{0, 0, 0, 0}...)
    newReminder := bits.Reverse32(reminderIEEE(file))

    return newReminder ^ 0xFFFFFFFF
}

其中,提醒IEEE是GF(2)[x]上的纯提醒