//******************************************************************************
//基于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.