|
@@ -1,6 +1,6 @@
|
|
|
{
|
|
|
This file is part of the Free Pascal packages.
|
|
|
- Copyright (c) 1999-2000 by the Free Pascal development team
|
|
|
+ Copyright (c) 1999-2006 by the Free Pascal development team
|
|
|
|
|
|
Implements a MD5 digest algorithm.
|
|
|
|
|
@@ -14,6 +14,7 @@
|
|
|
**********************************************************************}
|
|
|
|
|
|
{
|
|
|
+ Implements a MD4 digest algorithm (RFC 1320)
|
|
|
Implements a MD5 digest algorithm (RFC 1321)
|
|
|
}
|
|
|
|
|
@@ -22,381 +23,356 @@ unit md5;
|
|
|
{$mode objfpc}
|
|
|
{$h+}
|
|
|
|
|
|
-Interface
|
|
|
+interface
|
|
|
+
|
|
|
+const
|
|
|
+ DefBufSize = 1024;
|
|
|
|
|
|
type
|
|
|
- PCardinal = ^Cardinal;
|
|
|
- TMD5Count = array[0..1] of PtrUInt;
|
|
|
- TMD5State = array[0..3] of Cardinal;
|
|
|
- TMD5Block = array[0..15] of Cardinal;
|
|
|
- TMD5CBits = array[0..7] of byte;
|
|
|
- TMD5Digest = array[0..15] of byte;
|
|
|
- TMD5Buffer = array[0..63] of byte;
|
|
|
- TMD5Context = packed record
|
|
|
- State: TMD5State;
|
|
|
- Count: TMD5Count;
|
|
|
- Buffer: TMD5Buffer;
|
|
|
+ PMDDigest = ^TMDDigest;
|
|
|
+ TMDDigest = array[0..15] of Byte;
|
|
|
+
|
|
|
+ TMDContext = packed record
|
|
|
+ Version : Cardinal;
|
|
|
+ State : array[0..3] of Cardinal;
|
|
|
+ Length : PtrUInt;
|
|
|
+ BufCnt : PtrUInt;
|
|
|
+ Buffer : array[0..63] of Byte;
|
|
|
end;
|
|
|
|
|
|
-Const
|
|
|
- DefBufSize : Cardinal = 1024;
|
|
|
|
|
|
{ Raw methods }
|
|
|
|
|
|
-procedure MD5Init(var Context: TMD5Context);
|
|
|
-procedure MD5Update(var Context: TMD5Context; Var Buf; BufLen: PtrUInt);
|
|
|
-procedure MD5Final(var Context: TMD5Context; var Digest: TMD5Digest);
|
|
|
+procedure MDInit(var Context: TMDContext; const Version: Cardinal);
|
|
|
+procedure MDUpdate(var Context: TMDContext; var Buf; const BufLen: PtrUInt);
|
|
|
+procedure MDFinal(var Context: TMDContext; var Digest: TMDDigest);
|
|
|
|
|
|
{ Auxiliary methods }
|
|
|
|
|
|
-function MD5String(M: string): TMD5Digest;
|
|
|
-function MD5Buffer(Var Buf; BufLen: PtrUInt): TMD5Digest;
|
|
|
-function MD5File(N: string): TMD5Digest;
|
|
|
-function MD5File(N: string; Bufsize : PtrUInt): TMD5Digest;
|
|
|
-function MD5Print(D: TMD5Digest): String;
|
|
|
+function MDString(const S: String; const Version: Cardinal): TMDDigest;
|
|
|
+function MDBuffer(var Buf; const BufLen: PtrUInt; const Version: Cardinal): TMDDigest;
|
|
|
+function MDFile(const Filename: String; const Version: Cardinal; const Bufsize: PtrUInt = DefBufSize): TMDDigest;
|
|
|
+function MDPrint(const Digest: TMDDigest): String;
|
|
|
// based on an implementation by Matthias Fichtner
|
|
|
-function MD5Match(D1, D2: TMD5Digest): boolean;
|
|
|
-
|
|
|
-Implementation
|
|
|
-
|
|
|
-Var
|
|
|
- PADDING: TMD5Buffer;
|
|
|
-
|
|
|
-{ Transformations. }
|
|
|
-
|
|
|
-function F(x,y,z: Cardinal): Cardinal;
|
|
|
-
|
|
|
-begin
|
|
|
- Result:=(x and y) or ((not x) and z);
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-function G(x,y,z: Cardinal): Cardinal;
|
|
|
-
|
|
|
-begin
|
|
|
- Result:=(x and z) or (y and (not z));
|
|
|
-end;
|
|
|
+function MDMatch(const Digest1, Digest2: TMDDigest): Boolean;
|
|
|
|
|
|
+implementation
|
|
|
|
|
|
-function H(x,y,z: Cardinal): Cardinal;
|
|
|
|
|
|
+function rol(x: Cardinal; n: Byte): Cardinal;
|
|
|
begin
|
|
|
- Result:=x xor y xor z;
|
|
|
+ Result := (x shl n) or (x shr (32 - n));
|
|
|
end;
|
|
|
|
|
|
|
|
|
-function I(x,y,z: Cardinal): Cardinal;
|
|
|
-
|
|
|
-begin
|
|
|
- Result:=y xor (x or (not z));
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-procedure rot(var x: Cardinal; n: Byte);
|
|
|
-
|
|
|
-begin
|
|
|
- x:=(x shl n) or (x shr (32 - n));
|
|
|
-end;
|
|
|
-
|
|
|
-
|
|
|
-procedure FF(var a: Cardinal;b,c,d,x: Cardinal; s: Byte; ac: Cardinal);
|
|
|
+// inverts the bytes of (Count div 4) cardinals from source to target.
|
|
|
+procedure Invert(Source, Dest: Pointer; Count: PtrUInt);
|
|
|
+var
|
|
|
+ S: PByte;
|
|
|
+ T: PCardinal;
|
|
|
+ I: PtrUInt;
|
|
|
begin
|
|
|
- inc(a,F(b,c,d)+x+ac);
|
|
|
- rot(a,s);
|
|
|
- inc(a,b);
|
|
|
+ S := Source;
|
|
|
+ T := Dest;
|
|
|
+ for I := 1 to (Count div 4) do
|
|
|
+ begin
|
|
|
+ T^ := S[0] or (S[1] shl 8) or (S[2] shl 16) or (S[3] shl 24);
|
|
|
+ inc(S,4);
|
|
|
+ inc(T);
|
|
|
+ end;
|
|
|
end;
|
|
|
|
|
|
|
|
|
-procedure GG(var a: Cardinal;b,c,d,x: Cardinal;s: Byte;ac: Cardinal);
|
|
|
+procedure MD4Transform(var Context: TMDContext; Buffer: Pointer);
|
|
|
|
|
|
-begin
|
|
|
- inc(a,G(b,c,d)+x+ac);
|
|
|
- rot(a,s);
|
|
|
- inc(a,b);
|
|
|
-end;
|
|
|
+ procedure R1(var a: Cardinal; b,c,d,x: Cardinal; s: Byte);
|
|
|
+ // F(x,y,z) = (x and y) or ((not x) and z)
|
|
|
+ begin
|
|
|
+ a := rol(a + {F(b,c,d)}((b and c) or ((not b) and d)) + x, s);
|
|
|
+ end;
|
|
|
|
|
|
+ procedure R2(var a: Cardinal; b,c,d,x: Cardinal; s: Byte);
|
|
|
+ // G(x,y,z) = (x and y) or (x and z) or (y and z);
|
|
|
+ begin
|
|
|
+ a := rol(a + {G(b,c,d)}((b and c) or (b and d) or (c and d)) + x + $5A827999, s);
|
|
|
+ end;
|
|
|
|
|
|
-procedure HH(var a: Cardinal;b,c,d,x: Cardinal;s: Byte;ac: Cardinal);
|
|
|
+ procedure R3(var a: Cardinal; b,c,d,x: Cardinal; s: Byte);
|
|
|
+ // H(x,y,z) = x xor y xor z
|
|
|
+ begin
|
|
|
+ a := rol(a + {H(b,c,d)}(b xor c xor d) + x + $6ED9EBA1, s);
|
|
|
+ end;
|
|
|
|
|
|
+var
|
|
|
+ a, b, c, d: Cardinal;
|
|
|
+ Block: array[0..15] of Cardinal;
|
|
|
begin
|
|
|
- inc(a,H(b,c,d)+x+ac);
|
|
|
- rot(a,s);
|
|
|
- inc(a,b);
|
|
|
+ Invert(Buffer, @Block, 64);
|
|
|
+ a := Context.State[0];
|
|
|
+ b := Context.State[1];
|
|
|
+ c := Context.State[2];
|
|
|
+ d := Context.State[3];
|
|
|
+
|
|
|
+ // Round 1
|
|
|
+ R1(a,b,c,d,Block[0], 3); R1(d,a,b,c,Block[1], 7); R1(c,d,a,b,Block[2], 11); R1(b,c,d,a,Block[3], 19);
|
|
|
+ R1(a,b,c,d,Block[4], 3); R1(d,a,b,c,Block[5], 7); R1(c,d,a,b,Block[6], 11); R1(b,c,d,a,Block[7], 19);
|
|
|
+ R1(a,b,c,d,Block[8], 3); R1(d,a,b,c,Block[9], 7); R1(c,d,a,b,Block[10],11); R1(b,c,d,a,Block[11],19);
|
|
|
+ R1(a,b,c,d,Block[12], 3); R1(d,a,b,c,Block[13], 7); R1(c,d,a,b,Block[14],11); R1(b,c,d,a,Block[15],19);
|
|
|
+
|
|
|
+ // Round 2
|
|
|
+ R2(a,b,c,d,Block[0], 3); R2(d,a,b,c,Block[4], 5); R2(c,d,a,b,Block[8], 9); R2(b,c,d,a,Block[12],13);
|
|
|
+ R2(a,b,c,d,Block[1], 3); R2(d,a,b,c,Block[5], 5); R2(c,d,a,b,Block[9], 9); R2(b,c,d,a,Block[13],13);
|
|
|
+ R2(a,b,c,d,Block[2], 3); R2(d,a,b,c,Block[6], 5); R2(c,d,a,b,Block[10], 9); R2(b,c,d,a,Block[14],13);
|
|
|
+ R2(a,b,c,d,Block[3], 3); R2(d,a,b,c,Block[7], 5); R2(c,d,a,b,Block[11], 9); R2(b,c,d,a,Block[15],13);
|
|
|
+
|
|
|
+ // Round 3
|
|
|
+ R3(a,b,c,d,Block[0], 3); R3(d,a,b,c,Block[8], 9); R3(c,d,a,b,Block[4], 11); R3(b,c,d,a,Block[12],15);
|
|
|
+ R3(a,b,c,d,Block[2], 3); R3(d,a,b,c,Block[10], 9); R3(c,d,a,b,Block[6], 11); R3(b,c,d,a,Block[14],15);
|
|
|
+ R3(a,b,c,d,Block[1], 3); R3(d,a,b,c,Block[9], 9); R3(c,d,a,b,Block[5], 11); R3(b,c,d,a,Block[13],15);
|
|
|
+ R3(a,b,c,d,Block[3], 3); R3(d,a,b,c,Block[11], 9); R3(c,d,a,b,Block[7], 11); R3(b,c,d,a,Block[15],15);
|
|
|
+
|
|
|
+ inc(Context.State[0], a);
|
|
|
+ inc(Context.State[1], b);
|
|
|
+ inc(Context.State[2], c);
|
|
|
+ inc(Context.State[3], d);
|
|
|
+ inc(Context.Length,64);
|
|
|
end;
|
|
|
|
|
|
|
|
|
-procedure II(var a: Cardinal;b,c,d,x: Cardinal;s: Byte;ac: Cardinal);
|
|
|
-
|
|
|
-begin
|
|
|
- inc(a,I(b,c,d)+x+ac);
|
|
|
- rot(a,s);
|
|
|
- inc(a,b);
|
|
|
-end;
|
|
|
-
|
|
|
-// inverts the bytes of (Count div) 4 cardinals from source to target.
|
|
|
+procedure MD5Transform(var Context: TMDContext; Buffer: Pointer);
|
|
|
|
|
|
-procedure Invert(Source,Target: pointer; Count: PtrUInt);
|
|
|
+ procedure R1(var a: Cardinal; b,c,d,x: Cardinal; s: Byte; ac: Cardinal);
|
|
|
+ // F(x,y,z) = (x and y) or ((not x) and z)
|
|
|
+ begin
|
|
|
+ a := b + rol(a + {F(b,c,d)}((b and c) or ((not b) and d)) + x + ac, s);
|
|
|
+ end;
|
|
|
|
|
|
-var
|
|
|
- S: PByte;
|
|
|
- T: PCardinal;
|
|
|
- I: PtrUInt;
|
|
|
+ procedure R2(var a: Cardinal; b,c,d,x: Cardinal; s: Byte; ac: Cardinal);
|
|
|
+ // G(x,y,z) = (x and z) or (y and (not z))
|
|
|
+ begin
|
|
|
+ a := b + rol(a + {G(b,c,d)}((b and d) or (c and (not d))) + x + ac, s);
|
|
|
+ end;
|
|
|
|
|
|
-begin
|
|
|
- S := Source;
|
|
|
- T := Target;
|
|
|
- for I := 1 to (Count div 4) do
|
|
|
- begin
|
|
|
- T^:=S[0] or (S[1] shl 8) or (S[2] shl 16) or (S[3] shl 24);
|
|
|
- inc(S,4);
|
|
|
- inc(T);
|
|
|
- end;
|
|
|
-end;
|
|
|
+ procedure R3(var a: Cardinal; b,c,d,x: Cardinal; s: Byte; ac: Cardinal);
|
|
|
+ // H(x,y,z) = x xor y xor z;
|
|
|
+ begin
|
|
|
+ a := b + rol(a + {H(b,c,d)}(b xor c xor d) + x + ac, s);
|
|
|
+ end;
|
|
|
|
|
|
-procedure Transform(Buffer: pointer; var State: TMD5State);
|
|
|
+ procedure R4(var a: Cardinal; b,c,d,x: Cardinal; s: Byte; ac: Cardinal);
|
|
|
+ // I(x,y,z) = y xor (x or (not z));
|
|
|
+ begin
|
|
|
+ a := b + rol(a + {I(b,c,d)}(c xor (b or (not d))) + x + ac, s);
|
|
|
+ end;
|
|
|
|
|
|
var
|
|
|
a, b, c, d: Cardinal;
|
|
|
- Block: TMD5Block;
|
|
|
-
|
|
|
+ Block: array[0..15] of Cardinal;
|
|
|
begin
|
|
|
Invert(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,$02441453);
|
|
|
- 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,$04881d05);
|
|
|
- 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);
|
|
|
+ a := Context.State[0];
|
|
|
+ b := Context.State[1];
|
|
|
+ c := Context.State[2];
|
|
|
+ d := Context.State[3];
|
|
|
+
|
|
|
+ // Round 1
|
|
|
+ R1(a,b,c,d,Block[0] , 7,$d76aa478); R1(d,a,b,c,Block[1] ,12,$e8c7b756); R1(c,d,a,b,Block[2] ,17,$242070db); R1(b,c,d,a,Block[3] ,22,$c1bdceee);
|
|
|
+ R1(a,b,c,d,Block[4] , 7,$f57c0faf); R1(d,a,b,c,Block[5] ,12,$4787c62a); R1(c,d,a,b,Block[6] ,17,$a8304613); R1(b,c,d,a,Block[7] ,22,$fd469501);
|
|
|
+ R1(a,b,c,d,Block[8] , 7,$698098d8); R1(d,a,b,c,Block[9] ,12,$8b44f7af); R1(c,d,a,b,Block[10],17,$ffff5bb1); R1(b,c,d,a,Block[11],22,$895cd7be);
|
|
|
+ R1(a,b,c,d,Block[12], 7,$6b901122); R1(d,a,b,c,Block[13],12,$fd987193); R1(c,d,a,b,Block[14],17,$a679438e); R1(b,c,d,a,Block[15],22,$49b40821);
|
|
|
+
|
|
|
+ // Round 2
|
|
|
+ R2(a,b,c,d,Block[1] , 5,$f61e2562); R2(d,a,b,c,Block[6] , 9,$c040b340); R2(c,d,a,b,Block[11],14,$265e5a51); R2(b,c,d,a,Block[0] ,20,$e9b6c7aa);
|
|
|
+ R2(a,b,c,d,Block[5] , 5,$d62f105d); R2(d,a,b,c,Block[10], 9,$02441453); R2(c,d,a,b,Block[15],14,$d8a1e681); R2(b,c,d,a,Block[4] ,20,$e7d3fbc8);
|
|
|
+ R2(a,b,c,d,Block[9] , 5,$21e1cde6); R2(d,a,b,c,Block[14], 9,$c33707d6); R2(c,d,a,b,Block[3] ,14,$f4d50d87); R2(b,c,d,a,Block[8] ,20,$455a14ed);
|
|
|
+ R2(a,b,c,d,Block[13], 5,$a9e3e905); R2(d,a,b,c,Block[2] , 9,$fcefa3f8); R2(c,d,a,b,Block[7] ,14,$676f02d9); R2(b,c,d,a,Block[12],20,$8d2a4c8a);
|
|
|
+
|
|
|
+ // Round 3
|
|
|
+ R3(a,b,c,d,Block[5] , 4,$fffa3942); R3(d,a,b,c,Block[8] ,11,$8771f681); R3(c,d,a,b,Block[11],16,$6d9d6122); R3(b,c,d,a,Block[14],23,$fde5380c);
|
|
|
+ R3(a,b,c,d,Block[1] , 4,$a4beea44); R3(d,a,b,c,Block[4] ,11,$4bdecfa9); R3(c,d,a,b,Block[7] ,16,$f6bb4b60); R3(b,c,d,a,Block[10],23,$bebfbc70);
|
|
|
+ R3(a,b,c,d,Block[13], 4,$289b7ec6); R3(d,a,b,c,Block[0] ,11,$eaa127fa); R3(c,d,a,b,Block[3] ,16,$d4ef3085); R3(b,c,d,a,Block[6] ,23,$04881d05);
|
|
|
+ R3(a,b,c,d,Block[9] , 4,$d9d4d039); R3(d,a,b,c,Block[12],11,$e6db99e5); R3(c,d,a,b,Block[15],16,$1fa27cf8); R3(b,c,d,a,Block[2] ,23,$c4ac5665);
|
|
|
+
|
|
|
+ // Round 4
|
|
|
+ R4(a,b,c,d,Block[0] , 6,$f4292244); R4(d,a,b,c,Block[7] ,10,$432aff97); R4(c,d,a,b,Block[14],15,$ab9423a7); R4(b,c,d,a,Block[5] ,21,$fc93a039);
|
|
|
+ R4(a,b,c,d,Block[12], 6,$655b59c3); R4(d,a,b,c,Block[3] ,10,$8f0ccc92); R4(c,d,a,b,Block[10],15,$ffeff47d); R4(b,c,d,a,Block[1] ,21,$85845dd1);
|
|
|
+ R4(a,b,c,d,Block[8] , 6,$6fa87e4f); R4(d,a,b,c,Block[15],10,$fe2ce6e0); R4(c,d,a,b,Block[6] ,15,$a3014314); R4(b,c,d,a,Block[13],21,$4e0811a1);
|
|
|
+ R4(a,b,c,d,Block[4] , 6,$f7537e82); R4(d,a,b,c,Block[11],10,$bd3af235); R4(c,d,a,b,Block[2] ,15,$2ad7d2bb); R4(b,c,d,a,Block[9] ,21,$eb86d391);
|
|
|
+
|
|
|
+ inc(Context.State[0],a);
|
|
|
+ inc(Context.State[1],b);
|
|
|
+ inc(Context.State[2],c);
|
|
|
+ inc(Context.State[3],d);
|
|
|
+ inc(Context.Length,64);
|
|
|
end;
|
|
|
|
|
|
|
|
|
-
|
|
|
-procedure MD5Init(var Context: TMD5Context);
|
|
|
-
|
|
|
+procedure MDInit(var Context: TMDContext; const Version: Cardinal);
|
|
|
begin
|
|
|
- with Context do
|
|
|
- begin
|
|
|
- State[0] := $67452301;
|
|
|
- State[1] := $efcdab89;
|
|
|
- State[2] := $98badcfe;
|
|
|
- State[3] := $10325476;
|
|
|
- Count[0] := 0;
|
|
|
- Count[1] := 0;
|
|
|
- FillChar(Buffer, SizeOf(TMD5Buffer),0);
|
|
|
- end;
|
|
|
+ Context.Version := Version;
|
|
|
+ Context.State[0] := $67452301;
|
|
|
+ Context.State[1] := $efcdab89;
|
|
|
+ Context.State[2] := $98badcfe;
|
|
|
+ Context.State[3] := $10325476;
|
|
|
+ Context.Length := 0;
|
|
|
+ Context.BufCnt := 0;
|
|
|
end;
|
|
|
|
|
|
|
|
|
-
|
|
|
-procedure MD5Update(var Context: TMD5Context; Var Buf; BufLen: PtrUInt);
|
|
|
-
|
|
|
+procedure MDUpdate(var Context: TMDContext; var Buf; const BufLen: PtrUInt);
|
|
|
var
|
|
|
- Index: PtrUInt;
|
|
|
- PartLen: PtrUInt;
|
|
|
- I: PtrUInt;
|
|
|
- P : PByte;
|
|
|
-
|
|
|
+ Src: Pointer;
|
|
|
+ Num: PtrUInt;
|
|
|
begin
|
|
|
- P:=PByte(@Buf);
|
|
|
- with Context do
|
|
|
+ Src := @Buf;
|
|
|
+ Num := 0;
|
|
|
+
|
|
|
+ // 1. Transform existing data in buffer
|
|
|
+ if Context.BufCnt > 0 then
|
|
|
+ begin
|
|
|
+ // 1.1 Try to fill buffer to 64 bytes
|
|
|
+ Num := 64 - Context.BufCnt;
|
|
|
+ if Num > BufLen then
|
|
|
+ Num := BufLen;
|
|
|
+
|
|
|
+ Move(Src^, Context.Buffer[Context.BufCnt], Num);
|
|
|
+ Context.BufCnt := Context.BufCnt + Num;
|
|
|
+ Src := Pointer(PtrUInt(Src) + Num);
|
|
|
+
|
|
|
+ // 1.2 If buffer contains 64 bytes, transform it
|
|
|
+ if Context.BufCnt = 64 then
|
|
|
begin
|
|
|
- Index := (Count[0] shr 3) and $3f;
|
|
|
- inc(Count[0], BufLen shl 3);
|
|
|
- if Count[0] < (BufLen shl 3) then inc(Count[1]);
|
|
|
- inc(Count[1], BufLen shr 29);
|
|
|
- end;
|
|
|
- PartLen := 64 - Index;
|
|
|
- if BufLen >= PartLen then
|
|
|
- begin
|
|
|
- Move(Buf,Context.Buffer[Index], PartLen);
|
|
|
- Transform(@Context.Buffer, Context.State);
|
|
|
- I := PartLen;
|
|
|
- while I+63 < BufLen do
|
|
|
- begin
|
|
|
- Transform(@P[I], Context.State);
|
|
|
- inc(I, 64);
|
|
|
+ case Context.Version of
|
|
|
+ 4: MD4Transform(Context, @Context.Buffer);
|
|
|
+ 5: MD5Transform(Context, @Context.Buffer);
|
|
|
end;
|
|
|
- Index := 0;
|
|
|
- end
|
|
|
- else I := 0;
|
|
|
- Move(P[I],Context.Buffer[Index], BufLen - I);
|
|
|
-end;
|
|
|
+ Context.BufCnt := 0;
|
|
|
+ end;
|
|
|
+ end;
|
|
|
|
|
|
+ // 2. Transform 64-Byte blocks of Buf
|
|
|
+ Num := BufLen - Num;
|
|
|
+ while Num >= 64 do
|
|
|
+ begin
|
|
|
+ case Context.Version of
|
|
|
+ 4: MD4Transform(Context, Src);
|
|
|
+ 5: MD5Transform(Context, Src);
|
|
|
+ end;
|
|
|
+ Src := Pointer(PtrUInt(Src) + 64);
|
|
|
+ Num := Num - 64;
|
|
|
+ end;
|
|
|
|
|
|
+ // 3. If there's a block smaller than 64 Bytes left, add it to buffer
|
|
|
+ if Num > 0 then
|
|
|
+ begin
|
|
|
+ Context.BufCnt := Num;
|
|
|
+ Move(Src^, Context.Buffer, Num);
|
|
|
+ end;
|
|
|
+end;
|
|
|
|
|
|
-procedure MD5Final(var Context: TMD5Context; var Digest: TMD5Digest);
|
|
|
|
|
|
+procedure MDFinal(var Context: TMDContext; var Digest: TMDDigest);
|
|
|
+const
|
|
|
+ Padding: array[0..15] of Cardinal = ($80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
|
|
|
var
|
|
|
- Bits: TMD5CBits;
|
|
|
- I : PtrUInt;
|
|
|
- Pad : PtrUInt;
|
|
|
-
|
|
|
+ Length: QWord;
|
|
|
+ Pads: Cardinal;
|
|
|
begin
|
|
|
- Invert(@Context.Count, @Bits, 8);
|
|
|
- I:=(Context.Count[0] shr 3) and $3f;
|
|
|
- if I<56 then
|
|
|
- Pad:=56-I
|
|
|
- else
|
|
|
- Pad:=120-I;
|
|
|
- MD5Update(Context, Padding, Pad);
|
|
|
- MD5Update(Context, Bits, 8);
|
|
|
- Invert(@Context.State, @Digest, 16);
|
|
|
- FillChar(Context, SizeOf(TMD5Context),0);
|
|
|
-end;
|
|
|
+ // 1. Compute length of the whole stream in bits
|
|
|
+ Length := 8 * (Context.Length + Context.BufCnt);
|
|
|
|
|
|
+ // 2. Append padding bits
|
|
|
+ Pads := (120 - Context.BufCnt) mod 64;
|
|
|
+ if Pads > 0 then
|
|
|
+ MDUpdate(Context, Padding, Pads) else
|
|
|
+ MDUpdate(Context, Padding, 56);
|
|
|
|
|
|
-function MD5String(M: string): TMD5Digest;
|
|
|
+ // 3. Append length of the stream
|
|
|
+ Invert(@Length, @Length, 8);
|
|
|
+ MDUpdate(Context, Length, 8);
|
|
|
|
|
|
-var
|
|
|
- Context: TMD5Context;
|
|
|
-
|
|
|
-begin
|
|
|
- MD5Init(Context);
|
|
|
- MD5Update(Context, M[1], length(M));
|
|
|
- MD5Final(Context, Result);
|
|
|
+ // 4. Invert state to digest
|
|
|
+ Invert(@Context.State, @Digest, 16);
|
|
|
+ FillChar(Context, SizeOf(TMDContext), 0);
|
|
|
end;
|
|
|
|
|
|
-function MD5Buffer(var Buf; BufLen: PtrUInt): TMD5Digest;
|
|
|
-var
|
|
|
- Context: TMD5Context;
|
|
|
|
|
|
+function MDString(const S: String; const Version: Cardinal): TMDDigest;
|
|
|
+var
|
|
|
+ Context: TMDContext;
|
|
|
begin
|
|
|
- MD5Init(Context);
|
|
|
- MD5Update(Context, buf, buflen);
|
|
|
- MD5Final(Context, Result);
|
|
|
+ MDInit(Context, Version);
|
|
|
+ MDUpdate(Context, PChar(S)^, length(S));
|
|
|
+ MDFinal(Context, Result);
|
|
|
end;
|
|
|
|
|
|
-function MD5File(N: string): TMD5Digest;
|
|
|
|
|
|
+function MDBuffer(var Buf; const BufLen: PtrUInt; const Version: Cardinal): TMDDigest;
|
|
|
+var
|
|
|
+ Context: TMDContext;
|
|
|
begin
|
|
|
- Result:=MD5File(N,DefBufSize);
|
|
|
+ MDInit(Context, Version);
|
|
|
+ MDUpdate(Context, buf, buflen);
|
|
|
+ MDFinal(Context, Result);
|
|
|
end;
|
|
|
|
|
|
|
|
|
-function MD5File(N: string; BufSize : PtrUInt): TMD5Digest;
|
|
|
-
|
|
|
+function MDFile(const Filename: String; const Version: Cardinal; const BufSize: PtrUInt): TMDDigest;
|
|
|
var
|
|
|
- F : File;
|
|
|
- Buf : Pchar;
|
|
|
- Context: TMD5Context;
|
|
|
- Count : Longint;
|
|
|
- ofm : Longint;
|
|
|
-
|
|
|
+ F: File;
|
|
|
+ Buf: Pchar;
|
|
|
+ Context: TMDContext;
|
|
|
+ Count: Cardinal;
|
|
|
+ ofm: Longint;
|
|
|
begin
|
|
|
- MD5Init(Context);
|
|
|
- Assign(F,N);
|
|
|
+ MDInit(Context, Version);
|
|
|
+
|
|
|
+ Assign(F, Filename);
|
|
|
{$i-}
|
|
|
- ofm:=FileMode;
|
|
|
- FileMode:=0;
|
|
|
- Reset(F,1);
|
|
|
+ ofm := FileMode;
|
|
|
+ FileMode := 0;
|
|
|
+ Reset(F, 1);
|
|
|
{$i+}
|
|
|
- if (IOResult=0) then
|
|
|
- begin
|
|
|
- GetMem(Buf,BufSize);
|
|
|
- Repeat
|
|
|
- BlockRead(F,Buf^,Bufsize,Count);
|
|
|
- If (Count>0) then
|
|
|
- MD5Update(Context, Buf^, Count);
|
|
|
- Until (Count<BufSize);
|
|
|
- FreeMem(Buf,BufSize);
|
|
|
+
|
|
|
+ if IOResult = 0 then
|
|
|
+ begin
|
|
|
+ GetMem(Buf, BufSize);
|
|
|
+ repeat
|
|
|
+ BlockRead(F, Buf^, Bufsize, Count);
|
|
|
+ if Count > 0 then
|
|
|
+ MDUpdate(Context, Buf^, Count);
|
|
|
+ until Count < BufSize;
|
|
|
+ FreeMem(Buf, BufSize);
|
|
|
Close(F);
|
|
|
- end;
|
|
|
- MD5Final(Context, Result);
|
|
|
- FileMode:=ofm;
|
|
|
-end;
|
|
|
+ end;
|
|
|
|
|
|
+ MDFinal(Context, Result);
|
|
|
+ FileMode := ofm;
|
|
|
+end;
|
|
|
|
|
|
-function MD5Print(D: TMD5Digest): string;
|
|
|
|
|
|
+function MDPrint(const Digest: TMDDigest): String;
|
|
|
var
|
|
|
- I: byte;
|
|
|
-
|
|
|
+ I: Byte;
|
|
|
begin
|
|
|
Result := '';
|
|
|
for I := 0 to 15 do
|
|
|
- Result := Result + HexStr(D[i],2);
|
|
|
- Result:=LowerCase(Result);
|
|
|
+ Result := Result + HexStr(Digest[i],2);
|
|
|
+ Result := LowerCase(Result);
|
|
|
end;
|
|
|
|
|
|
-function MD5Match(D1, D2: TMD5Digest): boolean;
|
|
|
+
|
|
|
+function MDMatch(const Digest1, Digest2: TMDDigest): Boolean;
|
|
|
var
|
|
|
- I: byte;
|
|
|
+ I: Byte;
|
|
|
begin
|
|
|
I := 0;
|
|
|
- Result := TRUE;
|
|
|
- while Result and (I < 16) do begin
|
|
|
- Result := D1[I] = D2[I];
|
|
|
+ Result := True;
|
|
|
+ while Result and (I < 16) do
|
|
|
+ begin
|
|
|
+ Result := Digest1[I] = Digest2[I];
|
|
|
inc(I);
|
|
|
end;
|
|
|
end;
|
|
|
|
|
|
-Initialization
|
|
|
- FillChar(Padding,SizeOF(Padding),0);
|
|
|
- Padding[0]:=$80;
|
|
|
end.
|