delphi 64位MD5算法

来源:互联网 发布:淘宝客服售中话术整理 编辑:程序博客网 时间:2024/05/16 06:03

看到网上有人说indy的md5在64位下计算结果与32位下不一致。我测试了一下,确实如此,因此把自己用的64位计算结果正确的md5函数代码发出来。

说明1:这个单元的代码是从indy的md5代码修改而来的。

说明2:计算TBytes和String的MD5值可以使用TBytesStream或TStringStream。

说明3:计算结果转换为HEX字符的代码请自行编写。

 

unit BambooMD5;

interface

uses
  SysUtils,
  Classes;

function BambooMD5Stream(aStream: TStream): TBytes;

implementation

uses
  Math;

type
  T4x4LongWordRecord = array [0 .. 3] of LongWord;
  T16x4LongWordRecord = array [0 .. 15] of LongWord;

function ROL(const AVal: LongWord; AShift: Byte): LongWord; assembler;
asm
  {$IFDEF CPUX64}
  mov  eax, ecx
  {$ELSE}
  {$ENDIF !CPUX64}
  mov  cl, dl
  rol  eax, cl
end;

const
  MD4_INIT_VALUES: T4x4LongWordRecord = ($67452301, $EFCDAB89, $98BADCFE, $10325476);

  MD5_SINE: array [1 .. 64] of LongWord = (
    { Round 1. }
    $D76AA478, $E8C7B756, $242070DB, $C1BDCEEE, $F57C0FAF, $4787C62A, $A8304613, $FD469501, $698098D8, $8B44F7AF, $FFFF5BB1, $895CD7BE, $6B901122, $FD987193, $A679438E, $49B40821,
    { Round 2. }
    $F61E2562, $C040B340, $265E5A51, $E9B6C7AA, $D62F105D, $02441453, $D8A1E681, $E7D3FBC8, $21E1CDE6, $C33707D6, $F4D50D87, $455A14ED, $A9E3E905, $FCEFA3F8, $676F02D9, $8D2A4C8A,
    { Round 3. }
    $FFFA3942, $8771F681, $6D9D6122, $FDE5380C, $A4BEEA44, $4BDECFA9, $F6BB4B60, $BEBFBC70, $289B7EC6, $EAA127FA, $D4EF3085, $04881D05, $D9D4D039, $E6DB99E5, $1FA27CF8, $C4AC5665,
    { Round 4. }
    $F4292244, $432AFF97, $AB9423A7, $FC93A039, $655B59C3, $8F0CCC92, $FFEFF47D, $85845DD1, $6FA87E4F, $FE2CE6E0, $A3014314, $4E0811A1, $F7537E82, $BD3AF235, $2AD7D2BB, $EB86D391);
{$Q-}

procedure MDCoder(const FCBuffer: TBytes; var FState: T4x4LongWordRecord);
var
  A, B, C, D: LongWord;
  i: Integer;
  X: T16x4LongWordRecord;
begin
  A := FState[0];
  B := FState[1];
  C := FState[2];
  D := FState[3];

  for i := 0 to 15 do
  begin
    X[i] := FCBuffer[i * 4 + 0] + (FCBuffer[i * 4 + 1] shl 8) + (FCBuffer[i * 4 + 2] shl 16) + (FCBuffer[i * 4 + 3] shl 24);
  end;
  { Round 1 }
  A := ROL(A + (((D xor C) and B) xor D) + X[0] + MD5_SINE[1], 7) + B;
  D := ROL(D + (((C xor B) and A) xor C) + X[1] + MD5_SINE[2], 12) + A;
  C := ROL(C + (((B xor A) and D) xor B) + X[2] + MD5_SINE[3], 17) + D;
  B := ROL(B + (((A xor D) and C) xor A) + X[3] + MD5_SINE[4], 22) + C;
  A := ROL(A + (((D xor C) and B) xor D) + X[4] + MD5_SINE[5], 7) + B;
  D := ROL(D + (((C xor B) and A) xor C) + X[5] + MD5_SINE[6], 12) + A;
  C := ROL(C + (((B xor A) and D) xor B) + X[6] + MD5_SINE[7], 17) + D;
  B := ROL(B + (((A xor D) and C) xor A) + X[7] + MD5_SINE[8], 22) + C;
  A := ROL(A + (((D xor C) and B) xor D) + X[8] + MD5_SINE[9], 7) + B;
  D := ROL(D + (((C xor B) and A) xor C) + X[9] + MD5_SINE[10], 12) + A;
  C := ROL(C + (((B xor A) and D) xor B) + X[10] + MD5_SINE[11], 17) + D;
  B := ROL(B + (((A xor D) and C) xor A) + X[11] + MD5_SINE[12], 22) + C;
  A := ROL(A + (((D xor C) and B) xor D) + X[12] + MD5_SINE[13], 7) + B;
  D := ROL(D + (((C xor B) and A) xor C) + X[13] + MD5_SINE[14], 12) + A;
  C := ROL(C + (((B xor A) and D) xor B) + X[14] + MD5_SINE[15], 17) + D;
  B := ROL(B + (((A xor D) and C) xor A) + X[15] + MD5_SINE[16], 22) + C;

  { Round 2 }
  A := ROL(A + (C xor (D and (B xor C))) + X[1] + MD5_SINE[17], 5) + B;
  D := ROL(D + (B xor (C and (A xor B))) + X[6] + MD5_SINE[18], 9) + A;
  C := ROL(C + (A xor (B and (D xor A))) + X[11] + MD5_SINE[19], 14) + D;
  B := ROL(B + (D xor (A and (C xor D))) + X[0] + MD5_SINE[20], 20) + C;
  A := ROL(A + (C xor (D and (B xor C))) + X[5] + MD5_SINE[21], 5) + B;
  D := ROL(D + (B xor (C and (A xor B))) + X[10] + MD5_SINE[22], 9) + A;
  C := ROL(C + (A xor (B and (D xor A))) + X[15] + MD5_SINE[23], 14) + D;
  B := ROL(B + (D xor (A and (C xor D))) + X[4] + MD5_SINE[24], 20) + C;
  A := ROL(A + (C xor (D and (B xor C))) + X[9] + MD5_SINE[25], 5) + B;
  D := ROL(D + (B xor (C and (A xor B))) + X[14] + MD5_SINE[26], 9) + A;
  C := ROL(C + (A xor (B and (D xor A))) + X[3] + MD5_SINE[27], 14) + D;
  B := ROL(B + (D xor (A and (C xor D))) + X[8] + MD5_SINE[28], 20) + C;
  A := ROL(A + (C xor (D and (B xor C))) + X[13] + MD5_SINE[29], 5) + B;
  D := ROL(D + (B xor (C and (A xor B))) + X[2] + MD5_SINE[30], 9) + A;
  C := ROL(C + (A xor (B and (D xor A))) + X[7] + MD5_SINE[31], 14) + D;
  B := ROL(B + (D xor (A and (C xor D))) + X[12] + MD5_SINE[32], 20) + C;

  { Round 3. }
  A := ROL(A + (B xor C xor D) + X[5] + MD5_SINE[33], 4) + B;
  D := ROL(D + (A xor B xor C) + X[8] + MD5_SINE[34], 11) + A;
  C := ROL(C + (D xor A xor B) + X[11] + MD5_SINE[35], 16) + D;
  B := ROL(B + (C xor D xor A) + X[14] + MD5_SINE[36], 23) + C;
  A := ROL(A + (B xor C xor D) + X[1] + MD5_SINE[37], 4) + B;
  D := ROL(D + (A xor B xor C) + X[4] + MD5_SINE[38], 11) + A;
  C := ROL(C + (D xor A xor B) + X[7] + MD5_SINE[39], 16) + D;
  B := ROL(B + (C xor D xor A) + X[10] + MD5_SINE[40], 23) + C;
  A := ROL(A + (B xor C xor D) + X[13] + MD5_SINE[41], 4) + B;
  D := ROL(D + (A xor B xor C) + X[0] + MD5_SINE[42], 11) + A;
  C := ROL(C + (D xor A xor B) + X[3] + MD5_SINE[43], 16) + D;
  B := ROL(B + (C xor D xor A) + X[6] + MD5_SINE[44], 23) + C;
  A := ROL(A + (B xor C xor D) + X[9] + MD5_SINE[45], 4) + B;
  D := ROL(D + (A xor B xor C) + X[12] + MD5_SINE[46], 11) + A;
  C := ROL(C + (D xor A xor B) + X[15] + MD5_SINE[47], 16) + D;
  B := ROL(B + (C xor D xor A) + X[2] + MD5_SINE[48], 23) + C;

  { Round 4. }
  A := ROL(A + ((B or not D) xor C) + X[0] + MD5_SINE[49], 6) + B;
  D := ROL(D + ((A or not C) xor B) + X[7] + MD5_SINE[50], 10) + A;
  C := ROL(C + ((D or not B) xor A) + X[14] + MD5_SINE[51], 15) + D;
  B := ROL(B + ((C or not A) xor D) + X[5] + MD5_SINE[52], 21) + C;
  A := ROL(A + ((B or not D) xor C) + X[12] + MD5_SINE[53], 6) + B;
  D := ROL(D + ((A or not C) xor B) + X[3] + MD5_SINE[54], 10) + A;
  C := ROL(C + ((D or not B) xor A) + X[10] + MD5_SINE[55], 15) + D;
  B := ROL(B + ((C or not A) xor D) + X[1] + MD5_SINE[56], 21) + C;
  A := ROL(A + ((B or not D) xor C) + X[8] + MD5_SINE[57], 6) + B;
  D := ROL(D + ((A or not C) xor B) + X[15] + MD5_SINE[58], 10) + A;
  C := ROL(C + ((D or not B) xor A) + X[6] + MD5_SINE[59], 15) + D;
  B := ROL(B + ((C or not A) xor D) + X[13] + MD5_SINE[60], 21) + C;
  A := ROL(A + ((B or not D) xor C) + X[4] + MD5_SINE[61], 6) + B;
  D := ROL(D + ((A or not C) xor B) + X[11] + MD5_SINE[62], 10) + A;
  C := ROL(C + ((D or not B) xor A) + X[2] + MD5_SINE[63], 15) + D;
  B := ROL(B + ((C or not A) xor D) + X[9] + MD5_SINE[64], 21) + C;

  Inc(FState[0], A);
  Inc(FState[1], B);
  Inc(FState[2], C);
  Inc(FState[3], D);
end;
{$Q+}

function ReadTIdBytesFromStream(const aStream: TStream; var VBytes: TBytes; const ACount: Int64): Int64;
var
  LActual: Integer;
begin
  Assert(aStream <> nil);
  Result := 0;

  if VBytes = nil then
    SetLength(VBytes, 0);

  LActual := ACount;
  if LActual < 0 then
    LActual := aStream.Size - aStream.Position;

  if LActual = 0 then
    Exit;

  if Length(VBytes) < (LActual) then
    SetLength(VBytes, LActual);

  Assert(VBytes <> nil);
  Result := aStream.Read(VBytes[0], LActual);
end;

procedure CopyTIdLongWord(const ASource: LongWord; var VDest: TBytes; const ADestIndex: Integer);
begin
  PLongWord(@VDest[ADestIndex])^ := ASource;
end;

function GetHashBytes(aStream: TStream; ASize: Int64): TBytes;
var
  LStartPos: Integer;
  LSize: Int64;
  LBitSize: Int64;
  i, LReadSize: Integer;
  FState: T4x4LongWordRecord;
  FCBuffer: TBytes;
begin
  Result := nil;

  LSize := ASize;

  for i := 0 to 3 do
    FState[i] := MD4_INIT_VALUES[i];

  while LSize >= 64 do
  begin
    LReadSize := ReadTIdBytesFromStream(aStream, FCBuffer, 64);

    MDCoder(FCBuffer, FState);
    Dec(LSize, LReadSize);
  end;

  LStartPos := ReadTIdBytesFromStream(aStream, FCBuffer, 64);

  FCBuffer[LStartPos] := $80;
  Inc(LStartPos);

  if LStartPos > 56 then
  begin
    for i := LStartPos to 63 do
      FCBuffer[i] := 0;
    MDCoder(FCBuffer, FState);
    LStartPos := 0;
  end;

  for i := LStartPos to 55 do
    FCBuffer[i] := 0;

  LBitSize := ASize * 8;
  for i := 56 to 63 do
  begin
    FCBuffer[i] := LBitSize and $FF;
    LBitSize := LBitSize shr 8;
  end;
  MDCoder(FCBuffer, FState);

  SetLength(Result, SizeOf(LongWord) * 4);
  for i := 0 to 3 do
    CopyTIdLongWord(FState[i], Result, SizeOf(LongWord) * i);
end;

function Hash_Stream(aStream: TStream; const AStartPos, ASize: Int64): TBytes;
var
  LSize, LAvailable: Int64;
begin
  if AStartPos >= 0 then
    aStream.Position := AStartPos;
  LAvailable := aStream.Size - aStream.Position;
  if ASize < 0 then
    LSize := LAvailable
  else
    LSize := Min(LAvailable, ASize);
  Result := GetHashBytes(aStream, LSize);
end;

function BambooMD5Stream(aStream: TStream): TBytes;
begin
  if aStream = nil then
  begin
    Result := nil;
    Exit;
  end;
  aStream.Position := 0;
  Result := Hash_Stream(aStream, -1, -1);
end;

end.

 

原创粉丝点击