支持4G以上文件的MD5单元

根据网上一个流传很久的基于Delph4的MD5单元修改的, 可以支持4G以上的文件, 可以支持UNICODE字符的Delphi

恩.......对于大文件速度稍微慢了一点点, 在我自己的电脑上测试, 5.2G文件计算速度86秒...凑合了吧

如果谁能优化一下速度, 请联系我哦~~~

(*
-----------------------------------------------------------------------------------------------

                                     MD5 Message-Digest

                                 Delphi Unit implementing the
                      RSA Data Security, Inc. MD5 Message-Digest Algorithm

                          Implementation of Ronald L. Rivest's RFC 1321

                      Copyright ?1997-1999 Medienagentur Fichtner & Meyer
                                  Written by Matthias Fichtner

-----------------------------------------------------------------------------------------------
2013-11-11 堕落恶魔
  增加对超过4G大小文件支持
  增加对Delphi2009以及更高版本Delphi支持


如果有修改, 希望能够将代码同步邮件给我, 谢谢
hs_kill_god@hotmail.com
-----------------------------------------------------------------------------------------------

*)


Unit MD5;

// -----------------------------------------------------------------------------------------------
interface
// -----------------------------------------------------------------------------------------------

uses
  Windows, Classes, SysUtils;

const
  MD5Length: Byte = 32;

type
  MD5Count = array[0..1] of Int64;
  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;

function MD5String(M: AnsiString): MD5Digest;
function MD5File(N: AnsiString): MD5Digest;
function MD5Print(D: MD5Digest): AnsiString;

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
  );

type
  MD5Context = record
    State: MD5State;
    Count: MD5Count;
    Buffer: MD5Buffer;
  end;

function F(x, y, z: DWORD): DWORD; inline;
begin
  Result := (x and y) or ((not x) and z);
end;

function G(x, y, z: DWORD): DWORD; inline;
begin
  Result := (x and z) or (y and (not z));
end;

function H(x, y, z: DWORD): DWORD; inline;
begin
  Result := x xor y xor z;
end;

function I(x, y, z: DWORD): DWORD; inline;
begin
  Result := y xor (x or (not z));
end;

procedure rot(var x: DWORD; n: BYTE); inline;
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); inline;
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); inline;
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); inline;
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); inline;
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;

function MP(P: Pointer; M: Integer): Pointer;
begin
  Result := Pointer(Integer(P) + M);
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 AContext: MD5Context);
begin
  with AContext do
  begin
    State[0] := $67452301;
    State[1] := $EFCDAB89;
    State[2] := $98BADCFE;
    State[3] := $10325476;
    Count[0] := 0;
    Count[1] := 0;
    FillChar(Buffer, SizeOf(MD5Buffer), 0);
  end;
end;

// Update given Context to include Length bytes of Input
procedure MD5Update(var AContext: MD5Context; AInput: Pointer; ALength: Int64); overload;
var
  nIndex: Int64;
  nPartLen: Int64;
  I: Int64;
begin
  with AContext do
  begin
    nIndex := (Count[0] shr 3) and $3F;
    inc(Count[0], ALength shl 3);
    if Count[0] < (ALength shl 3) then
      inc(Count[1]);
    inc(Count[1], ALength shr 61);
  end;
  nPartLen := 64 - nIndex;
  if ALength >= nPartLen then
  begin
    Move(AInput^, AContext.Buffer[nIndex], nPartLen);
    Transform(@AContext.Buffer, AContext.State);
    I := nPartLen;
    while I + 63 < ALength do
    begin
      Transform(MP(AInput,  I), AContext.State);
      inc(I, 64);
    end;
    nIndex := 0;
  end
  else
    I := 0;
  Move(MP(AInput,  I)^, AContext.Buffer[nIndex], ALength - i);
end;

procedure MD5Update(var AContext: MD5Context; AInput: TStream; ALength: Int64); overload;
var
  nIndex: Int64;
  nPartLen: Int64;
  i: Int64;
  x, m: Integer;
  nBuff: array[0..1023] of Byte;
begin
  with AContext do
  begin
    nIndex := (Count[0] shr 3) and $3F;
    inc(Count[0], ALength shl 3);
    if Count[0] < (ALength shl 3) then
      inc(Count[1]);
    inc(Count[1], ALength shr 61);
  end;
  nPartLen := 64 - nIndex;
  if ALength >= nPartLen then
  begin
    AInput.Read(AContext.Buffer[nIndex], nPartLen);
    Transform(@AContext.Buffer, AContext.State);
    i := nPartLen;
    while i < ALength - 1024 do
    begin
      AInput.Read(nBuff, 1024);
      for x := 0 to 15 do
        Transform(@(nBuff[x * 64]), AContext.State);
      Inc(i, 1024);
    end;
    m := (ALength - i) div 64;
    x := m * 64;
    AInput.Read(nBuff, x);
    Inc(I, x);
    for x := 0 to m - 1 do
      Transform(@(nBuff[x * 64]), AContext.State);
    nIndex := 0;
  end
  else
    i := 0;
  AInput.Read(AContext.Buffer[nIndex], ALength - i);
end;

// Finalize given Context, create Digest and zeroize Context
procedure MD5Final(var AContext: MD5Context; var Digest: MD5Digest);
var
  nBits: MD5CBits;
  nIndex: longword;
  nPadLen: longword;
begin
  Decode(@AContext.Count, @nBits, 2);
  nIndex := (AContext.Count[0] shr 3) and $3f;
  if nIndex < 56 then
    nPadLen := 56 - nIndex
  else
    nPadLen := 120 - nIndex;
  MD5Update(AContext, @PADDING, nPadLen);
  MD5Update(AContext, @nBits, 8);
  Decode(@AContext.State, @Digest, 4);
  FillChar(AContext, SizeOf(MD5Context), 0);
end;

// -----------------------------------------------------------------------------------------------

// Create digest of given Message
function MD5String(M: AnsiString): MD5Digest;
var
  nContext: MD5Context;
begin
  MD5Init(nContext);
  MD5Update(nContext, pAnsiChar(M), length(M));
  MD5Final(nContext, Result);
end;

// Create digest of file with given Name
function MD5File(N: AnsiString): MD5Digest;
var
  nContext: MD5Context;
  nFS: TFileStream;
begin
  MD5Init(nContext);
  if FileExists(N) then
  begin
    nFS := TFileStream.Create(N, fmOpenRead or fmShareDenyWrite);
    try
      nFS.Position := 0;
      MD5Update(nContext, nFS, nFS.Size);
    finally
      nFS.Free;
    end;
  end;
  MD5Final(nContext, Result);
end;

// Create hex representation of given Digest
function MD5Print(D: MD5Digest): AnsiString;
var
  I, x: byte;
const
  Digits: array[0..15] of AnsiChar =
    ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f');
begin
  SetLength(Result, 32);
  for I := 0 to 15 do
  begin
    x := i * 2 + 1;
    Result[x] := Digits[(D[I] shr 4) and $0f];
    Result[x + 1] := Digits[D[I] and $0f];
  end;
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.
原文地址:https://www.cnblogs.com/lzl_17948876/p/3418282.html