【Delphi】HMACMD5算法(三):实现

 //******************************************************************************
//基于MD5算法的Hash MAC:实现
//******************************************************************************
//作者:Cai
//日期:2011-10-25
//******************************************************************************

unit HMAC_MD5Class;


interface
uses
    MD5Class;

type

THMAC_MD5Context = record
    MD5Context: TMD5Context;
    Key : TBytes_64;
    InPad : TBytes_64;
    OutPad : TBytes_64;
end;

THMAC_MD5Class = Class
protected
    FHash: TMD5Class;
public
    constructor Create(); virtual;
    destructor Destroy; override;
    //=========基于MD5的Hash MAC算法:实现==========
    procedure HMAC_MD5Init(var Context: THMAC_MD5Context; sKey: string);
    procedure HMAC_MD5Update(var Context: THMAC_MD5Context; pInBuffer: PByte; iInBufLen: UINT4);
    procedure HMAC_MD5Final(var Digest: TMD5Digest; var Context: THMAC_MD5Context);
end;


implementation

{ THMAC_MD5Class }

constructor THMAC_MD5Class.Create;
begin
    FHash:=TMD5Class.Create;
end;

destructor THMAC_MD5Class.Destroy;
begin
    FHash.Destroy;
    inherited;
end;

(*引用百科:
HMAC引擎提供HMAC运算步骤:
  (1) 在密钥K后面添加0来创建一个字长为B的字符串。(例如,如果K的字长是20
  字节,B=64字节,则K后会加入44个零字节0x00, 鉴别密钥的长度可以是小于等
于数据块字长的任何正整数值。应用程序中使用的密钥长度若是比B大,则首先
用使用散列函数H作用于它,然后用H输出的L长度字符串作为在HMAC中实际使用
的密钥。一般情况下,推荐的最小密钥K长度是L个字节。)
  (2) 将上一步生成的B字长的字符串与ipad做异或运算。
  (3) 将数据流text填充至第二步的结果字符串中。
  (4) 用H作用于第三步生成的数据流。
  (5) 将第一步生成的B字长字符串与opad做异或运算。
  (6) 再将第四步的结果填充进第五步的结果中。
  (7) 用H作用于第六步生成的数据流,输出最终结果
*)
//基于MD5的HMAC算法 (Hash-MAC算法)
procedure THMAC_MD5Class.HMAC_MD5Init(var Context: THMAC_MD5Context;
sKey: string);
var
    TmpContext: TMD5Context;
     I, iKeyLen: UINT4;
    TmpKey: TMD5Digest;
begin
    FillChar(Context, SizeOf(THMAC_MD5Context), 0);
    iKeyLen := Length(sKey);
    // if key is longer than 64 bytes reset it to key=MD5(key)
    if (iKeyLen > 64) then
    begin
        FHash.MD5Init(TmpContext);
        FHash.MD5Update(TmpContext, PByte(PChar(sKey)), iKeyLen);
        FHash.MD5Final(TmpKey, TmpContext);
        Move(TmpKey, Context.Key, 16);//SizeOf(TmpKey));
        iKeyLen := SizeOf(TBytes_16); //16
    end
    else
    begin
        Move(PChar(sKey)^, Context.Key, iKeyLen);
    end;  

    (* start out by storing key in pads *)

    FillChar(Context.InPad , SizeOf(Context.InPad) , 0);

    FillChar(Context.OutPad, SizeOf(Context.OutPad), 0);
    for i:=0 to iKeyLen-1 do
    begin
        Context.InPad[i] := Context.key[i];
        Context.OutPad[i] := Context.key[i];
    end;
    (* XOR key with ipad and opad values *)
    for i:=0 to 64-1 do
    begin
        Context.InPad[i] := Context.InPad[i] xor $36;
        Context.OutPad[i] := Context.OutPad[i] xor $5C;
    end;
    // perform inner MD5
    // init context for 1st * pass
    FHash.MD5Init(Context.MD5Context);
    //start with inner pad
    FHash.MD5Update(Context.MD5Context, @Context.InPad, 64);
end;

procedure THMAC_MD5Class.HMAC_MD5Update(var Context: THMAC_MD5Context;
    pInBuffer: PByte; iInBufLen: UINT4);
begin
    //then text of datagram
    FHash.MD5Update(Context.MD5Context, pInBuffer, iInBufLen);
end;

procedure THMAC_MD5Class.HMAC_MD5Final(var Digest: TMD5Digest;
    var Context: THMAC_MD5Context);
begin
    //finish up 1st pass
    FHash.MD5Final(Digest, Context.MD5Context);
    // perform outer MD5
    //init context for 2nd * pass
    FHash.MD5Init(Context.MD5Context);
    //start with outer pad
    FHash.MD5Update(Context.MD5Context, @Context.OutPad, 64);
    //then results of 1st * hash
    FHash.MD5Update(Context.MD5Context, @Digest, 16);
    //finish up 2nd pass
    FHash.MD5Final(Digest, Context.MD5Context);
end;

end.
原文地址:https://www.cnblogs.com/caibirdy1985/p/4232964.html