1. 程式人生 > >CRC編碼演算法研究與實現

CRC編碼演算法研究與實現

CRC

演算法及原理

CRC校驗碼的基本思想是利用線性編碼理論,在傳送端根據要傳送的k位二進位制碼序列,以一定的規則產生一個校驗用的監督碼(既CRC碼)r位,並附在資訊後邊,構成一個新的二進位制碼序列數共(k+r)位,最後傳送出去。在接收端,則根據資訊碼和CRC碼之間所遵循的規則進行檢驗,以確定傳送中是否出錯。在資料儲存和資料通訊領域,CRC無處不在:著名的通訊協議X.25FCS(幀檢錯序列)採用的是CRC. CCITTARJLHA等壓縮工具軟體採用的是CRC32,磁碟驅動器的讀寫採用了CRC16,通用的影象儲存格式GIFTIFF等也都用CRC作為檢錯手段。


    CRC
的本質是模-2除法的餘數,採用的除數不同,CRC的型別也就不一樣。通常,CRC的除數用生成多項式來表示。最常用的CRC碼的生成多項式有CRC16,CRC32.
   
CRC16為例,16位的CRC碼產生的規則是先將要傳送的二進位制序列數左移16位(既乘以2^16)後,再除以一個多項式,最後所得到的餘數既是CRC碼,如下式所示,其中K(X)表示n位的二進位制序列數,G(X)為多項式,Q(X)為整數,R(X)是餘數(既CRC碼)。
K(X)>>16=G(x)Q(x)+R(x)
   
CRC碼所採用模2加減運演算法則,既是不帶進位和借位的按位加減,這種加減運算實際上就是邏輯上的異或運算,加法和減法等價,乘法和除法運算與普通代數式的乘除法運算是一樣,符合同樣的規律。生成
CRC碼的多項式如下,其中CRC-16CRC-CCITT產生16位的CRC碼,而CRC-32則產生的是32位的CRC接收方將接收到的二進位制序列數(包括資訊碼和CRC碼)除以多項式,如果餘數為0,則說明傳輸中無錯誤發生,否則說明傳輸有誤,關於其原理這裡不再多述。用軟體計算CRC碼時,接收方可以將接收到的資訊碼求CRC碼,比較結果和接收到的CRC碼是否相同。CCITT推薦的高階資料鏈路控制規程HDLC的幀校驗序列FCS中,使用CCITT-16CRC16,其生成多項式為G(x)=x16+x12+x5+1,CRC-32的生成多項式為G(x)=x32+x26+x23+x22+x16+x11+x10+x16
+x8+x7+x5+x4+x2+x+1
CRC演算法原理及C語言實現

CRC原理介紹:

CRC的英文全稱為Cyclic Redundancy CheckCode),中文名稱為迴圈冗餘校驗(碼)。它是一類重要的線性分組碼,編碼和解碼方法簡單,檢錯和糾錯能力強,在通訊領域廣泛地用於實現差錯控制。

CRC計算與普通的除法計算有所不同。普通的除法計算是借位相減的,而CRC計算則是異或運算。任何一個除法運算都需要選取一個除數,在CRC運算中我們稱之為poly,而寬度W就是poly最高位的位置。比如poly 1001W3,而不是4。注意最高位總是1,當你選定一個寬度,那麼你只需要選擇低W各位的值。假如我們想計算一個位串的CRC碼,並要保證每一位都要被處理,因此我們需要在目標位串後面加上W0。下面舉例說明CRC演算法的過程。在此例中,我們假設位串為110101101

Poly
= 10011(寬度W = 4
Bitstring + W zeros = 110101101 0000

10011/1101011010000/110000101(我們不關心此運算的商) 10011|||||||| -----||||||||
10011|||||||
10011|||||||
-----|||||||
00001||||||
00000||||||
-----||||||
00010|||||
00000|||||
-----|||||
00101||||
00000||||
-----||||
01010|||
00000||| -----|||
10100||
10011||
-----||
01110|
00000|
-----|
11100
10011
-----
1111 ->餘數 -> CRC

計算過程總結如下:
1.
只有當位串的最高位為1,我們才將它與polyXOR運算,否則我們只是將位串左移一位。
2.
異或運算的結果實質上是被操作位串與poly的低W位進行運算的結果,因為最高位總為0。 

CRC原理及其逆向破解方法:

介紹:

這篇短文包含CRC原理介紹和其逆向分析方法,很多程式設計師和破解者不是很清楚瞭解
CRC
的工作原理,而且幾乎沒人知道如何逆向分析它的方法,事實上它是非常有用的.
首先,這篇教程教你一般如何計算CRC,你可以將它用在資料程式碼保護中.第二,主要是介紹如何逆向分析CRC-32,你可以以此來分析程式中的CRC保護(象反病毒編碼).當然有很多有效的工具用來對付CRC,但我懷疑它是否會說明原理.
 
我要告訴你,這篇短文裡中應用了很多數學知識,這不會影響一些人,而且會被一般的程式設計師與逆向分析者很好理解.為什麼?那麼如果你不知道數學是如何被應用在CRC,
我建議你可以停止繼續學習了.所以我假定你們(讀者)都是具備二進位制算術知識的.

第一部分:CRC介紹,CRC是什麼和計算CRC的方法

迴圈冗餘碼 CRC

我們都知道CRC.甚至你沒有印象,但當你想到那些來自諸如RAR,ZIP等壓縮軟體發給你由於錯誤連線和其他一些意外原因導致的檔案錯誤的惱人的訊息時,你就會知道.CRC是塊資料的計算值,比如對每一個檔案進行壓縮.在一個解壓縮過程中,程式會從新計算解壓檔案CRC,並且將之與從檔案中讀取的CRC值進行比對,如果值相同,那麼正確.CRC-32,
會有1/2^32的可能性發生對確認資料更改的校驗錯誤.   
 
很多人認為CRC就是迴圈冗餘校驗,假如CRC真的就是迴圈冗餘校驗,那麼很多人都錯用了這個術語.你不能說"這個程式的CRC12345678".人們也常說某一個程式有CRC校驗,而不說是 "迴圈冗餘校驗"校驗.結論:CRC代表迴圈冗餘碼,而不是迴圈冗餘校驗
 
計算是如何完成的呢?好,主要的想法就是將一個檔案看成一個被一些數字分割的很長的位字串,這裡會有一個餘數---CRC!你總會有一個餘數(可以是0),它至多比除數小一.
(9/3=3
餘數=0 ; (9+2)/3=3餘數=2)
(
或者它本身就包含一個除數在其中).
 
在這裡CRC計算方法與除法有一點點區別,除法就是將被減數重複的減去除數X,然後留下餘數.如果你希望得到原值,那麼你就要把除數乘上X,然後加上餘數.
  CRC
計算使用特殊的減法與加法完成的.也就是一種新的"演算法".計算中每一位計算的進位值"遺忘"
看如下兩個例子,1是普通減法,23是特殊的.
     -+
(1) 1101  (2) 1010  1010  (3) 0+0=0  0-0=0
    1010-     1111+ 1111-     0+1=1 *0-1=1
    ----      ----  ----      1+0=1  1-0=1
    0011      0101  0101     *1+1=0  1-1=0
 
(1),右數第二列可以看成是0-1=-1,因此要從高位借1,就變成(10+0)-1=1.(這就象普通'by-paper'十進位制減法).特例(2,3),1+1會有正常的結果10,'1'是計算後的進位.這個值被忽略了.特殊情況0-1應該有正常結果'-1'就要退到下一位.這個值也被忽略了.假如你對程式設計有一定了解,這就象,XOR操作或者更好.
 
現在來看一個除法的例子:

在普通演算法中:
1001/1111000/1101 13            9/120/13
     1001    -                    09  -|
     ----                         --   |
      1100                         30  |
      1001    -                    27  -
      ----                         --
       0110                         3 ->
餘數
       0000    -
       ----
        1100
        1001    -
        ----
         011 -> 3,
餘數

CRC演算法中:
1001/1111000/1110               9/120/14
餘數為6
     1001    -
     ----
      1100
      1001    -
      ----
       1010
       1001    -
       ----
        0110
        0000    -
        ----
         110 ->
餘數
(
3)

這個除法的商並不重要,也沒必要去記住,因為他們僅僅是一組無關緊要的位串.真正重要的是餘數!它就是這個值,可以說比原檔案還重要的值,他就是基本的CRC.

過度到真正的CRC碼計算.

進行一個CRC計算我們需要選則一個除數,從現在起我們稱之為"poly".寬度W就是最高位的位置,所以這個poly 1001W3,而不是4.注意最高位總是1,當你選定一個寬度,那麼你只需要選擇低W各位的值
 
假如我們想計算一個位串的CRC,我們想確定每一個位都被處理過,因此,我們要在目標位串後面加上W0.在此例中,我們假設位串為1111.請仔細分析下面一個例子:

Poly                = 10011,寬度 W=4
位串                Bitstring
Bitstring + W zeros = 110101101 + 0000

10011/1101011010000/110000101 (我們不關心此運算的商)
      10011|||||||| -
      -----||||||||
       10011|||||||
       10011|||||||  -
       -----|||||||
        00001||||||
        00000||||||   -
        -----||||||
         00010|||||
         00000|||||    -
         -----|||||
          00101||||
          00000||||     -
          -----||||
           01010|||
           00000|||      -
           -----|||
            10100||
            10011||       -
            -----||
             01110|
             00000|        -
             -----|
              11100
              10011         -
              -----
               1111 ->
餘數 -> the CRC!
(
4)

重要兩點宣告如下:
1.
只有當Bitstring的最高位為1,我們才將它與polyXOR運算,否則我們只是將
  Bitstring
左移一位.
2.XOR
運算的結果就是被操作位串bitstring與低W位進行XOR運算,因為最高位總為0.

演算法設計:

你們都應知道基於位運算的演算法是非常慢的而且效率低下.但如果將計算放在每一位元組上進行,那麼效率將大大提高.不過我們只能接受poly的寬度是8的倍數(一個位元組;).可以形象的看成這樣一個寬度為32poly(W=32):

          3   2   1   0    byte
        +---+---+---+---+
Pop! <--|   |   |   |   |<-- bitstring with W zero bits added, in this case 32
        +---+---+---+---+
       1<--- 32 bits ---> this is the poly, 4*8 bits

(figure 1)
 
這是一個你用來存放暫時CRC結果的記存器,現在我稱它為CRC記存器或者記存器.你從右至左移動位串,當從左邊移出的位是1,則整個記存器被與poly的低W位進行XOR運算.(