192 lines
4.8 KiB
Plaintext
192 lines
4.8 KiB
Plaintext
{
|
|
$Project$
|
|
$Workfile$
|
|
$Revision$
|
|
$DateUTC$
|
|
$Id$
|
|
|
|
This file is part of the Indy (Internet Direct) project, and is offered
|
|
under the dual-licensing agreement described on the Indy website.
|
|
(http://www.indyproject.org/)
|
|
|
|
Copyright:
|
|
(c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
|
|
}
|
|
{
|
|
$Log$
|
|
}
|
|
{
|
|
HMAC specification on the NIST website
|
|
http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf
|
|
}
|
|
|
|
unit IdHMAC;
|
|
|
|
interface
|
|
|
|
{$i IdCompilerDefines.inc}
|
|
|
|
uses
|
|
Classes,
|
|
IdFIPS,
|
|
IdGlobal, IdHash;
|
|
|
|
type
|
|
TIdHMACKeyBuilder = class(TObject)
|
|
public
|
|
class function Key(const ASize: Integer) : TIdBytes;
|
|
class function IV(const ASize: Integer) : TIdBytes;
|
|
end;
|
|
|
|
TIdHMAC = class
|
|
protected
|
|
FHashSize: Integer; // n bytes
|
|
FBlockSize: Integer; // n bytes
|
|
FKey: TIdBytes;
|
|
FHash: TIdHash;
|
|
FHashName: string;
|
|
procedure InitHash; virtual; abstract;
|
|
procedure InitKey;
|
|
procedure SetHashVars; virtual; abstract;
|
|
function HashValueNative(const ABuffer: TIdBytes; const ATruncateTo: Integer = -1) : TIdBytes; // for now, supply in bytes
|
|
function HashValueIntF(const ABuffer: TIdBytes; const ATruncateTo: Integer = -1) : TIdBytes; // for now, supply in bytes
|
|
function IsIntFAvail : Boolean; virtual;
|
|
function InitIntFInst(const AKey : TIdBytes) : TIdHMACIntCtx; virtual; abstract;
|
|
public
|
|
constructor Create; virtual;
|
|
destructor Destroy; override;
|
|
function HashValue(const ABuffer: TIdBytes; const ATruncateTo: Integer = -1) : TIdBytes; // for now, supply in bytes
|
|
property HashSize: Integer read FHashSize;
|
|
property BlockSize: Integer read FBlockSize;
|
|
property HashName: string read FHashName;
|
|
property Key: TIdBytes read FKey write FKey;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
SysUtils;
|
|
|
|
{ TIdHMACKeyBuilder }
|
|
|
|
class function TIdHMACKeyBuilder.Key(const ASize: Integer): TIdBytes;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
SetLength(Result, ASize);
|
|
for I := Low(Result) to High(Result) do begin
|
|
Result[I] := Byte(Random(255));
|
|
end;
|
|
end;
|
|
|
|
class function TIdHMACKeyBuilder.IV(const ASize: Integer): TIdBytes;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
SetLength(Result, ASize);
|
|
for I := Low(Result) to High(Result) do begin
|
|
Result[I] := Byte(Random(255));
|
|
end;
|
|
end;
|
|
|
|
{ TIdHMAC }
|
|
|
|
constructor TIdHMAC.Create;
|
|
begin
|
|
inherited Create;
|
|
SetLength(FKey, 0);
|
|
SetHashVars;
|
|
if IsHMACAvail then begin
|
|
FHash := nil;
|
|
end else begin
|
|
InitHash;
|
|
end;
|
|
end;
|
|
|
|
destructor TIdHMAC.Destroy;
|
|
begin
|
|
FreeAndNil(FHash);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TIdHMAC.HashValueNative(const ABuffer: TIdBytes; const ATruncateTo: Integer = -1) : TIdBytes; // for now, supply in bytes
|
|
const
|
|
CInnerPad : Byte = $36;
|
|
COuterPad : Byte = $5C;
|
|
var
|
|
TempBuffer1: TIdBytes;
|
|
TempBuffer2: TIdBytes;
|
|
LKey: TIdBytes;
|
|
I: Integer;
|
|
begin
|
|
InitKey;
|
|
LKey := Copy(FKey, 0, MaxInt);
|
|
SetLength(LKey, FBlockSize);
|
|
SetLength(TempBuffer1, FBlockSize + Length(ABuffer));
|
|
for I := Low(LKey) to High(LKey) do begin
|
|
TempBuffer1[I] := LKey[I] xor CInnerPad;
|
|
end;
|
|
CopyTIdBytes(ABuffer, 0, TempBuffer1, Length(LKey), Length(ABuffer));
|
|
TempBuffer2 := FHash.HashBytes(TempBuffer1);
|
|
SetLength(TempBuffer1, 0);
|
|
SetLength(TempBuffer1, FBlockSize + FHashSize);
|
|
for I := Low(LKey) to High(LKey) do begin
|
|
TempBuffer1[I] := LKey[I] xor COuterPad;
|
|
end;
|
|
CopyTIdBytes(TempBuffer2, 0, TempBuffer1, Length(LKey), Length(TempBuffer2));
|
|
Result := FHash.HashBytes(TempBuffer1);
|
|
SetLength(TempBuffer1, 0);
|
|
SetLength(TempBuffer2, 0);
|
|
SetLength(LKey, 0);
|
|
if ATruncateTo > -1 then begin
|
|
SetLength(Result, ATruncateTo);
|
|
end;
|
|
end;
|
|
|
|
function TIdHMAC.HashValueIntF(const ABuffer: TIdBytes; const ATruncateTo: Integer = -1) : TIdBytes; // for now, supply in bytes
|
|
var
|
|
LCtx : TIdHMACIntCtx;
|
|
begin
|
|
if FKey = nil then begin
|
|
FKey := TIdHMACKeyBuilder.Key(FHashSize);
|
|
end;
|
|
LCtx := InitIntFInst(FKey);
|
|
try
|
|
UpdateHMACInst(LCtx,ABuffer);
|
|
finally
|
|
Result := FinalHMACInst(LCtx);
|
|
end;
|
|
if (ATruncateTo >-1) and (ATruncateTo < Length(Result)) then begin
|
|
SetLength(Result, ATruncateTo);
|
|
end;
|
|
end;
|
|
|
|
function TIdHMAC.HashValue(const ABuffer: TIdBytes; const ATruncateTo: Integer = -1): TIdBytes; // for now, supply in bytes
|
|
begin
|
|
if IsIntFAvail then begin
|
|
Result := HashValueIntF(ABuffer,ATruncateTo);
|
|
end else begin
|
|
Result := HashValueNative(ABuffer,ATruncateTo);
|
|
end;
|
|
end;
|
|
|
|
procedure TIdHMAC.InitKey;
|
|
begin
|
|
if FKey = nil then begin
|
|
FKey := TIdHMACKeyBuilder.Key(FHashSize);
|
|
end
|
|
else if Length(FKey) > FBlockSize then begin
|
|
FKey := FHash.HashBytes(FKey);
|
|
end;
|
|
end;
|
|
|
|
function TIdHMAC.IsIntFAvail: Boolean;
|
|
begin
|
|
Result := IsHMACAvail;
|
|
end;
|
|
|
|
initialization
|
|
Randomize;
|
|
|
|
end.
|