VB-Tec.de Visual Basic - Technik, FAQ, Tricks, BeispieleHome / Allgemein / Sicherheit / CRC CRC - Schnelle und sichere Prüfsummen-Berechnung |
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".
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.
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
Legen Sie am Besten ein neues Modul an, etwa "modCRC.Bas".
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
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
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
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