IdHMAC.pas 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. {
  2. $Project$
  3. $Workfile$
  4. $Revision$
  5. $DateUTC$
  6. $Id$
  7. This file is part of the Indy (Internet Direct) project, and is offered
  8. under the dual-licensing agreement described on the Indy website.
  9. (http://www.indyproject.org/)
  10. Copyright:
  11. (c) 1993-2005, Chad Z. Hower and the Indy Pit Crew. All rights reserved.
  12. }
  13. {
  14. $Log$
  15. }
  16. {
  17. HMAC specification on the NIST website
  18. http://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf
  19. }
  20. unit IdHMAC;
  21. interface
  22. {$i IdCompilerDefines.inc}
  23. uses
  24. Classes,
  25. IdFIPS,
  26. IdGlobal, IdHash;
  27. type
  28. TIdHMACKeyBuilder = class(TObject)
  29. public
  30. class function Key(const ASize: Integer) : TIdBytes;
  31. class function IV(const ASize: Integer) : TIdBytes;
  32. end;
  33. TIdHMAC = class
  34. protected
  35. FHashSize: Integer; // n bytes
  36. FBlockSize: Integer; // n bytes
  37. FKey: TIdBytes;
  38. FHash: TIdHash;
  39. FHashName: string;
  40. procedure InitHash; virtual; abstract;
  41. procedure InitKey;
  42. procedure SetHashVars; virtual; abstract;
  43. function HashValueNative(const ABuffer: TIdBytes; const ATruncateTo: Integer = -1) : TIdBytes; // for now, supply in bytes
  44. function HashValueIntF(const ABuffer: TIdBytes; const ATruncateTo: Integer = -1) : TIdBytes; // for now, supply in bytes
  45. function IsIntFAvail : Boolean; virtual;
  46. function InitIntFInst(const AKey : TIdBytes) : TIdHMACIntCtx; virtual; abstract;
  47. public
  48. constructor Create; virtual;
  49. destructor Destroy; override;
  50. function HashValue(const ABuffer: TIdBytes; const ATruncateTo: Integer = -1) : TIdBytes; // for now, supply in bytes
  51. property HashSize: Integer read FHashSize;
  52. property BlockSize: Integer read FBlockSize;
  53. property HashName: string read FHashName;
  54. property Key: TIdBytes read FKey write FKey;
  55. end;
  56. implementation
  57. uses
  58. SysUtils;
  59. { TIdHMACKeyBuilder }
  60. class function TIdHMACKeyBuilder.Key(const ASize: Integer): TIdBytes;
  61. var
  62. I: Integer;
  63. begin
  64. SetLength(Result, ASize);
  65. for I := Low(Result) to High(Result) do begin
  66. Result[I] := Byte(Random(255));
  67. end;
  68. end;
  69. class function TIdHMACKeyBuilder.IV(const ASize: Integer): TIdBytes;
  70. var
  71. I: Integer;
  72. begin
  73. SetLength(Result, ASize);
  74. for I := Low(Result) to High(Result) do begin
  75. Result[I] := Byte(Random(255));
  76. end;
  77. end;
  78. { TIdHMAC }
  79. constructor TIdHMAC.Create;
  80. begin
  81. inherited Create;
  82. SetLength(FKey, 0);
  83. SetHashVars;
  84. LoadHashLibrary;
  85. if IsIntFAvail then begin
  86. FHash := nil;
  87. end else begin
  88. InitHash;
  89. end;
  90. end;
  91. destructor TIdHMAC.Destroy;
  92. begin
  93. FreeAndNil(FHash);
  94. inherited Destroy;
  95. end;
  96. function TIdHMAC.HashValueNative(const ABuffer: TIdBytes; const ATruncateTo: Integer = -1) : TIdBytes; // for now, supply in bytes
  97. const
  98. CInnerPad : Byte = $36;
  99. COuterPad : Byte = $5C;
  100. var
  101. TempBuffer1: TIdBytes;
  102. TempBuffer2: TIdBytes;
  103. LKey: TIdBytes;
  104. I: Integer;
  105. begin
  106. InitKey;
  107. LKey := Copy(FKey, 0, MaxInt);
  108. SetLength(LKey, FBlockSize);
  109. SetLength(TempBuffer1, FBlockSize + Length(ABuffer));
  110. for I := Low(LKey) to High(LKey) do begin
  111. TempBuffer1[I] := LKey[I] xor CInnerPad;
  112. end;
  113. CopyTIdBytes(ABuffer, 0, TempBuffer1, Length(LKey), Length(ABuffer));
  114. TempBuffer2 := FHash.HashBytes(TempBuffer1);
  115. SetLength(TempBuffer1, 0);
  116. SetLength(TempBuffer1, FBlockSize + FHashSize);
  117. for I := Low(LKey) to High(LKey) do begin
  118. TempBuffer1[I] := LKey[I] xor COuterPad;
  119. end;
  120. CopyTIdBytes(TempBuffer2, 0, TempBuffer1, Length(LKey), Length(TempBuffer2));
  121. Result := FHash.HashBytes(TempBuffer1);
  122. SetLength(TempBuffer1, 0);
  123. SetLength(TempBuffer2, 0);
  124. SetLength(LKey, 0);
  125. if ATruncateTo > -1 then begin
  126. SetLength(Result, ATruncateTo);
  127. end;
  128. end;
  129. function TIdHMAC.HashValueIntF(const ABuffer: TIdBytes; const ATruncateTo: Integer = -1) : TIdBytes; // for now, supply in bytes
  130. var
  131. LCtx : TIdHMACIntCtx;
  132. begin
  133. if FKey = nil then begin
  134. FKey := TIdHMACKeyBuilder.Key(FHashSize);
  135. end;
  136. LCtx := InitIntFInst(FKey);
  137. try
  138. UpdateHMACInst(LCtx,ABuffer);
  139. finally
  140. Result := FinalHMACInst(LCtx);
  141. end;
  142. if (ATruncateTo >-1) and (ATruncateTo < Length(Result)) then begin
  143. SetLength(Result, ATruncateTo);
  144. end;
  145. end;
  146. function TIdHMAC.HashValue(const ABuffer: TIdBytes; const ATruncateTo: Integer = -1): TIdBytes; // for now, supply in bytes
  147. begin
  148. if IsIntFAvail then begin
  149. Result := HashValueIntF(ABuffer,ATruncateTo);
  150. end else begin
  151. Result := HashValueNative(ABuffer,ATruncateTo);
  152. end;
  153. end;
  154. procedure TIdHMAC.InitKey;
  155. begin
  156. if FKey = nil then begin
  157. FKey := TIdHMACKeyBuilder.Key(FHashSize);
  158. end
  159. else if Length(FKey) > FBlockSize then begin
  160. FKey := FHash.HashBytes(FKey);
  161. end;
  162. end;
  163. function TIdHMAC.IsIntFAvail: Boolean;
  164. begin
  165. Result := IsHMACAvail;
  166. end;
  167. initialization
  168. Randomize;
  169. end.