1、MD5算法是对输入的数据进行补位,使得如果数据位长度LEN对512求余的结果是448。 即数据扩展至K*512+448位。即K*64+56个字节,K为整数。 具体补位操作:补一个1,然后补0至满足上述要求2、补数据长度: 用一个64位的数字表示数据的原始长度B,把B用两个32位数表示。这时,数据就被填 补成长度为512位的倍数。3. 初始化MD5参数 四个32位整数 (A,B,C,D) 用来计算信息摘要,初始化使用的是十六进制表示的数字A=0X01234567 B=0X89abcdef C=0Xfedcba98 D=0X765432104、处理位操作函数X,Y,Z为32位整数。 F(X,Y,Z) = X&Y|NOT(X)&Z G(X,Y,Z) = X&Z|Y¬(Z) H(X,Y,Z) = X xor Y xor Z I(X,Y,Z) = Y xor (X|not(Z))5、主要变换过程: 使用常数组T[1 ... 64], T[i]为32位整数用16进制表示,数据用16个32位的整 数数组M[]表示。具体过程如下:/* 处理数据原文 */ For i = 0 to N/16-1 do/*每一次,把数据原文存放在16个元素的数组X中. */ For j = 0 to 15 do Set X[j] to M[i*16+j]. end /结束对J的循环/* Save A as AA, B as BB, C as CC, and D as DD. */ AA = A BB = B CC = C DD = D/* 第1轮*/ /* 以 [abcd k s i]表示如下操作 a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). *//* Do the following 16 operations. */ [ABCD 0 7 1] [DABC 1 12 2] [CDAB 2 17 3] [BCDA 3 22 4] [ABCD 4 7 5] [DABC 5 12 6] [CDAB 6 17 7] [BCDA 7 22 8] [ABCD 8 7 9] [DABC 9 12 10] [CDAB 10 17 11] [BCDA 11 22 12] [ABCD 12 7 13] [DABC 13 12 14] [CDAB 14 17 15] [BCDA 15 22 16]/* 第2轮* */ /* 以 [abcd k s i]表示如下操作 a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ /* Do the following 16 operations. */ [ABCD 1 5 17] [DABC 6 9 18] [CDAB 11 14 19] [BCDA 0 20 20] [ABCD 5 5 21] [DABC 10 9 22] [CDAB 15 14 23] [BCDA 4 20 24] [ABCD 9 5 25] [DABC 14 9 26] [CDAB 3 14 27] [BCDA 8 20 28] [ABCD 13 5 29] [DABC 2 9 30] [CDAB 7 14 31] [BCDA 12 20 32]/* 第3轮*/ /* 以 [abcd k s i]表示如下操作 a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ /* Do the following 16 operations. */ [ABCD 5 4 33] [DABC 8 11 34] [CDAB 11 16 35] [BCDA 14 23 36] [ABCD 1 4 37] [DABC 4 11 38] [CDAB 7 16 39] [BCDA 10 23 40] [ABCD 13 4 41] [DABC 0 11 42] [CDAB 3 16 43] [BCDA 6 23 44] [ABCD 9 4 45] [DABC 12 11 46] [CDAB 15 16 47] [BCDA 2 23 48]/* 第4轮*/ /* 以 [abcd k s i]表示如下操作 a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ /* Do the following 16 operations. */ [ABCD 0 6 49] [DABC 7 10 50] [CDAB 14 15 51] [BCDA 5 21 52] [ABCD 12 6 53] [DABC 3 10 54] [CDAB 10 15 55] [BCDA 1 21 56] [ABCD 8 6 57] [DABC 15 10 58] [CDAB 6 15 59] [BCDA 13 21 60] [ABCD 4 6 61] [DABC 11 10 62] [CDAB 2 15 63] [BCDA 9 21 64]/* 然后进行如下操作 */ A = A + AA B = B + BB C = C + CC D = D + DDend /* 结束对I的循环*/ 6、输出结果。
以下是MD5的源码: unit md5;// ----------------------------------------------------------------------------------------------- INTERFACE // -----------------------------------------------------------------------------------------------uses Windows;type MD5Count = array[0..1] of DWORD; MD5State = array[0..3] of DWORD; MD5Block = array[0..15] of DWORD; MD5CBits = array[0..7] of byte; MD5Digest = array[0..15] of byte; MD5Buffer = array[0..63] of byte; MD5Context = record State: MD5State; Count: MD5Count; Buffer: MD5Buffer; end;procedure MD5Init(var Context: MD5Context); procedure MD5Update(var Context: MD5Context; Input: pChar; Length: longword); procedure MD5Final(var Context: MD5Context; var Digest: MD5Digest);function MD5String(M: string): MD5Digest; function MD5File(N: string): MD5Digest; function MD5Print(D: MD5Digest): string;function MD5Match(D1, D2: MD5Digest): boolean;// ----------------------------------------------------------------------------------------------- IMPLEMENTATION // -----------------------------------------------------------------------------------------------var PADDING: MD5Buffer = ( $80, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00, $00 );function F(x, y, z: DWORD): DWORD; begin Result := (x and y) or ((not x) and z); end;function G(x, y, z: DWORD): DWORD; begin Result := (x and z) or (y and (not z)); end;function H(x, y, z: DWORD): DWORD; begin Result := x xor y xor z; end;function I(x, y, z: DWORD): DWORD; begin Result := y xor (x or (not z)); end;procedure rot(var x: DWORD; n: BYTE); begin x := (x shl n) or (x shr (32 - n)); end;procedure FF(var a: DWORD; b, c, d, x: DWORD; s: BYTE; ac: DWORD); begin inc(a, F(b, c, d) + x + ac); rot(a, s); inc(a, b); end;procedure GG(var a: DWORD; b, c, d, x: DWORD; s: BYTE; ac: DWORD); begin inc(a, G(b, c, d) + x + ac); rot(a, s); inc(a, b); end;procedure HH(var a: DWORD; b, c, d, x: DWORD; s: BYTE; ac: DWORD); begin inc(a, H(b, c, d) + x + ac); rot(a, s); inc(a, b); end;procedure II(var a: DWORD; b, c, d, x: DWORD; s: BYTE; ac: DWORD); begin inc(a, I(b, c, d) + x + ac); rot(a, s); inc(a, b); end;// -----------------------------------------------------------------------------------------------// Encode Count bytes at Source into (Count / 4) DWORDs at Target procedure Encode(Source, Target: pointer; Count: longword); var S: PByte; T: PDWORD; I: longword; begin S := Source; T := Target; for I := 1 to Count div 4 do begin T^ := S^; inc(S); T^ := T^ or (S^ shl 8); inc(S); T^ := T^ or (S^ shl 16); inc(S); T^ := T^ or (S^ shl 24); inc(S); inc(T); end; end;// Decode Count DWORDs at Source into (Count * 4) Bytes at Target procedure Decode(Source, Target: pointer; Count: longword); var S: PDWORD; T: PByte; I: longword; begin S := Source; T := Target; for I := 1 to Count do begin T^ := S^ and $ff; inc(T); T^ := (S^ shr 8) and $ff; inc(T); T^ := (S^ shr 16) and $ff; inc(T); T^ := (S^ shr 24) and $ff; inc(T); inc(S); end; end;// Transform State according to first 64 bytes at Buffer procedure Transform(Buffer: pointer; var State: MD5State); var a, b, c, d: DWORD; Block: MD5Block; begin Encode(Buffer, @Block, 64); a := State[0]; b := State[1]; c := State[2]; d := State[3]; FF (a, b, c, d, Block[ 0], 7, $d76aa478); FF (d, a, b, c, Block[ 1], 12, $e8c7b756); FF (c, d, a, b, Block[ 2], 17, $242070db); FF (b, c, d, a, Block[ 3], 22, $c1bdceee); FF (a, b, c, d, Block[ 4], 7, $f57c0faf); FF (d, a, b, c, Block[ 5], 12, $4787c62a); FF (c, d, a, b, Block[ 6], 17, $a8304613); FF (b, c, d, a, Block[ 7], 22, $fd469501); FF (a, b, c, d, Block[ 8], 7, $698098d8); FF (d, a, b, c, Block[ 9], 12, $8b44f7af); FF (c, d, a, b, Block[10], 17, $ffff5bb1); FF (b, c, d, a, Block[11], 22, $895cd7be); FF (a, b, c, d, Block[12], 7, $6b901122); FF (d, a, b, c, Block[13], 12, $fd987193); FF (c, d, a, b, Block[14], 17, $a679438e); FF (b, c, d, a, Block[15], 22, $49b40821); GG (a, b, c, d, Block[ 1], 5, $f61e2562); GG (d, a, b, c, Block[ 6], 9, $c040b340); GG (c, d, a, b, Block[11], 14, $265e5a51); GG (b, c, d, a, Block[ 0], 20, $e9b6c7aa); GG (a, b, c, d, Block[ 5], 5, $d62f105d); GG (d, a, b, c, Block[10], 9, $2441453); GG (c, d, a, b, Block[15], 14, $d8a1e681); GG (b, c, d, a, Block[ 4], 20, $e7d3fbc8); GG (a, b, c, d, Block[ 9], 5, $21e1cde6); GG (d, a, b, c, Block[14], 9, $c33707d6); GG (c, d, a, b, Block[ 3], 14, $f4d50d87); GG (b, c, d, a, Block[ 8], 20, $455a14ed); GG (a, b, c, d, Block[13], 5, $a9e3e905); GG (d, a, b, c, Block[ 2], 9, $fcefa3f8); GG (c, d, a, b, Block[ 7], 14, $676f02d9); GG (b, c, d, a, Block[12], 20, $8d2a4c8a); HH (a, b, c, d, Block[ 5], 4, $fffa3942); HH (d, a, b, c, Block[ 8], 11, $8771f681); HH (c, d, a, b, Block[11], 16, $6d9d6122); HH (b, c, d, a, Block[14], 23, $fde5380c); HH (a, b, c, d, Block[ 1], 4, $a4beea44); HH (d, a, b, c, Block[ 4], 11, $4bdecfa9); HH (c, d, a, b, Block[ 7], 16, $f6bb4b60); HH (b, c, d, a, Block[10], 23, $bebfbc70); HH (a, b, c, d, Block[13], 4, $289b7ec6); HH (d, a, b, c, Block[ 0], 11, $eaa127fa); HH (c, d, a, b, Block[ 3], 16, $d4ef3085); HH (b, c, d, a, Block[ 6], 23, $4881d05); HH (a, b, c, d, Block[ 9], 4, $d9d4d039); HH (d, a, b, c, Block[12], 11, $e6db99e5); HH (c, d, a, b, Block[15], 16, $1fa27cf8); HH (b, c, d, a, Block[ 2], 23, $c4ac5665); II (a, b, c, d, Block[ 0], 6, $f4292244); II (d, a, b, c, Block[ 7], 10, $432aff97); II (c, d, a, b, Block[14], 15, $ab9423a7); II (b, c, d, a, Block[ 5], 21, $fc93a039); II (a, b, c, d, Block[12], 6, $655b59c3); II (d, a, b, c, Block[ 3], 10, $8f0ccc92); II (c, d, a, b, Block[10], 15, $ffeff47d); II (b, c, d, a, Block[ 1], 21, $85845dd1); II (a, b, c, d, Block[ 8], 6, $6fa87e4f); II (d, a, b, c, Block[15], 10, $fe2ce6e0); II (c, d, a, b, Block[ 6], 15, $a3014314); II (b, c, d, a, Block[13], 21, $4e0811a1); II (a, b, c, d, Block[ 4], 6, $f7537e82); II (d, a, b, c, Block[11], 10, $bd3af235); II (c, d, a, b, Block[ 2], 15, $2ad7d2bb); II (b, c, d, a, Block[ 9], 21, $eb86d391); inc(State[0], a); inc(State[1], b); inc(State[2], c); inc(State[3], d); end;
// -----------------------------------------------------------------------------------------------// Initialize given Context procedure MD5Init(var Context: MD5Context); begin with Context do begin State[0] := $67452301; State[1] := $efcdab89; State[2] := $98badcfe; State[3] := $10325476; Count[0] := 0; Count[1] := 0; ZeroMemory(@Buffer, SizeOf(MD5Buffer)); end; end;// Update given Context to include Length bytes of Input procedure MD5Update(var Context: MD5Context; Input: pChar; Length: longword); var Index: longword; PartLen: longword; I: longword; begin with Context do begin Index := (Count[0] shr 3) and $3f; inc(Count[0], Length shl 3); if Count[0] < (Length shl 3) then inc(Count[1]); inc(Count[1], Length shr 29); end; PartLen := 64 - Index; if Length >= PartLen then begin CopyMemory(@Context.Buffer[Index], Input, PartLen); Transform(@Context.Buffer, Context.State); I := PartLen; while I + 63 < Length do begin Transform(@Input[I], Context.State); inc(I, 64); end; Index := 0; end else I := 0; CopyMemory(@Context.Buffer[Index], @Input[I], Length - I); end;// Finalize given Context, create Digest and zeroize Context procedure MD5Final(var Context: MD5Context; var Digest: MD5Digest); var Bits: MD5CBits; Index: longword; PadLen: longword; begin Decode(@Context.Count, @Bits, 2); Index := (Context.Count[0] shr 3) and $3f; if Index < 56 then PadLen := 56 - Index else PadLen := 120 - Index; MD5Update(Context, @PADDING, PadLen); MD5Update(Context, @Bits, 8); Decode(@Context.State, @Digest, 4); ZeroMemory(@Context, SizeOf(MD5Context)); end;// -----------------------------------------------------------------------------------------------// Create digest of given Message function MD5String(M: string): MD5Digest; var Context: MD5Context; begin MD5Init(Context); MD5Update(Context, pChar(M), length(M)); MD5Final(Context, Result); end;// Create digest of file with given Name function MD5File(N: string): MD5Digest; var FileHandle: THandle; MapHandle: THandle; ViewPointer: pointer; Context: MD5Context; begin MD5Init(Context); FileHandle := CreateFile(pChar(N), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN, 0); if FileHandle <> INVALID_HANDLE_VALUE then try MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil); if MapHandle <> 0 then try ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0); if ViewPointer <> nil then try MD5Update(Context, ViewPointer, GetFileSize(FileHandle, nil)); finally UnmapViewOfFile(ViewPointer); end; finally CloseHandle(MapHandle); end; finally CloseHandle(FileHandle); end; MD5Final(Context, Result); end;// Create hex representation of given Digest function MD5Print(D: MD5Digest): string; var I: byte; const Digits: array[0..15] of char = ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'); begin Result := ''; for I := 0 to 15 do Result := Result + Digits[(D[I] shr 4) and $0f] + Digits[D[I] and $0f]; end;// -----------------------------------------------------------------------------------------------// Compare two Digests function MD5Match(D1, D2: MD5Digest): boolean; var I: byte; begin I := 0; Result := TRUE; while Result and (I < 16) do begin Result := D1[I] = D2[I]; inc(I); end; end;end.
interface uses Cryptcon, SysUtils{$IFDEF DELPHI}, Classes, Controls{$ENDIF} {$IFDEF BP7},objects{$ENDIF};Type ULONG32 = record LoWord16: WORD; HiWord16: WORD; end;PULONG32 = ^ULONG32; PLong = ^LongInt;hashDigest = record A: Longint; B: Longint; C: Longint; D: Longint; end;{hashArray}PTR_Hash = ^hashDigest;{$IFDEF DELPHI} TMD5 = class(TComponent) Private { Private declarations } {$ENDIF}{$IFDEF BP7} PTMD5 = ^TMD5; {For BP7 Objects} TMD5 = object(TObject) Public {Since BP7 doesn't support Properties, we make these Public} {$ENDIF} FType : TSourceType; {Source type, whether its a file or ByteArray, or a Pascal String} FInputFilePath: String; {Full Path to Input File} FInputArray: PByte; {Point to input array} FInputString: String; {Input String} FOutputDigest: PTR_Hash; {output MD5 Digest} FSourceLength: LongInt; {input length in BYTES} FActiveBlock: Array[0..15] of LongInt; {the 64Byte block being transformed} FA, FB, FC, FD, FAA, FBB, FCC, FDD: LongInt; {FA..FDD are used during Step 4, the transform. I made them part of the Object to cut down on time used to pass variables.} FpA, FpB, FpC, FpD: PLong; {FIXME! do we need these, or just use the '@' operator?} {Put in for readability} {FF, GG, HH, II are used in Step 4, the transform} Procedure FF(a, b, c, d, x: Pointer; s: BYTE; ac: Longint); Procedure GG(a, b, c, d, x: Pointer; s: BYTE; ac: Longint); Procedure HH(a, b, c, d, x: Pointer; s: BYTE; ac: Longint); Procedure II(a, b, c, d, x: Pointer; s: BYTE; ac: Longint);{$IFDEF DELPHI} protected { Protected declarations } {$ENDIF} public { Public declarations } {Initialize is used in Step 3, this fills FA..FD with init. values and points FpA..FpD to FA..FD} Procedure MD5_Initialize; {this is where all the magic happens} Procedure MD5_Transform; Procedure MD5_Finish; Procedure MD5_Hash_Bytes; { Procedure MD5_Hash_String;(Pascal Style strings???)} Procedure MD5_Hash_File; {This procedure sends the data 64Bytes at a time to MD5_Transform} Procedure MD5_Hash; {$IFDEF DELPHI} Property pInputArray: PByte read FInputArray write FInputArray; Property pOutputArray: PTR_Hash read FOutputDigest write FOutputDigest;{!!See FOutputArray} Published Property InputType: TSourceType read FType write FType; Property InputFilePath: String read FInputFilePath write FInputFilePath; Property InputString: String read FInputString write FInputString; Property InputLength: LongInt read FSourceLength write FSourceLength; {$ENDIF} end;{TMD5}{$IFDEF DELPHI} procedure Register;{register the component to the Delphi toolbar} {$ENDIF}Const {Constants for MD5Transform routine.} S11 = 7; S12 = 12; S13 = 17; S14 = 22; S21 = 5; S22 = 9; S23 = 14; S24 = 20; S31 = 4; S32 = 11; S33 = 16; S34 = 23; S41 = 6; S42 = 10; S43 = 15; S44 = 21;
implementation{This will only work on an intel} {$IFDEF i286} Function ROL(A: Longint; Amount: BYTE): Longint;NEAR; begin inline( $8A/$4E/$04/ { mov cl,[bp+4] } $66/$8B/$46/$06/ { mov eax,[bp+6] } $66/$D3/$C0/ { rol eax,cl } $66/$89/$46/$FC { mov [bp-4],eax } ); end; {$ENDIF}{$IFDEF i386} Function ROL(A: Longint; Amount: BYTE): Longint; Assembler; asm mov cl, Amount rol eax, cl end; {$ENDIF}{$IFDEF DELPHI} procedure Register; {Registers the Component to the toobar, on the tab named 'Crypto'} {Now all a Delphi programmer needs to do is drag n drop to have Blowfish encryption} begin RegisterComponents('Crypto', [TMD5]); end; {$ENDIF} Procedure TMD5.MD5_Initialize; var a, b, c, d: LongInt; begin a := $67452301; b:=$efcdab89; c:=$98badcfe; d:=$10325476; Move(a, FA, 4); FpA := @FA; Move(b, FB, 4); FpB := @FB; Move(c, FC, 4); FpC := @FC; Move(d, FD, 4); FpD := @FD; end;{MD5_Initialize}Procedure TMD5.FF(a, b, c, d, x: Pointer; s: BYTE; ac: Longint); {Purpose: Round 1 of the Transform. Equivalent to a = b + ((a + F(b,c,d) + x + ac) <<< s) Where F(b,c,d) = b And c Or Not(b) And d } var Fret: LongInt; begin Fret := ((PLong(b)^) And (PLong(c)^)) Or ((Not(PLong(b)^)) And (PLong(d)^)); PLong(a)^ := PLong(a)^ + Fret + PLong(x)^ + ac; {NOW DO THE ROTATE LEFT} LongInt(a^):= ROL(LongInt(a^), s); {LongInt(a^):= ( LongInt(a^) SHL s) Or (LongInt(a^) SHR (32-(s)) );} Inc(PLong(a)^, PLong(b)^); end;{FF}Procedure TMD5.GG(a, b, c, d, x: Pointer; s: BYTE; ac: Longint); {Purpose: Round 2 of the Transform. Equivalent to a = b + ((a + G(b,c,d) + x + ac) <<< s) Where G(b,c,d) = b And d Or c Not d } var Gret: LongInt; begin Gret := (PLong(b)^ And PLong(d)^) Or ( PLong(c)^ And (Not PLong(d)^)); PLong(a)^ := PLong(a)^ + Gret + PLong(x)^ + ac; LongInt(a^):= ROL(LongInt(a^), s); {LongInt(a^):= ( LongInt(a^) SHL s) Or (LongInt(a^) SHR (32-(s)) );} Inc(PLong(a)^, PLong(b)^); end;{GG}Procedure TMD5.HH(a, b, c, d, x: Pointer; s: BYTE; ac: Longint); {Purpose: Round 3 of the Transform. Equivalent to a = b + ((a + H(b,c,d) + x + ac) <<< s) Where H(b,c,d) = b Xor c Xor d } var Hret: LongInt; begin Hret := PLong(b)^ Xor PLong(c)^ Xor PLong(d)^; PLong(a)^ := PLong(a)^ + Hret + PLong(x)^ + ac; LongInt(a^):= ROL(LongInt(a^), s); {LongInt(a^):= ( LongInt(a^) SHL s) Or (LongInt(a^) SHR (32-(s)) );} PLong(a)^ := PLong(b)^ + PLong(a)^; end;{HH}Procedure TMD5.II(a, b, c, d, x: Pointer; s: BYTE; ac: Longint); {Purpose: Round 4 of the Transform. Equivalent to a = b + ((a + I(b,c,d) + x + ac) <<< s) Where I(b,c,d) = C Xor (b Or Not(d)) } var Iret: LongInt; begin Iret := (PLong(c)^ Xor (PLong(b)^ Or (Not PLong(d)^))); PLong(a)^ := PLong(a)^ + Iret + PLong(x)^ + ac; LongInt(a^):= ROL(PLong(a)^, s ); { LongInt(a^):= ( LongInt(a^) SHL s) Or (LongInt(a^) SHR (32-(s)) );} PLong(a)^ := PLong(b)^ + PLong(a)^; end;{II}Procedure TMD5.MD5_Transform; {Purpose: Perform Step 4 of the algorithm. This is where all the important stuff happens. This performs the rounds on a 64Byte Block. This procedure should be called in a loop until all input data has been transformed. }begin FAA := FA; FBB := FB; FCC := FC; FDD := FD; { Round 1 } FF (FpA, FpB, FpC, FpD, @FActiveBlock[ 0], S11, $d76aa478); { 1 } FF (FpD, FpA, FpB, FpC, @FActiveBlock[ 1], S12, $e8c7b756); { 2 } FF (FpC, FpD, FpA, FpB, @FActiveBlock[ 2], S13, $242070db); { 3 } FF (FpB, FpC, FpD, FpA, @FActiveBlock[ 3], S14, $c1bdceee); { 4 } FF (FpA, FpB, FpC, FpD, @FActiveBlock[ 4], S11, $f57c0faf); { 5 } FF (FpD, FpA, FpB, FpC, @FActiveBlock[ 5], S12, $4787c62a); { 6 } FF (FpC, FpD, FpA, FpB, @FActiveBlock[ 6], S13, $a8304613); { 7 } FF (FpB, FpC, FpD, FpA, @FActiveBlock[ 7], S14, $fd469501); { 8 } FF (FpA, FpB, FpC, FpD, @FActiveBlock[ 8], S11, $698098d8); { 9 } FF (FpD, FpA, FpB, FpC, @FActiveBlock[ 9], S12, $8b44f7af); { 10 } FF (FpC, FpD, FpA, FpB, @FActiveBlock[10], S13, $ffff5bb1); { 11 } FF (FpB, FpC, FpD, FpA, @FActiveBlock[11], S14, $895cd7be); { 12 } FF (FpA, FpB, FpC, FpD, @FActiveBlock[12], S11, $6b901122); { 13 } FF (FpD, FpA, FpB, FpC, @FActiveBlock[13], S12, $fd987193); { 14 } FF (FpC, FpD, FpA, FpB, @FActiveBlock[14], S13, $a679438e); { 15 } FF (FpB, FpC, FpD, FpA, @FActiveBlock[15], S14, $49b40821); { 16 } { Round 2 } GG (FpA, FpB, FpC, FpD, @FActiveBlock[ 1], S21, $f61e2562); { 17 } GG (FpD, FpA, FpB, FpC, @FActiveBlock[ 6], S22, $c040b340); { 18 } GG (FpC, FpD, FpA, FpB, @FActiveBlock[11], S23, $265e5a51); { 19 } GG (FpB, FpC, FpD, FpA, @FActiveBlock[ 0], S24, $e9b6c7aa); { 20 } GG (FpA, FpB, FpC, FpD, @FActiveBlock[ 5], S21, $d62f105d); { 21 } GG (FpD, FpA, FpB, FpC, @FActiveBlock[10], S22, $2441453); { 22 } GG (FpC, FpD, FpA, FpB, @FActiveBlock[15], S23, $d8a1e681); { 23 } GG (FpB, FpC, FpD, FpA, @FActiveBlock[ 4], S24, $e7d3fbc8); { 24 } GG (FpA, FpB, FpC, FpD, @FActiveBlock[ 9], S21, $21e1cde6); { 25 } GG (FpD, FpA, FpB, FpC, @FActiveBlock[14], S22, $c33707d6); { 26 } GG (FpC, FpD, FpA, FpB, @FActiveBlock[ 3], S23, $f4d50d87); { 27 } GG (FpB, FpC, FpD, FpA, @FActiveBlock[ 8], S24, $455a14ed); { 28 } GG (FpA, FpB, FpC, FpD, @FActiveBlock[13], S21, $a9e3e905); { 29 } GG (FpD, FpA, FpB, FpC, @FActiveBlock[ 2], S22, $fcefa3f8); { 30 } GG (FpC, FpD, FpA, FpB, @FActiveBlock[ 7], S23, $676f02d9); { 31 } GG (FpB, FpC, FpD, FpA, @FActiveBlock[12], S24, $8d2a4c8a); { 32 } { Round 3 } HH (FpA, FpB, FpC, FpD, @FActiveBlock[ 5], S31, $fffa3942); { 33 } HH (FpD, FpA, FpB, FpC, @FActiveBlock[ 8], S32, $8771f681); { 34 } HH (FpC, FpD, FpA, FpB, @FActiveBlock[11], S33, $6d9d6122); { 35 } HH (FpB, FpC, FpD, FpA, @FActiveBlock[14], S34, $fde5380c); { 36 } HH (FpA, FpB, FpC, FpD, @FActiveBlock[ 1], S31, $a4beea44); { 37 } HH (FpD, FpA, FpB, FpC, @FActiveBlock[ 4], S32, $4bdecfa9); { 38 } HH (FpC, FpD, FpA, FpB, @FActiveBlock[ 7], S33, $f6bb4b60); { 39 } HH (FpB, FpC, FpD, FpA, @FActiveBlock[10], S34, $bebfbc70); { 40 } HH (FpA, FpB, FpC, FpD, @FActiveBlock[13], S31, $289b7ec6); { 41 } HH (FpD, FpA, FpB, FpC, @FActiveBlock[ 0], S32, $eaa127fa); { 42 } HH (FpC, FpD, FpA, FpB, @FActiveBlock[ 3], S33, $d4ef3085); { 43 } HH (FpB, FpC, FpD, FpA, @FActiveBlock[ 6], S34, $4881d05); { 44 } HH (FpA, FpB, FpC, FpD, @FActiveBlock[ 9], S31, $d9d4d039); { 45 } HH (FpD, FpA, FpB, FpC, @FActiveBlock[12], S32, $e6db99e5); { 46 } HH (FpC, FpD, FpA, FpB, @FActiveBlock[15], S33, $1fa27cf8); { 47 } HH (FpB, FpC, FpD, FpA, @FActiveBlock[ 2], S34, $c4ac5665); { 48 } { Round 4 } II (FpA, FpB, FpC, FpD, @FActiveBlock[ 0], S41, $f4292244); { 49 } II (FpD, FpA, FpB, FpC, @FActiveBlock[ 7], S42, $432aff97); { 50 } II (FpC, FpD, FpA, FpB, @FActiveBlock[14], S43, $ab9423a7); { 51 } II (FpB, FpC, FpD, FpA, @FActiveBlock[ 5], S44, $fc93a039); { 52 } II (FpA, FpB, FpC, FpD, @FActiveBlock[12], S41, $655b59c3); { 53 } II (FpD, FpA, FpB, FpC, @FActiveBlock[ 3], S42, $8f0ccc92); { 54 } II (FpC, FpD, FpA, FpB, @FActiveBlock[10], S43, $ffeff47d); { 55 } II (FpB, FpC, FpD, FpA, @FActiveBlock[ 1], S44, $85845dd1); { 56 } II (FpA, FpB, FpC, FpD, @FActiveBlock[ 8], S41, $6fa87e4f); { 57 } II (FpD, FpA, FpB, FpC, @FActiveBlock[15], S42, $fe2ce6e0); { 58 } II (FpC, FpD, FpA, FpB, @FActiveBlock[ 6], S43, $a3014314); { 59 } II (FpB, FpC, FpD, FpA, @FActiveBlock[13], S44, $4e0811a1); { 60 } II (FpA, FpB, FpC, FpD, @FActiveBlock[ 4], S41, $f7537e82); { 61 } II (FpD, FpA, FpB, FpC, @FActiveBlock[11], S42, $bd3af235); { 62 } II (FpC, FpD, FpA, FpB, @FActiveBlock[ 2], S43, $2ad7d2bb); { 63 } II (FpB, FpC, FpD, FpA, @FActiveBlock[ 9], S44, $eb86d391); { 64 }
Inc(FA, FAA); Inc(FB, FBB); Inc(FC, FCC); Inc(FD, FDD); { Zeroize sensitive information} FillChar(FActiveBlock, SizeOf(FActiveBlock), #0); end;{TMD5.MD5_Transform} Procedure TMD5.MD5_Hash; var pStr: PChar; begin MD5_Initialize; case FType of SourceFile: begin MD5_Hash_File; end;{SourceFile} SourceByteArray: begin MD5_Hash_Bytes; end;{SourceByteArray} SourceString: begin {Convert Pascal String to Byte Array} {$IFDEF DELPHI} pStr := StrAlloc(Length(FInputString) + 1); try {protect dyanmic memory allocation} StrPCopy(pStr, FInputString); {$ENDIF} {$IFDEF BP7} GetMem(pStr, Length(FInputString)); Move(FInputString[1],pStr^, Length(FInputString)); {$ENDIF} FSourceLength := Length(FInputString); FInputArray := Pointer(pStr); MD5_Hash_Bytes; {$IFDEF DELPHI} finally StrDispose(pStr); end; {$ENDIF} {$IFDEF BP7} FreeMem(pStr,Length(FInputString)); {$ENDIF} end;{SourceString} end;{case} MD5_Finish; end;{TMD5.MD5_Hash}Procedure TMD5.MD5_Hash_Bytes; var Buffer: array[0..4159] of Byte; Count64: Comp; index: longInt; begin Move(FInputArray^, Buffer, FSourceLength); Count64 := FSourceLength * 8; {Save the Length(in bits) before padding} Buffer[FSourceLength] := $80; {Must always pad with at least a '1'} inc(FSourceLength); while (FSourceLength mod 64)<>56 do begin Buffer[FSourceLength] := 0; Inc(FSourceLength); end; Move(Count64,Buffer[FSourceLength],SizeOf(Count64){This better be 64bits}); index := 0; Inc(FSourceLength, 8); repeat Move(Buffer[Index], FActiveBlock, 64); {Flip bytes here on Mac??} MD5_Transform; Inc(Index,64); until Index = FSourceLength; end;{TMD5.Hash_Bytes}Procedure TMD5.MD5_Hash_File; var Buffer:array[0..4159] of BYTE; InputFile: File; Count64: Comp; DoneFile : Boolean; Index: LongInt; NumRead: {$IFDEF DELPHI32}integer {$ELSE}WORD{$ENDIF}; begin DoneFile := False; {$IFDEF DELPHI} AssignFile(InputFile, FInputFilePath); {$ENDIF} {$IFDEF BP7} Assign(InputFile, FInputFilePath); {$ENDIF}Reset(InputFile, 1); Count64 := 0; repeat BlockRead(InputFile,Buffer,4096,NumRead); Count64 := Count64 + NumRead; if NumRead<>4096 {reached end of file} then begin Buffer[NumRead]:= $80; Inc(NumRead); while (NumRead mod 64)<>56 do begin Buffer[ NumRead ] := 0; Inc(NumRead); end; Count64 := Count64 * 8; Move(Count64,Buffer[NumRead],8); Inc(NumRead,8); DoneFile := True; end; Index := 0; repeat Move(Buffer[Index], FActiveBlock, 64); {Flip bytes here on a Mac(I think)} MD5_Transform; Inc(Index,64); until Index = NumRead; until DoneFile; {$IFDEF DELPHI} CloseFile(InputFile); {$ENDIF} {$IFDEF BP7} Close(InputFile); {$ENDIF} end;{TMD5.MD5_Hash_File} Procedure TMD5.MD5_Finish; begin FOutputDigest^.A := LongInt(FpA^); FOutputDigest^.B := LongInt(FpB^); FOutputDigest^.C := LongInt(FpC^); FOutputDigest^.D := LongInt(FpD^); end; end.
--------------------------------------------------------------------------------
1、MD5算法是对输入的数据进行补位,使得如果数据位长度LEN对512求余的结果是448。
即数据扩展至K*512+448位。即K*64+56个字节,K为整数。
具体补位操作:补一个1,然后补0至满足上述要求2、补数据长度:
用一个64位的数字表示数据的原始长度B,把B用两个32位数表示。这时,数据就被填
补成长度为512位的倍数。3. 初始化MD5参数
四个32位整数 (A,B,C,D) 用来计算信息摘要,初始化使用的是十六进制表示的数字A=0X01234567
B=0X89abcdef
C=0Xfedcba98
D=0X765432104、处理位操作函数X,Y,Z为32位整数。
F(X,Y,Z) = X&Y|NOT(X)&Z
G(X,Y,Z) = X&Z|Y¬(Z)
H(X,Y,Z) = X xor Y xor Z
I(X,Y,Z) = Y xor (X|not(Z))5、主要变换过程:
使用常数组T[1 ... 64], T[i]为32位整数用16进制表示,数据用16个32位的整
数数组M[]表示。具体过程如下:/* 处理数据原文 */
For i = 0 to N/16-1 do/*每一次,把数据原文存放在16个元素的数组X中. */
For j = 0 to 15 do
Set X[j] to M[i*16+j].
end /结束对J的循环/* Save A as AA, B as BB, C as CC, and D as DD. */
AA = A
BB = B
CC = C
DD = D/* 第1轮*/
/* 以 [abcd k s i]表示如下操作
a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). *//* Do the following 16 operations. */
[ABCD 0 7 1] [DABC 1 12 2] [CDAB 2 17 3] [BCDA 3 22 4]
[ABCD 4 7 5] [DABC 5 12 6] [CDAB 6 17 7] [BCDA 7 22 8]
[ABCD 8 7 9] [DABC 9 12 10] [CDAB 10 17 11] [BCDA 11 22 12]
[ABCD 12 7 13] [DABC 13 12 14] [CDAB 14 17 15] [BCDA 15 22 16]/* 第2轮* */
/* 以 [abcd k s i]表示如下操作
a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */
/* Do the following 16 operations. */
[ABCD 1 5 17] [DABC 6 9 18] [CDAB 11 14 19] [BCDA 0 20 20]
[ABCD 5 5 21] [DABC 10 9 22] [CDAB 15 14 23] [BCDA 4 20 24]
[ABCD 9 5 25] [DABC 14 9 26] [CDAB 3 14 27] [BCDA 8 20 28]
[ABCD 13 5 29] [DABC 2 9 30] [CDAB 7 14 31] [BCDA 12 20 32]/* 第3轮*/
/* 以 [abcd k s i]表示如下操作
a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */
/* Do the following 16 operations. */
[ABCD 5 4 33] [DABC 8 11 34] [CDAB 11 16 35] [BCDA 14 23 36]
[ABCD 1 4 37] [DABC 4 11 38] [CDAB 7 16 39] [BCDA 10 23 40]
[ABCD 13 4 41] [DABC 0 11 42] [CDAB 3 16 43] [BCDA 6 23 44]
[ABCD 9 4 45] [DABC 12 11 46] [CDAB 15 16 47] [BCDA 2 23 48]/* 第4轮*/
/* 以 [abcd k s i]表示如下操作
a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */
/* Do the following 16 operations. */
[ABCD 0 6 49] [DABC 7 10 50] [CDAB 14 15 51] [BCDA 5 21 52]
[ABCD 12 6 53] [DABC 3 10 54] [CDAB 10 15 55] [BCDA 1 21 56]
[ABCD 8 6 57] [DABC 15 10 58] [CDAB 6 15 59] [BCDA 13 21 60]
[ABCD 4 6 61] [DABC 11 10 62] [CDAB 2 15 63] [BCDA 9 21 64]/* 然后进行如下操作 */
A = A + AA
B = B + BB
C = C + CC
D = D + DDend /* 结束对I的循环*/
6、输出结果。
unit md5;// -----------------------------------------------------------------------------------------------
INTERFACE
// -----------------------------------------------------------------------------------------------uses
Windows;type
MD5Count = array[0..1] of DWORD;
MD5State = array[0..3] of DWORD;
MD5Block = array[0..15] of DWORD;
MD5CBits = array[0..7] of byte;
MD5Digest = array[0..15] of byte;
MD5Buffer = array[0..63] of byte;
MD5Context = record
State: MD5State;
Count: MD5Count;
Buffer: MD5Buffer;
end;procedure MD5Init(var Context: MD5Context);
procedure MD5Update(var Context: MD5Context; Input: pChar; Length: longword);
procedure MD5Final(var Context: MD5Context; var Digest: MD5Digest);function MD5String(M: string): MD5Digest;
function MD5File(N: string): MD5Digest;
function MD5Print(D: MD5Digest): string;function MD5Match(D1, D2: MD5Digest): boolean;// -----------------------------------------------------------------------------------------------
IMPLEMENTATION
// -----------------------------------------------------------------------------------------------var
PADDING: MD5Buffer = (
$80, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00,
$00, $00, $00, $00, $00, $00, $00, $00
);function F(x, y, z: DWORD): DWORD;
begin
Result := (x and y) or ((not x) and z);
end;function G(x, y, z: DWORD): DWORD;
begin
Result := (x and z) or (y and (not z));
end;function H(x, y, z: DWORD): DWORD;
begin
Result := x xor y xor z;
end;function I(x, y, z: DWORD): DWORD;
begin
Result := y xor (x or (not z));
end;procedure rot(var x: DWORD; n: BYTE);
begin
x := (x shl n) or (x shr (32 - n));
end;procedure FF(var a: DWORD; b, c, d, x: DWORD; s: BYTE; ac: DWORD);
begin
inc(a, F(b, c, d) + x + ac);
rot(a, s);
inc(a, b);
end;procedure GG(var a: DWORD; b, c, d, x: DWORD; s: BYTE; ac: DWORD);
begin
inc(a, G(b, c, d) + x + ac);
rot(a, s);
inc(a, b);
end;procedure HH(var a: DWORD; b, c, d, x: DWORD; s: BYTE; ac: DWORD);
begin
inc(a, H(b, c, d) + x + ac);
rot(a, s);
inc(a, b);
end;procedure II(var a: DWORD; b, c, d, x: DWORD; s: BYTE; ac: DWORD);
begin
inc(a, I(b, c, d) + x + ac);
rot(a, s);
inc(a, b);
end;// -----------------------------------------------------------------------------------------------// Encode Count bytes at Source into (Count / 4) DWORDs at Target
procedure Encode(Source, Target: pointer; Count: longword);
var
S: PByte;
T: PDWORD;
I: longword;
begin
S := Source;
T := Target;
for I := 1 to Count div 4 do begin
T^ := S^;
inc(S);
T^ := T^ or (S^ shl 8);
inc(S);
T^ := T^ or (S^ shl 16);
inc(S);
T^ := T^ or (S^ shl 24);
inc(S);
inc(T);
end;
end;// Decode Count DWORDs at Source into (Count * 4) Bytes at Target
procedure Decode(Source, Target: pointer; Count: longword);
var
S: PDWORD;
T: PByte;
I: longword;
begin
S := Source;
T := Target;
for I := 1 to Count do begin
T^ := S^ and $ff;
inc(T);
T^ := (S^ shr 8) and $ff;
inc(T);
T^ := (S^ shr 16) and $ff;
inc(T);
T^ := (S^ shr 24) and $ff;
inc(T);
inc(S);
end;
end;// Transform State according to first 64 bytes at Buffer
procedure Transform(Buffer: pointer; var State: MD5State);
var
a, b, c, d: DWORD;
Block: MD5Block;
begin
Encode(Buffer, @Block, 64);
a := State[0];
b := State[1];
c := State[2];
d := State[3];
FF (a, b, c, d, Block[ 0], 7, $d76aa478);
FF (d, a, b, c, Block[ 1], 12, $e8c7b756);
FF (c, d, a, b, Block[ 2], 17, $242070db);
FF (b, c, d, a, Block[ 3], 22, $c1bdceee);
FF (a, b, c, d, Block[ 4], 7, $f57c0faf);
FF (d, a, b, c, Block[ 5], 12, $4787c62a);
FF (c, d, a, b, Block[ 6], 17, $a8304613);
FF (b, c, d, a, Block[ 7], 22, $fd469501);
FF (a, b, c, d, Block[ 8], 7, $698098d8);
FF (d, a, b, c, Block[ 9], 12, $8b44f7af);
FF (c, d, a, b, Block[10], 17, $ffff5bb1);
FF (b, c, d, a, Block[11], 22, $895cd7be);
FF (a, b, c, d, Block[12], 7, $6b901122);
FF (d, a, b, c, Block[13], 12, $fd987193);
FF (c, d, a, b, Block[14], 17, $a679438e);
FF (b, c, d, a, Block[15], 22, $49b40821);
GG (a, b, c, d, Block[ 1], 5, $f61e2562);
GG (d, a, b, c, Block[ 6], 9, $c040b340);
GG (c, d, a, b, Block[11], 14, $265e5a51);
GG (b, c, d, a, Block[ 0], 20, $e9b6c7aa);
GG (a, b, c, d, Block[ 5], 5, $d62f105d);
GG (d, a, b, c, Block[10], 9, $2441453);
GG (c, d, a, b, Block[15], 14, $d8a1e681);
GG (b, c, d, a, Block[ 4], 20, $e7d3fbc8);
GG (a, b, c, d, Block[ 9], 5, $21e1cde6);
GG (d, a, b, c, Block[14], 9, $c33707d6);
GG (c, d, a, b, Block[ 3], 14, $f4d50d87);
GG (b, c, d, a, Block[ 8], 20, $455a14ed);
GG (a, b, c, d, Block[13], 5, $a9e3e905);
GG (d, a, b, c, Block[ 2], 9, $fcefa3f8);
GG (c, d, a, b, Block[ 7], 14, $676f02d9);
GG (b, c, d, a, Block[12], 20, $8d2a4c8a);
HH (a, b, c, d, Block[ 5], 4, $fffa3942);
HH (d, a, b, c, Block[ 8], 11, $8771f681);
HH (c, d, a, b, Block[11], 16, $6d9d6122);
HH (b, c, d, a, Block[14], 23, $fde5380c);
HH (a, b, c, d, Block[ 1], 4, $a4beea44);
HH (d, a, b, c, Block[ 4], 11, $4bdecfa9);
HH (c, d, a, b, Block[ 7], 16, $f6bb4b60);
HH (b, c, d, a, Block[10], 23, $bebfbc70);
HH (a, b, c, d, Block[13], 4, $289b7ec6);
HH (d, a, b, c, Block[ 0], 11, $eaa127fa);
HH (c, d, a, b, Block[ 3], 16, $d4ef3085);
HH (b, c, d, a, Block[ 6], 23, $4881d05);
HH (a, b, c, d, Block[ 9], 4, $d9d4d039);
HH (d, a, b, c, Block[12], 11, $e6db99e5);
HH (c, d, a, b, Block[15], 16, $1fa27cf8);
HH (b, c, d, a, Block[ 2], 23, $c4ac5665);
II (a, b, c, d, Block[ 0], 6, $f4292244);
II (d, a, b, c, Block[ 7], 10, $432aff97);
II (c, d, a, b, Block[14], 15, $ab9423a7);
II (b, c, d, a, Block[ 5], 21, $fc93a039);
II (a, b, c, d, Block[12], 6, $655b59c3);
II (d, a, b, c, Block[ 3], 10, $8f0ccc92);
II (c, d, a, b, Block[10], 15, $ffeff47d);
II (b, c, d, a, Block[ 1], 21, $85845dd1);
II (a, b, c, d, Block[ 8], 6, $6fa87e4f);
II (d, a, b, c, Block[15], 10, $fe2ce6e0);
II (c, d, a, b, Block[ 6], 15, $a3014314);
II (b, c, d, a, Block[13], 21, $4e0811a1);
II (a, b, c, d, Block[ 4], 6, $f7537e82);
II (d, a, b, c, Block[11], 10, $bd3af235);
II (c, d, a, b, Block[ 2], 15, $2ad7d2bb);
II (b, c, d, a, Block[ 9], 21, $eb86d391);
inc(State[0], a);
inc(State[1], b);
inc(State[2], c);
inc(State[3], d);
end;
// -----------------------------------------------------------------------------------------------// Initialize given Context
procedure MD5Init(var Context: MD5Context);
begin
with Context do begin
State[0] := $67452301;
State[1] := $efcdab89;
State[2] := $98badcfe;
State[3] := $10325476;
Count[0] := 0;
Count[1] := 0;
ZeroMemory(@Buffer, SizeOf(MD5Buffer));
end;
end;// Update given Context to include Length bytes of Input
procedure MD5Update(var Context: MD5Context; Input: pChar; Length: longword);
var
Index: longword;
PartLen: longword;
I: longword;
begin
with Context do begin
Index := (Count[0] shr 3) and $3f;
inc(Count[0], Length shl 3);
if Count[0] < (Length shl 3) then inc(Count[1]);
inc(Count[1], Length shr 29);
end;
PartLen := 64 - Index;
if Length >= PartLen then begin
CopyMemory(@Context.Buffer[Index], Input, PartLen);
Transform(@Context.Buffer, Context.State);
I := PartLen;
while I + 63 < Length do begin
Transform(@Input[I], Context.State);
inc(I, 64);
end;
Index := 0;
end else I := 0;
CopyMemory(@Context.Buffer[Index], @Input[I], Length - I);
end;// Finalize given Context, create Digest and zeroize Context
procedure MD5Final(var Context: MD5Context; var Digest: MD5Digest);
var
Bits: MD5CBits;
Index: longword;
PadLen: longword;
begin
Decode(@Context.Count, @Bits, 2);
Index := (Context.Count[0] shr 3) and $3f;
if Index < 56 then PadLen := 56 - Index else PadLen := 120 - Index;
MD5Update(Context, @PADDING, PadLen);
MD5Update(Context, @Bits, 8);
Decode(@Context.State, @Digest, 4);
ZeroMemory(@Context, SizeOf(MD5Context));
end;// -----------------------------------------------------------------------------------------------// Create digest of given Message
function MD5String(M: string): MD5Digest;
var
Context: MD5Context;
begin
MD5Init(Context);
MD5Update(Context, pChar(M), length(M));
MD5Final(Context, Result);
end;// Create digest of file with given Name
function MD5File(N: string): MD5Digest;
var
FileHandle: THandle;
MapHandle: THandle;
ViewPointer: pointer;
Context: MD5Context;
begin
MD5Init(Context);
FileHandle := CreateFile(pChar(N), GENERIC_READ, FILE_SHARE_READ or FILE_SHARE_WRITE,
nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN, 0);
if FileHandle <> INVALID_HANDLE_VALUE then try
MapHandle := CreateFileMapping(FileHandle, nil, PAGE_READONLY, 0, 0, nil);
if MapHandle <> 0 then try
ViewPointer := MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0);
if ViewPointer <> nil then try
MD5Update(Context, ViewPointer, GetFileSize(FileHandle, nil));
finally
UnmapViewOfFile(ViewPointer);
end;
finally
CloseHandle(MapHandle);
end;
finally
CloseHandle(FileHandle);
end;
MD5Final(Context, Result);
end;// Create hex representation of given Digest
function MD5Print(D: MD5Digest): string;
var
I: byte;
const
Digits: array[0..15] of char =
('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f');
begin
Result := '';
for I := 0 to 15 do Result := Result + Digits[(D[I] shr 4) and $0f] + Digits[D[I] and $0f];
end;// -----------------------------------------------------------------------------------------------// Compare two Digests
function MD5Match(D1, D2: MD5Digest): boolean;
var
I: byte;
begin
I := 0;
Result := TRUE;
while Result and (I < 16) do begin
Result := D1[I] = D2[I];
inc(I);
end;
end;end.
uses Cryptcon, SysUtils{$IFDEF DELPHI}, Classes, Controls{$ENDIF}
{$IFDEF BP7},objects{$ENDIF};Type
ULONG32 = record
LoWord16: WORD;
HiWord16: WORD;
end;PULONG32 = ^ULONG32;
PLong = ^LongInt;hashDigest = record
A: Longint;
B: Longint;
C: Longint;
D: Longint;
end;{hashArray}PTR_Hash = ^hashDigest;{$IFDEF DELPHI}
TMD5 = class(TComponent)
Private
{ Private declarations }
{$ENDIF}{$IFDEF BP7}
PTMD5 = ^TMD5; {For BP7 Objects}
TMD5 = object(TObject)
Public {Since BP7 doesn't support Properties, we make these Public}
{$ENDIF} FType : TSourceType; {Source type, whether its a file or ByteArray, or
a Pascal String}
FInputFilePath: String; {Full Path to Input File}
FInputArray: PByte; {Point to input array}
FInputString: String; {Input String}
FOutputDigest: PTR_Hash; {output MD5 Digest}
FSourceLength: LongInt; {input length in BYTES}
FActiveBlock: Array[0..15] of LongInt; {the 64Byte block being transformed}
FA, FB, FC, FD, FAA, FBB, FCC, FDD: LongInt;
{FA..FDD are used during Step 4, the transform. I made them part of the
Object to cut down on time used to pass variables.}
FpA, FpB, FpC, FpD: PLong;
{FIXME! do we need these, or just use the '@' operator?}
{Put in for readability}
{FF, GG, HH, II are used in Step 4, the transform}
Procedure FF(a, b, c, d, x: Pointer; s: BYTE; ac: Longint);
Procedure GG(a, b, c, d, x: Pointer; s: BYTE; ac: Longint);
Procedure HH(a, b, c, d, x: Pointer; s: BYTE; ac: Longint);
Procedure II(a, b, c, d, x: Pointer; s: BYTE; ac: Longint);{$IFDEF DELPHI}
protected
{ Protected declarations }
{$ENDIF}
public
{ Public declarations }
{Initialize is used in Step 3, this fills FA..FD with init. values
and points FpA..FpD to FA..FD}
Procedure MD5_Initialize;
{this is where all the magic happens}
Procedure MD5_Transform;
Procedure MD5_Finish;
Procedure MD5_Hash_Bytes;
{ Procedure MD5_Hash_String;(Pascal Style strings???)}
Procedure MD5_Hash_File;
{This procedure sends the data 64Bytes at a time to MD5_Transform}
Procedure MD5_Hash;
{$IFDEF DELPHI}
Property pInputArray: PByte read FInputArray write FInputArray;
Property pOutputArray: PTR_Hash read FOutputDigest write FOutputDigest;{!!See FOutputArray}
Published
Property InputType: TSourceType read FType write FType;
Property InputFilePath: String read FInputFilePath write FInputFilePath;
Property InputString: String read FInputString write FInputString;
Property InputLength: LongInt read FSourceLength write FSourceLength;
{$ENDIF}
end;{TMD5}{$IFDEF DELPHI}
procedure Register;{register the component to the Delphi toolbar}
{$ENDIF}Const
{Constants for MD5Transform routine.}
S11 = 7;
S12 = 12;
S13 = 17;
S14 = 22;
S21 = 5;
S22 = 9;
S23 = 14;
S24 = 20;
S31 = 4;
S32 = 11;
S33 = 16;
S34 = 23;
S41 = 6;
S42 = 10;
S43 = 15;
S44 = 21;
{$IFDEF i286}
Function ROL(A: Longint; Amount: BYTE): Longint;NEAR;
begin
inline(
$8A/$4E/$04/ { mov cl,[bp+4] }
$66/$8B/$46/$06/ { mov eax,[bp+6] }
$66/$D3/$C0/ { rol eax,cl }
$66/$89/$46/$FC { mov [bp-4],eax }
);
end;
{$ENDIF}{$IFDEF i386}
Function ROL(A: Longint; Amount: BYTE): Longint; Assembler;
asm
mov cl, Amount
rol eax, cl
end;
{$ENDIF}{$IFDEF DELPHI}
procedure Register;
{Registers the Component to the toobar, on the tab named 'Crypto'}
{Now all a Delphi programmer needs to do is drag n drop to have
Blowfish encryption}
begin
RegisterComponents('Crypto', [TMD5]);
end;
{$ENDIF}
Procedure TMD5.MD5_Initialize;
var
a, b, c, d: LongInt;
begin
a := $67452301; b:=$efcdab89; c:=$98badcfe; d:=$10325476;
Move(a, FA, 4); FpA := @FA;
Move(b, FB, 4); FpB := @FB;
Move(c, FC, 4); FpC := @FC;
Move(d, FD, 4); FpD := @FD;
end;{MD5_Initialize}Procedure TMD5.FF(a, b, c, d, x: Pointer; s: BYTE; ac: Longint);
{Purpose: Round 1 of the Transform.
Equivalent to a = b + ((a + F(b,c,d) + x + ac) <<< s)
Where F(b,c,d) = b And c Or Not(b) And d
}
var
Fret: LongInt;
begin
Fret := ((PLong(b)^) And (PLong(c)^)) Or ((Not(PLong(b)^)) And (PLong(d)^));
PLong(a)^ := PLong(a)^ + Fret + PLong(x)^ + ac;
{NOW DO THE ROTATE LEFT}
LongInt(a^):= ROL(LongInt(a^), s);
{LongInt(a^):= ( LongInt(a^) SHL s) Or (LongInt(a^) SHR (32-(s)) );}
Inc(PLong(a)^, PLong(b)^);
end;{FF}Procedure TMD5.GG(a, b, c, d, x: Pointer; s: BYTE; ac: Longint);
{Purpose: Round 2 of the Transform.
Equivalent to a = b + ((a + G(b,c,d) + x + ac) <<< s)
Where G(b,c,d) = b And d Or c Not d
}
var
Gret: LongInt;
begin
Gret := (PLong(b)^ And PLong(d)^) Or ( PLong(c)^ And (Not PLong(d)^));
PLong(a)^ := PLong(a)^ + Gret + PLong(x)^ + ac;
LongInt(a^):= ROL(LongInt(a^), s);
{LongInt(a^):= ( LongInt(a^) SHL s) Or (LongInt(a^) SHR (32-(s)) );}
Inc(PLong(a)^, PLong(b)^);
end;{GG}Procedure TMD5.HH(a, b, c, d, x: Pointer; s: BYTE; ac: Longint);
{Purpose: Round 3 of the Transform.
Equivalent to a = b + ((a + H(b,c,d) + x + ac) <<< s)
Where H(b,c,d) = b Xor c Xor d
}
var
Hret: LongInt;
begin
Hret := PLong(b)^ Xor PLong(c)^ Xor PLong(d)^;
PLong(a)^ := PLong(a)^ + Hret + PLong(x)^ + ac;
LongInt(a^):= ROL(LongInt(a^), s);
{LongInt(a^):= ( LongInt(a^) SHL s) Or (LongInt(a^) SHR (32-(s)) );}
PLong(a)^ := PLong(b)^ + PLong(a)^;
end;{HH}Procedure TMD5.II(a, b, c, d, x: Pointer; s: BYTE; ac: Longint);
{Purpose: Round 4 of the Transform.
Equivalent to a = b + ((a + I(b,c,d) + x + ac) <<< s)
Where I(b,c,d) = C Xor (b Or Not(d))
}
var
Iret: LongInt;
begin
Iret := (PLong(c)^ Xor (PLong(b)^ Or (Not PLong(d)^)));
PLong(a)^ := PLong(a)^ + Iret + PLong(x)^ + ac;
LongInt(a^):= ROL(PLong(a)^, s );
{ LongInt(a^):= ( LongInt(a^) SHL s) Or (LongInt(a^) SHR (32-(s)) );}
PLong(a)^ := PLong(b)^ + PLong(a)^;
end;{II}Procedure TMD5.MD5_Transform;
{Purpose: Perform Step 4 of the algorithm. This is where all the important
stuff happens. This performs the rounds on a 64Byte Block. This
procedure should be called in a loop until all input data has been
transformed.
}begin
FAA := FA;
FBB := FB;
FCC := FC;
FDD := FD; { Round 1 }
FF (FpA, FpB, FpC, FpD, @FActiveBlock[ 0], S11, $d76aa478); { 1 }
FF (FpD, FpA, FpB, FpC, @FActiveBlock[ 1], S12, $e8c7b756); { 2 }
FF (FpC, FpD, FpA, FpB, @FActiveBlock[ 2], S13, $242070db); { 3 }
FF (FpB, FpC, FpD, FpA, @FActiveBlock[ 3], S14, $c1bdceee); { 4 }
FF (FpA, FpB, FpC, FpD, @FActiveBlock[ 4], S11, $f57c0faf); { 5 }
FF (FpD, FpA, FpB, FpC, @FActiveBlock[ 5], S12, $4787c62a); { 6 }
FF (FpC, FpD, FpA, FpB, @FActiveBlock[ 6], S13, $a8304613); { 7 }
FF (FpB, FpC, FpD, FpA, @FActiveBlock[ 7], S14, $fd469501); { 8 }
FF (FpA, FpB, FpC, FpD, @FActiveBlock[ 8], S11, $698098d8); { 9 }
FF (FpD, FpA, FpB, FpC, @FActiveBlock[ 9], S12, $8b44f7af); { 10 }
FF (FpC, FpD, FpA, FpB, @FActiveBlock[10], S13, $ffff5bb1); { 11 }
FF (FpB, FpC, FpD, FpA, @FActiveBlock[11], S14, $895cd7be); { 12 }
FF (FpA, FpB, FpC, FpD, @FActiveBlock[12], S11, $6b901122); { 13 }
FF (FpD, FpA, FpB, FpC, @FActiveBlock[13], S12, $fd987193); { 14 }
FF (FpC, FpD, FpA, FpB, @FActiveBlock[14], S13, $a679438e); { 15 }
FF (FpB, FpC, FpD, FpA, @FActiveBlock[15], S14, $49b40821); { 16 } { Round 2 }
GG (FpA, FpB, FpC, FpD, @FActiveBlock[ 1], S21, $f61e2562); { 17 }
GG (FpD, FpA, FpB, FpC, @FActiveBlock[ 6], S22, $c040b340); { 18 }
GG (FpC, FpD, FpA, FpB, @FActiveBlock[11], S23, $265e5a51); { 19 }
GG (FpB, FpC, FpD, FpA, @FActiveBlock[ 0], S24, $e9b6c7aa); { 20 }
GG (FpA, FpB, FpC, FpD, @FActiveBlock[ 5], S21, $d62f105d); { 21 }
GG (FpD, FpA, FpB, FpC, @FActiveBlock[10], S22, $2441453); { 22 }
GG (FpC, FpD, FpA, FpB, @FActiveBlock[15], S23, $d8a1e681); { 23 }
GG (FpB, FpC, FpD, FpA, @FActiveBlock[ 4], S24, $e7d3fbc8); { 24 }
GG (FpA, FpB, FpC, FpD, @FActiveBlock[ 9], S21, $21e1cde6); { 25 }
GG (FpD, FpA, FpB, FpC, @FActiveBlock[14], S22, $c33707d6); { 26 }
GG (FpC, FpD, FpA, FpB, @FActiveBlock[ 3], S23, $f4d50d87); { 27 }
GG (FpB, FpC, FpD, FpA, @FActiveBlock[ 8], S24, $455a14ed); { 28 }
GG (FpA, FpB, FpC, FpD, @FActiveBlock[13], S21, $a9e3e905); { 29 }
GG (FpD, FpA, FpB, FpC, @FActiveBlock[ 2], S22, $fcefa3f8); { 30 }
GG (FpC, FpD, FpA, FpB, @FActiveBlock[ 7], S23, $676f02d9); { 31 }
GG (FpB, FpC, FpD, FpA, @FActiveBlock[12], S24, $8d2a4c8a); { 32 } { Round 3 }
HH (FpA, FpB, FpC, FpD, @FActiveBlock[ 5], S31, $fffa3942); { 33 }
HH (FpD, FpA, FpB, FpC, @FActiveBlock[ 8], S32, $8771f681); { 34 }
HH (FpC, FpD, FpA, FpB, @FActiveBlock[11], S33, $6d9d6122); { 35 }
HH (FpB, FpC, FpD, FpA, @FActiveBlock[14], S34, $fde5380c); { 36 }
HH (FpA, FpB, FpC, FpD, @FActiveBlock[ 1], S31, $a4beea44); { 37 }
HH (FpD, FpA, FpB, FpC, @FActiveBlock[ 4], S32, $4bdecfa9); { 38 }
HH (FpC, FpD, FpA, FpB, @FActiveBlock[ 7], S33, $f6bb4b60); { 39 }
HH (FpB, FpC, FpD, FpA, @FActiveBlock[10], S34, $bebfbc70); { 40 }
HH (FpA, FpB, FpC, FpD, @FActiveBlock[13], S31, $289b7ec6); { 41 }
HH (FpD, FpA, FpB, FpC, @FActiveBlock[ 0], S32, $eaa127fa); { 42 }
HH (FpC, FpD, FpA, FpB, @FActiveBlock[ 3], S33, $d4ef3085); { 43 }
HH (FpB, FpC, FpD, FpA, @FActiveBlock[ 6], S34, $4881d05); { 44 }
HH (FpA, FpB, FpC, FpD, @FActiveBlock[ 9], S31, $d9d4d039); { 45 }
HH (FpD, FpA, FpB, FpC, @FActiveBlock[12], S32, $e6db99e5); { 46 }
HH (FpC, FpD, FpA, FpB, @FActiveBlock[15], S33, $1fa27cf8); { 47 }
HH (FpB, FpC, FpD, FpA, @FActiveBlock[ 2], S34, $c4ac5665); { 48 } { Round 4 }
II (FpA, FpB, FpC, FpD, @FActiveBlock[ 0], S41, $f4292244); { 49 }
II (FpD, FpA, FpB, FpC, @FActiveBlock[ 7], S42, $432aff97); { 50 }
II (FpC, FpD, FpA, FpB, @FActiveBlock[14], S43, $ab9423a7); { 51 }
II (FpB, FpC, FpD, FpA, @FActiveBlock[ 5], S44, $fc93a039); { 52 }
II (FpA, FpB, FpC, FpD, @FActiveBlock[12], S41, $655b59c3); { 53 }
II (FpD, FpA, FpB, FpC, @FActiveBlock[ 3], S42, $8f0ccc92); { 54 }
II (FpC, FpD, FpA, FpB, @FActiveBlock[10], S43, $ffeff47d); { 55 }
II (FpB, FpC, FpD, FpA, @FActiveBlock[ 1], S44, $85845dd1); { 56 }
II (FpA, FpB, FpC, FpD, @FActiveBlock[ 8], S41, $6fa87e4f); { 57 }
II (FpD, FpA, FpB, FpC, @FActiveBlock[15], S42, $fe2ce6e0); { 58 }
II (FpC, FpD, FpA, FpB, @FActiveBlock[ 6], S43, $a3014314); { 59 }
II (FpB, FpC, FpD, FpA, @FActiveBlock[13], S44, $4e0811a1); { 60 }
II (FpA, FpB, FpC, FpD, @FActiveBlock[ 4], S41, $f7537e82); { 61 }
II (FpD, FpA, FpB, FpC, @FActiveBlock[11], S42, $bd3af235); { 62 }
II (FpC, FpD, FpA, FpB, @FActiveBlock[ 2], S43, $2ad7d2bb); { 63 }
II (FpB, FpC, FpD, FpA, @FActiveBlock[ 9], S44, $eb86d391); { 64 }
Inc(FA, FAA);
Inc(FB, FBB);
Inc(FC, FCC);
Inc(FD, FDD);
{ Zeroize sensitive information}
FillChar(FActiveBlock, SizeOf(FActiveBlock), #0);
end;{TMD5.MD5_Transform}
Procedure TMD5.MD5_Hash;
var
pStr: PChar;
begin
MD5_Initialize;
case FType of
SourceFile:
begin
MD5_Hash_File;
end;{SourceFile}
SourceByteArray:
begin
MD5_Hash_Bytes;
end;{SourceByteArray}
SourceString:
begin
{Convert Pascal String to Byte Array}
{$IFDEF DELPHI}
pStr := StrAlloc(Length(FInputString) + 1);
try {protect dyanmic memory allocation}
StrPCopy(pStr, FInputString);
{$ENDIF}
{$IFDEF BP7}
GetMem(pStr, Length(FInputString));
Move(FInputString[1],pStr^, Length(FInputString));
{$ENDIF}
FSourceLength := Length(FInputString);
FInputArray := Pointer(pStr);
MD5_Hash_Bytes;
{$IFDEF DELPHI}
finally
StrDispose(pStr);
end;
{$ENDIF}
{$IFDEF BP7}
FreeMem(pStr,Length(FInputString));
{$ENDIF}
end;{SourceString}
end;{case}
MD5_Finish;
end;{TMD5.MD5_Hash}Procedure TMD5.MD5_Hash_Bytes;
var
Buffer: array[0..4159] of Byte;
Count64: Comp;
index: longInt;
begin
Move(FInputArray^, Buffer, FSourceLength);
Count64 := FSourceLength * 8; {Save the Length(in bits) before padding}
Buffer[FSourceLength] := $80; {Must always pad with at least a '1'}
inc(FSourceLength); while (FSourceLength mod 64)<>56 do begin
Buffer[FSourceLength] := 0;
Inc(FSourceLength);
end;
Move(Count64,Buffer[FSourceLength],SizeOf(Count64){This better be 64bits});
index := 0;
Inc(FSourceLength, 8);
repeat
Move(Buffer[Index], FActiveBlock, 64);
{Flip bytes here on Mac??}
MD5_Transform;
Inc(Index,64);
until Index = FSourceLength;
end;{TMD5.Hash_Bytes}Procedure TMD5.MD5_Hash_File;
var
Buffer:array[0..4159] of BYTE;
InputFile: File;
Count64: Comp;
DoneFile : Boolean;
Index: LongInt;
NumRead: {$IFDEF DELPHI32}integer {$ELSE}WORD{$ENDIF};
begin
DoneFile := False;
{$IFDEF DELPHI}
AssignFile(InputFile, FInputFilePath);
{$ENDIF}
{$IFDEF BP7}
Assign(InputFile, FInputFilePath);
{$ENDIF}Reset(InputFile, 1);
Count64 := 0;
repeat
BlockRead(InputFile,Buffer,4096,NumRead);
Count64 := Count64 + NumRead;
if NumRead<>4096 {reached end of file}
then begin
Buffer[NumRead]:= $80;
Inc(NumRead);
while (NumRead mod 64)<>56
do begin
Buffer[ NumRead ] := 0;
Inc(NumRead);
end;
Count64 := Count64 * 8;
Move(Count64,Buffer[NumRead],8);
Inc(NumRead,8);
DoneFile := True;
end;
Index := 0;
repeat
Move(Buffer[Index], FActiveBlock, 64);
{Flip bytes here on a Mac(I think)} MD5_Transform;
Inc(Index,64);
until Index = NumRead;
until DoneFile;
{$IFDEF DELPHI}
CloseFile(InputFile);
{$ENDIF}
{$IFDEF BP7}
Close(InputFile);
{$ENDIF}
end;{TMD5.MD5_Hash_File}
Procedure TMD5.MD5_Finish;
begin
FOutputDigest^.A := LongInt(FpA^);
FOutputDigest^.B := LongInt(FpB^);
FOutputDigest^.C := LongInt(FpC^);
FOutputDigest^.D := LongInt(FpD^);
end;
end.
http://www.fichtner.net/delphi/md5.delphi.phtml