Solved

CRC Check Calculation

Posted on 2001-09-14
6
1,218 Views
Last Modified: 2012-08-14
Hi,

I have some settings data, which mainly consists of various String, Integer, Currency, Single and Boolean data types.  These are saved to a file when the user closes the program and loaded when it is started.

Now in order to protect the integrity of the data, I would like to append a CRC value to the data so when it is used it is possible to tell that the data hasn't been corrupted or tampered with (by comparing the saved CRC value of the loaded data with a recalculated CRC).

So what I need to be able to do is create a CRC value from the data.  Could anyone give me any code that would do this easily and be effective and accurate in determining errors in the data?

Thanks in Advance,

Richard
0
Comment
Question by:Richard2000
6 Comments
 
LVL 2

Expert Comment

by:lucika
Comment Utility
Unit CRC32;
{=======================================================}
{           Delphi unit for getting CRC32 of file       }
{=======================================================}
{              Performed for Delphi from BP 7.0         }
{                      1998 by Vladimir Zaytcev         }
{                                    2:5015/116         }
{=======================================================}

Interface

Uses Windows;

Procedure MakeCRCTable;
Function  RecountCRC(b : Byte; CrcOld : Longint) : Longint;
Function  HextW(w : Word) : String;
Function  HextL(l : Longint) : String;
Function  GetCRC32(FileToGet:String):String;

Implementation

Type
  Long = Record
    Loword : Word;
    Hiword : Word;
  End;

Const
  CRCPOLY = $EDB88320;

Var
  CRCTable  : Array[0..512] Of Longint;


Procedure MakeCRCTable;
Var
  i, j : Word;
  r    : Longint;
Begin
  FillChar(CRCTable, SizeOf(CRCTable), 0);
  For i:=0 To 255 Do
   Begin
    r:=i Shl 1;
    For j:=8 DownTo 0 do
      If (r and 1)<>0 Then
        r:=(r Shr 1) Xor CRCPOLY
      Else
        r:=r Shr 1;
    CRCTable[i]:=r;
   End;
End;

Function RecountCRC(b : byte; CrcOld : Longint) : Longint;
Begin
   RecountCRC:=CRCtable[byte(CrcOld xor longint(b))] xor ((CrcOld shr 8) And
$00FFFFFF)
End;

Function HextW(w : Word) : String;
Const
  h : Array[0..15] Of Char = '0123456789ABCDEF';
Begin
  HextW:='';
  HextW:=h[Hi(w) Shr 4]+h[Hi(w) And $F]+h[Lo(w) Shr 4]+h[Lo(w) And $F];
End;

Function HextL(l : Longint) : String;
Begin
  With Long(l) Do
    HextL:=HextW(HiWord)+HextW(LoWord);
End;

Function GetCRC32(FileToGet:String):String;
Var
  Buffer: PChar;
  f     : File Of Byte;
  b     : Array[0..255] Of Byte;
  CRC   : Longint;
  e, i  : Integer;
Begin
  MakeCRCTable;
  CRC := $FFFFFFFF;
  AssignFile(F,FileToGet);
  FileMode := 0;
  Reset(F);
   Repeat
    GetMem(Buffer,SizeOf(B));
    FillChar(b, SizeOf(b), 0);
    BlockRead(F, b,SizeOf(b), e);
    For i := 0 To (e-1) Do
     CRC := RecountCRC (b[i], CRC);
    Freemem(Buffer,SizeOf(B));
   Until (e < 255) Or (IOresult <> 0);
  CloseFile(F);
  CRC := Not CRC;
  GetCRC32:='$'+HextL(CRC);
end;

end.


or

>-- aluue.pas

// Archive Lister UUE Code/Decode (c) SotSoft
// by s0t //SotSoft //NSi //rAN
// by SOt //SotSoft //rAN
// thx r0wdy //rAN (crc64.asm)

// skip by s0t

type
  TCRC64 = array[0..1] of Longint;

procedure CRC64AddByte; assembler;
asm
        add     es:[di],ax
        mov     al,0
        adc     es:[di+2],ax
        adc     es:[di+4],ax
        adc     es:[di+6],ax
        shl     word ptr es:[di],1
        rcl     word ptr es:[di+2],1
        rcl     word ptr es:[di+4],1
        rcl     word ptr es:[di+6],1
        adc     es:[di],ax
end;

procedure GetCRC64Buf(var Buf; Size: Word; var CRC64: TCRC64;
  var BufPos: word); assembler;
asm
        cld
        mov     cx,Size
        jcxz    @@E
        push    ds
        lds     si,Buf
        les     di,BufPos
        mov     dx,es:[di]
        les     di,CRC64
        xor     ax,ax
@@1:
        lodsb
        call    CRC64AddByte
        mov     al,dl
        call    CRC64AddByte
        inc     dx
        loop    @@1
        pop     ds
        les     di,BufPos
        mov     es:[di],dx
@@E:
end;

procedure InitCRC64(var CRC64: TCRC64);
begin
  CRC64[0] := $7A8B3989; CRC64[1] := $7C616DF9;
end;


0
 
LVL 7

Expert Comment

by:Motaz
Comment Utility
See this unit also:

UNIT CRC32;

 (* Comment below is the development history of this unit *)

 {CRC32 calculates a cyclic redundancy code (CRC), known as CRC-32, using
  a byte-wise algorithm.

  (C) Copyright 1989, 1995-1996 Earl F. Glynn, Overland Park, KS.
  All Rights Reserved.

  This UNIT was derived from the CRCT FORTRAN 77 program given in
  "Byte-wise CRC Calculations" by Aram Perez in IEEE Micro, June 1983,
  pp. 40-50.  The constants here are for the CRC-32 generator polynomial,
  as defined in the Microsoft Systems Journal, March 1995, pp. 107-108

  This CRC algorithm emphasizes speed at the expense of the 512 element
  lookup table.}

 { In 1999, This unit updated by Motaz Abdel Azim, motaz1@yahoo.com }
 { The update include ability of getting CRC of any part of file by }
 { adding BytesFromStart and BytesBeforEnd, if both of them are 0, the }
 { CRC code of entire file will be returned }


Interface

Function GetFileCRC (FileName: string;var CRCvalue:  LongInt;
         BytesFromStart, BytesBeforEnd: LongInt): integer;
procedure CalcCRC32 (var Buf: array of byte; nbyte: word;
          var CRCvalue: LongInt);

Implementation

const
    table:  array[0..255] of LongWord =
   ($00000000, $77073096, $EE0E612C, $990951BA,
    $076DC419, $706AF48F, $E963A535, $9E6495A3,
    $0EDB8832, $79DCB8A4, $E0D5E91E, $97D2D988,
    $09B64C2B, $7EB17CBD, $E7B82D07, $90BF1D91,
    $1DB71064, $6AB020F2, $F3B97148, $84BE41DE,
    $1ADAD47D, $6DDDE4EB, $F4D4B551, $83D385C7,
    $136C9856, $646BA8C0, $FD62F97A, $8A65C9EC,
    $14015C4F, $63066CD9, $FA0F3D63, $8D080DF5,
    $3B6E20C8, $4C69105E, $D56041E4, $A2677172,
    $3C03E4D1, $4B04D447, $D20D85FD, $A50AB56B,
    $35B5A8FA, $42B2986C, $DBBBC9D6, $ACBCF940,
    $32D86CE3, $45DF5C75, $DCD60DCF, $ABD13D59,
    $26D930AC, $51DE003A, $C8D75180, $BFD06116,
    $21B4F4B5, $56B3C423, $CFBA9599, $B8BDA50F,
    $2802B89E, $5F058808, $C60CD9B2, $B10BE924,
    $2F6F7C87, $58684C11, $C1611DAB, $B6662D3D,

    $76DC4190, $01DB7106, $98D220BC, $EFD5102A,
    $71B18589, $06B6B51F, $9FBFE4A5, $E8B8D433,
    $7807C9A2, $0F00F934, $9609A88E, $E10E9818,
    $7F6A0DBB, $086D3D2D, $91646C97, $E6635C01,
    $6B6B51F4, $1C6C6162, $856530D8, $F262004E,
    $6C0695ED, $1B01A57B, $8208F4C1, $F50FC457,
    $65B0D9C6, $12B7E950, $8BBEB8EA, $FCB9887C,
    $62DD1DDF, $15DA2D49, $8CD37CF3, $FBD44C65,
    $4DB26158, $3AB551CE, $A3BC0074, $D4BB30E2,
    $4ADFA541, $3DD895D7, $A4D1C46D, $D3D6F4FB,
    $4369E96A, $346ED9FC, $AD678846, $DA60B8D0,
    $44042D73, $33031DE5, $AA0A4C5F, $DD0D7CC9,
    $5005713C, $270241AA, $BE0B1010, $C90C2086,
    $5768B525, $206F85B3, $B966D409, $CE61E49F,
    $5EDEF90E, $29D9C998, $B0D09822, $C7D7A8B4,
    $59B33D17, $2EB40D81, $B7BD5C3B, $C0BA6CAD,

    $EDB88320, $9ABFB3B6, $03B6E20C, $74B1D29A,
    $EAD54739, $9DD277AF, $04DB2615, $73DC1683,
    $E3630B12, $94643B84, $0D6D6A3E, $7A6A5AA8,
    $E40ECF0B, $9309FF9D, $0A00AE27, $7D079EB1,
    $F00F9344, $8708A3D2, $1E01F268, $6906C2FE,
    $F762575D, $806567CB, $196C3671, $6E6B06E7,
    $FED41B76, $89D32BE0, $10DA7A5A, $67DD4ACC,
    $F9B9DF6F, $8EBEEFF9, $17B7BE43, $60B08ED5,
    $D6D6A3E8, $A1D1937E, $38D8C2C4, $4FDFF252,
    $D1BB67F1, $A6BC5767, $3FB506DD, $48B2364B,
    $D80D2BDA, $AF0A1B4C, $36034AF6, $41047A60,
    $DF60EFC3, $A867DF55, $316E8EEF, $4669BE79,
    $CB61B38C, $BC66831A, $256FD2A0, $5268E236,
    $CC0C7795, $BB0B4703, $220216B9, $5505262F,
    $C5BA3BBE, $B2BD0B28, $2BB45A92, $5CB36A04,
    $C2D7FFA7, $B5D0CF31, $2CD99E8B, $5BDEAE1D,

    $9B64C2B0, $EC63F226, $756AA39C, $026D930A,
    $9C0906A9, $EB0E363F, $72076785, $05005713,
    $95BF4A82, $E2B87A14, $7BB12BAE, $0CB61B38,
    $92D28E9B, $E5D5BE0D, $7CDCEFB7, $0BDBDF21,
    $86D3D2D4, $F1D4E242, $68DDB3F8, $1FDA836E,
    $81BE16CD, $F6B9265B, $6FB077E1, $18B74777,
    $88085AE6, $FF0F6A70, $66063BCA, $11010B5C,
    $8F659EFF, $F862AE69, $616BFFD3, $166CCF45,
    $A00AE278, $D70DD2EE, $4E048354, $3903B3C2,
    $A7672661, $D06016F7, $4969474D, $3E6E77DB,
    $AED16A4A, $D9D65ADC, $40DF0B66, $37D83BF0,
    $A9BCAE53, $DEBB9EC5, $47B2CF7F, $30B5FFE9,
    $BDBDF21C, $CABAC28A, $53B39330, $24B4A3A6,
    $BAD03605, $CDD70693, $54DE5729, $23D967BF,
    $B3667A2E, $C4614AB8, $5D681B02, $2A6F2B94,
    $B40BBE37, $C30C8EA1, $5A05DF1B, $2D02EF8D);


procedure CalcCRC32 (var Buf: array of byte; nbyte:
  word; var CRCvalue: LongInt);
   {The following is a little cryptic (but executes very quickly).
    The algorithm is as follows:
      1.  exclusive-or the input byte with the low-order portion of
          the CRC register to get an INDEX
      2.  shift the CRC register eight bits to the right
      3.  exclusive-or the CRC register with the contents of
          Table[INDEX]
      4.  repeat steps 1 through 3 for all bytes}
var
  i: LongInt;
begin
  for i:= 0 to nBYTE-1 do
    CRCvalue := (LongWord(CRCvalue) shr 8)  xor
      Table[Buf[i] xor (CRCvalue and $000000FF)]
end;

(*********************  Get file CRC  *******************)

Function GetFileCRC(FileName: string; var CRCvalue:  LongInt;
            BytesFromStart, BytesBeforEnd: LongInt): integer;
var
  BytesRead: integer;
  F: file;
  Buf: array [0..1023] of byte;
  FSize, TotalBytes, MustRead: integer;
  Error: integer;
begin
  FileMode := 0;  (*** Read only access ***)
  CRCValue := -1;
  AssignFile(F, FileName);
  {$I-}
  Reset(F, 1);
  {$I+}
  Error := IOResult;
  IF Error <> 0 then
  begin
    GetFileCRC:= Error;
    exit;
  end;
  TotalBytes := 0;
  FSize:= FileSize(F)-BytesFromStart-BytesBeforEnd;

  Seek(F, BytesFromStart); (*** Bypass file header ***)
  MustRead:= SizeOf(Buf);

  repeat
    if TotalBytes+MustRead > FSize then
      MustRead:= FSize-TotalBytes;
    {$i-}
    BlockRead(F, Buf, MustRead, BytesRead);
    {$i+}
    Error:= IOResult;
    if Error <> 0 then
    begin
      CloseFile(F);
      GetFileCRC:= Error;
      Exit;
    end;
    CalcCRC32(Buf, BytesRead, CRCvalue);
    Inc(TotalBytes, BytesRead)
  until TotalBytes >= FSize;

  CloseFile(F);
  CRCvalue := NOT CRCvalue;
  GetFileCRC :=0; (*** Successed ***)
end;

end.
0
 
LVL 7

Expert Comment

by:Motaz
Comment Utility
This is an example of using CRC32.pas unit:

- Add CRC32 to Uses clause.
- Write this code:

Var
  Err: integer;
  CRC: integer;
begin
  Err:= GetFileCRC('c:\command.com', CRC,
         0, 0);
  if Err <> 0 then
   ShowMessage('Error while reading CRC code')
  else
    ShowMessage('File CRC code is: '+IntToStr(CRC));
end;

Very simple! isn't it ?

GetFileCRC function declared as:

Function GetFileCRC(FileName: string;
   var CRCvalue:  LongInt;
   BytesFromStart,
   BytesBeforEnd: LongInt): integer;
 
BytesFromStart and BytesBeforEnd enables you get file CRC code for any part of a file.  For example you can get file CRC without first 10 bytes:

  GetFileCRC('c:\command.com', CRC, 10, 0);

If you want to get file CRC except last 4 bytes you can write:

  GetFileCRC('c:\command.com', CRC, 0, 4);

0
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 

Expert Comment

by:DelFreak
Comment Utility
Listening...
0
 
LVL 20

Accepted Solution

by:
Madshi earned 50 total points
Comment Utility
Here comes the variation I'm using:

function updateCrc32(crc32: cardinal; const inBuf; inLen: integer) : cardinal;
const crc32Tab : array [0..255] of cardinal =
                 ($00000000, $77073096, $ee0e612c, $990951ba, $076dc419, $706af48f, $e963a535, $9e6495a3,
                  $0edb8832, $79dcb8a4, $e0d5e91e, $97d2d988, $09b64c2b, $7eb17cbd, $e7b82d07, $90bf1d91,
                  $1db71064, $6ab020f2, $f3b97148, $84be41de, $1adad47d, $6ddde4eb, $f4d4b551, $83d385c7,
                  $136c9856, $646ba8c0, $fd62f97a, $8a65c9ec, $14015c4f, $63066cd9, $fa0f3d63, $8d080df5,
                  $3b6e20c8, $4c69105e, $d56041e4, $a2677172, $3c03e4d1, $4b04d447, $d20d85fd, $a50ab56b,
                  $35b5a8fa, $42b2986c, $dbbbc9d6, $acbcf940, $32d86ce3, $45df5c75, $dcd60dcf, $abd13d59,
                  $26d930ac, $51de003a, $c8d75180, $bfd06116, $21b4f4b5, $56b3c423, $cfba9599, $b8bda50f,
                  $2802b89e, $5f058808, $c60cd9b2, $b10be924, $2f6f7c87, $58684c11, $c1611dab, $b6662d3d,
                  $76dc4190, $01db7106, $98d220bc, $efd5102a, $71b18589, $06b6b51f, $9fbfe4a5, $e8b8d433,
                  $7807c9a2, $0f00f934, $9609a88e, $e10e9818, $7f6a0dbb, $086d3d2d, $91646c97, $e6635c01,
                  $6b6b51f4, $1c6c6162, $856530d8, $f262004e, $6c0695ed, $1b01a57b, $8208f4c1, $f50fc457,
                  $65b0d9c6, $12b7e950, $8bbeb8ea, $fcb9887c, $62dd1ddf, $15da2d49, $8cd37cf3, $fbd44c65,
                  $4db26158, $3ab551ce, $a3bc0074, $d4bb30e2, $4adfa541, $3dd895d7, $a4d1c46d, $d3d6f4fb,
                  $4369e96a, $346ed9fc, $ad678846, $da60b8d0, $44042d73, $33031de5, $aa0a4c5f, $dd0d7cc9,
                  $5005713c, $270241aa, $be0b1010, $c90c2086, $5768b525, $206f85b3, $b966d409, $ce61e49f,
                  $5edef90e, $29d9c998, $b0d09822, $c7d7a8b4, $59b33d17, $2eb40d81, $b7bd5c3b, $c0ba6cad,
                  $edb88320, $9abfb3b6, $03b6e20c, $74b1d29a, $ead54739, $9dd277af, $04db2615, $73dc1683,
                  $e3630b12, $94643b84, $0d6d6a3e, $7a6a5aa8, $e40ecf0b, $9309ff9d, $0a00ae27, $7d079eb1,
                  $f00f9344, $8708a3d2, $1e01f268, $6906c2fe, $f762575d, $806567cb, $196c3671, $6e6b06e7,
                  $fed41b76, $89d32be0, $10da7a5a, $67dd4acc, $f9b9df6f, $8ebeeff9, $17b7be43, $60b08ed5,
                  $d6d6a3e8, $a1d1937e, $38d8c2c4, $4fdff252, $d1bb67f1, $a6bc5767, $3fb506dd, $48b2364b,
                  $d80d2bda, $af0a1b4c, $36034af6, $41047a60, $df60efc3, $a867df55, $316e8eef, $4669be79,
                  $cb61b38c, $bc66831a, $256fd2a0, $5268e236, $cc0c7795, $bb0b4703, $220216b9, $5505262f,
                  $c5ba3bbe, $b2bd0b28, $2bb45a92, $5cb36a04, $c2d7ffa7, $b5d0cf31, $2cd99e8b, $5bdeae1d,
                  $9b64c2b0, $ec63f226, $756aa39c, $026d930a, $9c0906a9, $eb0e363f, $72076785, $05005713,
                  $95bf4a82, $e2b87a14, $7bb12bae, $0cb61b38, $92d28e9b, $e5d5be0d, $7cdcefb7, $0bdbdf21,
                  $86d3d2d4, $f1d4e242, $68ddb3f8, $1fda836e, $81be16cd, $f6b9265b, $6fb077e1, $18b74777,
                  $88085ae6, $ff0f6a70, $66063bca, $11010b5c, $8f659eff, $f862ae69, $616bffd3, $166ccf45,
                  $a00ae278, $d70dd2ee, $4e048354, $3903b3c2, $a7672661, $d06016f7, $4969474d, $3e6e77db,
                  $aed16a4a, $d9d65adc, $40df0b66, $37d83bf0, $a9bcae53, $debb9ec5, $47b2cf7f, $30b5ffe9,
                  $bdbdf21c, $cabac28a, $53b39330, $24b4a3a6, $bad03605, $cdd70693, $54de5729, $23d967bf,
                  $b3667a2e, $c4614ab8, $5d681b02, $2a6f2b94, $b40bbe37, $c30c8ea1, $5a05df1b, $2d02ef8d);
var i1 : integer;
    ab : array [0..maxInt - 1] of byte absolute inBuf;
begin
  result := crc32;
  for i1 := 0 to inLen - 1 do
    result := crc32Tab[byte(result xor ab[i1])] xor (result shr 8);
end;

type
  TWildTypes = record
    str : string;
    int : integer;
    cur : Currency;
    sin : single;
    boo : boolean;
  end;

var
  wt  : TWildTypes = (...);
  crc : dword;

crc := updateCrc32($FFFFFFFF, pchar(wt.str)^, Length(wt.str));
crc := updateCrc32(crc, wt.int, sizeOf(wt.int));
crc := updateCrc32(crc, wt.cur, sizeOf(wt.cur));
crc := updateCrc32(crc, wt.sin, sizeOf(wt.sin));
crc := updateCrc32(crc, wt.boo, sizeOf(wt.boo));

Please be cautious with dynamic types (string, wideString, dynamic array, interface, variant, ...). All those types are nothing but a special type of pointer, so you must handle all those differently, see the example with the string above.

Regards, Madshi.
0
 
LVL 20

Expert Comment

by:Madshi
Comment Utility
P.S: Normally you give in $FFFFFFFF when calling updateCrc32 the first time. After you're done, you usually do:

crc := not crc;

This is the exact logic that zip programs use.
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…
Here's a very brief overview of the methods PRTG Network Monitor (https://www.paessler.com/prtg) offers for monitoring bandwidth, to help you decide which methods you´d like to investigate in more detail.  The methods are covered in more detail in o…

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now