+ Initial implementation

This commit is contained in:
michael 2002-07-23 19:42:41 +00:00
parent feb28ce902
commit c8dbdd3e41
5 changed files with 1726 additions and 0 deletions

1266
packages/base/md5/Makefile Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,17 @@
#
# Makefile.fpc for MD5 checksum.
#
[package]
name=md5
version=1.0.6
[target]
units=md5
examples=md5test
[install]
fpcpackage=y
[default]
fpcdir=../../..

389
packages/base/md5/md5.pp Normal file
View File

@ -0,0 +1,389 @@
{
$Id$
This file is part of the Free Pascal packages.
Copyright (c) 1999-2000 by the Free Pascal development team
Implements a MD5 digest algorithm.
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**********************************************************************}
{
Implements a MD5 digest algorithm (RFC 1321)
}
unit md5;
{$mode objfpc}
{$h+}
Interface
type
PCardinal = ^Cardinal;
TMD5Count = array[0..1] of Cardinal;
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;
end;
Const
DefBufSize : Cardinal = 1024;
{ Raw methods }
procedure MD5Init(var Context: TMD5Context);
procedure MD5Update(var Context: TMD5Context; Var Buf; BufLen: cardinal);
procedure MD5Final(var Context: TMD5Context; var Digest: TMD5Digest);
{ Auxiliary methods }
function MD5String(M: string): TMD5Digest;
function MD5File(N: string): TMD5Digest;
function MD5File(N: string; Bufsize : Cardinal): TMD5Digest;
function MD5Print(D: TMD5Digest): 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 H(x,y,z: Cardinal): Cardinal;
begin
Result:=x xor y xor z;
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);
begin
inc(a,F(b,c,d)+x+ac);
rot(a,s);
inc(a,b);
end;
procedure GG(var a: Cardinal;b,c,d,x: Cardinal;s: Byte;ac: Cardinal);
begin
inc(a,G(b,c,d)+x+ac);
rot(a,s);
inc(a,b);
end;
procedure HH(var a: Cardinal;b,c,d,x: Cardinal;s: Byte;ac: Cardinal);
begin
inc(a,H(b,c,d)+x+ac);
rot(a,s);
inc(a,b);
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 Invert(Source,Target: pointer; Count: cardinal);
var
S: PByte;
T: PCardinal;
I: cardinal;
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 Transform(Buffer: pointer; var State: TMD5State);
var
a, b, c, d: Cardinal;
Block: TMD5Block;
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);
end;
procedure MD5Init(var Context: TMD5Context);
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;
end;
procedure MD5Update(var Context: TMD5Context; Var Buf; BufLen: cardinal);
var
Index: cardinal;
PartLen: cardinal;
I: cardinal;
P : PByte;
begin
P:=PByte(@Buf);
with Context do
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);
end;
Index := 0;
end
else I := 0;
Move(P[I],Context.Buffer[Index], BufLen - I);
end;
procedure MD5Final(var Context: TMD5Context; var Digest: TMD5Digest);
var
Bits: TMD5CBits;
I : cardinal;
Pad : 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;
function MD5String(M: string): TMD5Digest;
var
Context: TMD5Context;
begin
MD5Init(Context);
MD5Update(Context, M[1], length(M));
MD5Final(Context, Result);
end;
function MD5File(N: string): TMD5Digest;
begin
Result:=MD5File(N,DefBufSize);
end;
function MD5File(N: string; BufSize : Cardinal): TMD5Digest;
var
F : File;
Buf : Pchar;
Context: TMD5Context;
Count : Longint;
begin
MD5Init(Context);
Assign(F,N);
{$i-}
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);
Close(F);
end;
MD5Final(Context, Result);
end;
function MD5Print(D: TMD5Digest): string;
var
I: byte;
begin
Result := '';
for I := 0 to 15 do
Result := Result + HexStr(D[i],2);
Result:=LowerCase(Result);
end;
function MD5Match(D1, D2: TMD5Digest): 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;
Initialization
FillChar(Padding,SizeOF(Padding),0);
Padding[0]:=$80;
end.

11
packages/base/md5/md5.ref Normal file
View File

@ -0,0 +1,11 @@
Executing RFC 1321 test suite ...
MD5 ("") = d41d8cd98f00b204e9800998ecf8427e
MD5 ("a") = 0cc175b9c0f1b6a831c399e269772661
MD5 ("abc") = 900150983cd24fb0d6963f7d28e17f72
MD5 ("message digest") = f96b697d7cb7938d525a2f31aaf161d0
MD5 ("abcdefghijklmnopqrstuvwxyz") = c3fcd3d76192e4007dfb496cca67e13b
MD5 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = d174ab98d277d9f5a5611c2c9f419d9f
MD5 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890") = 57edf4a22be3c955ac49da2e2107b67a
md5file (50) : 4082044e9fc73d5a080b05bb103db0db
md5file (def) : 4082044e9fc73d5a080b05bb103db0db

View File

@ -0,0 +1,43 @@
{
$Id$
This file is part of the Free Pascal packages.
Copyright (c) 1999-2000 by the Free Pascal development team
Tests the MD5 program.
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**********************************************************************}
program md5test;
{$h+}
uses md5;
var
I: byte;
const
Suite: array[1..7] of string = (
'',
'a',
'abc',
'message digest',
'abcdefghijklmnopqrstuvwxyz',
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
'12345678901234567890123456789012345678901234567890123456789012345678901234567890'
);
begin
Writeln('Executing RFC 1321 test suite ...');
for I := 1 to 7 do
Writeln('MD5 ("',Suite[i],'") = ',MD5Print(MD5String(Suite[I])));
Writeln();
Writeln('md5file (50) : ',md5print(Md5File('md5test.pas',50)));
Writeln('md5file (def) : ',md5print(Md5File('md5test.pas')));
end.