Visual Basic - Technik, FAQ, Tricks, Beispiele

Home / Allgemein / Sicherheit / CRC

CRC - Schnelle und sichere Prüfsummen-Berechnung

Einleitung

Motivation

Prüfsummen, insbesondere CRC32, bieten eine gute und einfache Möglichkeit, die Konsistenz etwa von Dateien zu prüfen. Wenn die CRC32-Summen zweier Dateien gleich sind, so werden die Dateien selbst auch zu 99,99999998% gleich sein.

Klar, dass der Vergleich zweier 32Bit-Zahlen viel schneller ist, als der Vergleich zweier Megabyte-Dateien. Vorneweg sollte man aber immer erst die Längen der beiden Dateien vergleichen (s.a. Artikel "Zwei Dateien vergleichen").

Gegenüber anderen Methoden der Prüfsummen-Bildung ist CRC ("Cyclic Redundancy Code") sehr robust sogar gegenüber Bit-Fehlern, die an der gleichen Stelle auftauchen. So heben sich "ein Bit zuviel" und "ein Bit zuwenig" in CRC nicht einfach auf, im Gegensatz zu der üblichen arithmetischen Summe "Module n".

Problem

Da CRC auf Bit-Ebene arbeitet (viele Shifts und Bit-Tests), ist eine reine Software-Lösung (nicht nur in VB) eigentlich nur sehr schwer zu realisieren und zudem ziemlich langsam. Doch zum Glück gibt es eine Möglichkeit, die CRC-Berechnung durch vorausberechnete Tabellen zu beschleunigen.

Weitere Informationen zu der dahintersteckenden Theorie der Berechnung sind u.a. in "A painless Guide to CRC Error Detection Algorithms" zu finden.

Beispiele

Die CRC32-Summe eines (Unicode-)Strings bestimmen:

MsgBox Hex$(CRC32Unicode("abcdefgh")) 'ergibt AEEF2A50

An eine Datei die CRC32-Summe dranhängen:

CRC32File "C:\Test\File.dat", Add:=True

Die CRC32-Summe einer Datei prüfen:

If CRC32File("C:\Test\File.dat", Check:=True) Then
  MsgBox "Datei OK"
End If

Code/Quelltext

Legen Sie am Besten ein neues Modul an, etwa "modCRC.Bas".

Hilfs-Variablen und -Routine

Im Modulkopf werden folgende Deklarationen (für die Speicherung der vorausberechneten Werte) benötigt:

Option Explicit

Private pInititialized As Boolean
Private pTable(0 To 255) As Long

Die folgende Prozedur muss nur einmal aufgerufen werden (erledigen die CRC-Funktionen selbstständig). Sie füllt die Hilfstabelle mit allen möglichen Byte-Werten zu einem vorgegebenen "Polynom":

Public Sub CRCInit( _
    Optional ByVal Poly As Long = &HEDB88320 _
  )
  'Deklarationen:
  Dim CRC As Long
  Dim i As Integer
  Dim j As Integer
  
  For i = 0 To 255
  
    CRC = i
    For j = 0 To 7
    
      If CRC And &H1 Then
        'CRC = (CRC >>> 1) ^ Poly
        CRC = ((CRC And &HFFFFFFFE) \ &H2 And &H7FFFFFFF) Xor Poly
      Else
        'CRC = (CRC >>> 1)
        CRC = CRC \ &H2 And &H7FFFFFFF
      End If
    
    Next j
    pTable(i) = CRC
  
  Next i
  pInititialized = True
End Sub

CRC32 - Prüfsumme über ein Byte-Array

Die folgende Funktion gibt entweder die CRC32-Summe zurück (falls Check=False, default), oder (bei Check=True) prüft das Byte-Array darauf, ob die letzten 4 Bytes gerade der CRC-Summe entsprechen:

' ©2003 by Jost Schwider, http://vb-tec.de/
Public Function CRC32( _
    ByRef Bytes() As Byte, _
    Optional ByVal Check As Boolean = False _
  ) As Long
  'Deklarationen:
  Dim CRC As Long
  Dim i As Long
  Dim n As Long
  
  If Not pInititialized Then CRCInit
  
  'Daten-Länge bestimmen:
  n = UBound(Bytes)
  If Check Then
    n = n - 4
    If n < LBound(Bytes) Then Exit Function
  End If
  
  'CRC berechnen:
  CRC = &HFFFFFFFF
  For i = LBound(Bytes) To n
  
    'CRC = (CRC >>> 8) ^ pTable[Bytes[i] ^ (CRC & 0xff)]
    CRC = ((CRC And &HFFFFFF00) \ &H100) And &HFFFFFF _
        Xor pTable(Bytes(i) Xor CRC And &HFF&)
  
  Next i
  CRC32 = Not CRC
  
  If Check Then
  
    'CRC checken:
    CRC = Bytes2Long(Bytes(i), Bytes(i + 1), Bytes(i + 2), Bytes(i + 3))
    CRC32 = (CRC32 = CRC)
  
  End If
End Function

CRC32Unicode - Prüfsumme über ein String

Diese Funktion arbeitet analog zu CRC32, jedoch mit einem String als Eingabe:

Public Function CRC32Unicode( _
    ByRef Text As String, _
    Optional ByVal Check As Boolean = False _
  ) As Long
  'Wie Byte-Array behandeln:
  CRC32Unicode = CRC32(StrConv(Text, vbFromUnicode), Check)
End Function

CRC32File - Prüfsumme über eine Datei

Diese Funktion arbeitet wie CRC32, jedoch mit einem Datei(pfad). Zusätzlich kann mit dem optionalen Parameter Add festgelegt werden, ob die Prüfsumme an die Datei angehängt werden soll:

' ©2003 by Jost Schwider, http://vb-tec.de/
Public Function CRC32File( _
    ByRef Path As String, _
    Optional ByVal Check As Boolean = False, _
    Optional ByVal Add As Boolean = False _
  ) As Long
  'Deklarationen:
  Dim Buffer() As Byte
  Dim BufferSize As Long
  Dim CRC As Long
  Dim FileNr As Integer
  Dim Length As Long
  Dim i As Long
  
  If Not pInititialized Then CRCInit
  
  BufferSize = &H1000 '4 KB
  ReDim Buffer(1 To BufferSize)
  
  FileNr = FreeFile
  Open Path For Binary As #FileNr
  
    'Daten-Länge bestimmen:
    Length = LOF(FileNr)
    If Check Then
      Length = Length - 4
      If Length < 0 Then Exit Function
    End If
    
    'CRC berechnen:
    CRC = &HFFFFFFFF
    Do While Length
    
      'Buffer einlesen:
      If Length < BufferSize Then
        BufferSize = Length
        ReDim Buffer(1 To Length)
      End If
      Get #FileNr, , Buffer
      
      'Buffer CRC-summieren:
      For i = 1 To BufferSize
        CRC = ((CRC And &HFFFFFF00) \ &H100) And &HFFFFFF _
            Xor pTable(Buffer(i) Xor CRC And &HFF&)
      Next i
      
      Length = Length - BufferSize
    
    Loop
    CRC32File = Not CRC
    
    If Check Then
    
      'CRC checken:
      Get #FileNr, , CRC
      If Add Then Put #FileNr, LOF(FileNr) - 3, CRC32File
      CRC32File = (CRC32File = CRC)
    
    Else
      If Add Then Put #FileNr, , CRC32File
    End If
  
  Close #FileNr
End Function

Aus Performance-Gründen wird die Datei (im Gegensatz zu CRC32) Block-weise verarbeitet.

© Jost Schwider, 24.10.2002-24.10.2002 - http://vb-tec.de/crc.htm