IdHashIntf.pas 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. unit IdHashIntf;
  2. interface
  3. {$i IdCompilerDefines.inc}
  4. uses
  5. Classes,
  6. IdFIPS,
  7. IdGlobal, IdHash,
  8. {$IFDEF DOTNET}
  9. System.Security.Cryptography,
  10. IdException
  11. {$ELSE}
  12. IdStreamVCL
  13. {$ENDIF}
  14. ;
  15. type
  16. TIdHashInt = class(TIdHash)
  17. protected
  18. function HashToHex(const AHash: TIdBytes): String; override;
  19. function GetHashInst : TIdHashInst; virtual; abstract;
  20. function InitHash : TIdHashIntCtx; virtual;
  21. procedure UpdateHash(ACtx : TIdHashIntCtx; const AIn : TIdBytes);
  22. function FinalHash(ACtx : TIdHashIntCtx) : TIdBytes;
  23. function GetHashBytes(AStream: TStream; ASize: TIdStreamSize): TIdBytes; override;
  24. {$IFNDEF DOTNET}
  25. public
  26. class function IsAvailable : Boolean; override;
  27. {$ENDIF}
  28. end;
  29. TIdHashSHA224 = class(TIdHashInt)
  30. protected
  31. function GetHashInst : TIdHashInst; override;
  32. {$IFNDEF DOTNET}
  33. public
  34. class function IsAvailable : Boolean; override;
  35. {$ENDIF}
  36. end;
  37. TIdHashSHA256 = class(TIdHashInt)
  38. protected
  39. function GetHashInst : TIdHashInst; override;
  40. {$IFNDEF DOTNET}
  41. public
  42. class function IsAvailable : Boolean; override;
  43. {$ENDIF}
  44. end;
  45. TIdHashSHA386 = class(TIdHashInt)
  46. protected
  47. function GetHashInst : TIdHashInst; override;
  48. {$IFNDEF DOTNET}
  49. public
  50. class function IsAvailable : Boolean; override;
  51. {$ENDIF}
  52. end;
  53. TIdHashSHA512 = class(TIdHashInt)
  54. protected
  55. function GetHashInst : TIdHashInst; override;
  56. {$IFNDEF DOTNET}
  57. public
  58. class function IsAvailable : Boolean; override;
  59. {$ENDIF}
  60. end;
  61. {$IFDEF DOTNET}
  62. EIdSecurityAPIException = class(EIdException);
  63. EIdSHA224NotSupported = class(EIdSecurityAPIException);
  64. {$ELSE}
  65. EIdDigestError = class(EIdOpenSSLAPICryptoError);
  66. EIdDigestFinalEx = class(EIdDigestError);
  67. EIdDigestInitEx = class(EIdDigestError);
  68. EIdDigestUpdate = class(EIdDigestError);
  69. {$ENDIF}
  70. implementation
  71. {$IFNDEF DOTNET}
  72. uses IdCTypes;
  73. {$ENDIF}
  74. { TIdHashInt }
  75. function TIdHashInt.FinalHash(ACtx: TIdHashIntCtx): TIdBytes;
  76. var
  77. {$IFDEF DOTNET}
  78. LDummy : TIdBytes;
  79. {$ELSE}
  80. LLen, LRet : TIdC_UInt;
  81. {$ENDIF}
  82. begin
  83. {$IFDEF DOTNET}
  84. //This is a funny way of coding. I have to pass a dummy value to
  85. //TransformFinalBlock so that things can work similarly to the OpenSSL
  86. //Crypto API. You can't pass nul to TransformFinalBlock without an exception.
  87. SetLength(LDummy,0);
  88. ACtx.TransformFinalBlock(LDummy,0,0);
  89. Result := ACtx.Hash;
  90. {$ELSE}
  91. SetLength(Result,OPENSSL_EVP_MAX_MD_SIZE);
  92. LRet := IdSslEvpDigestFinalEx(@ACtx,@Result[0],LLen);
  93. if LRet <> 1 then begin
  94. EIdDigestFinalEx.RaiseException('EVP_DigestFinal_ex error');
  95. end;
  96. SetLength(Result,LLen);
  97. IdSslEvpMDCtxCleanup(@ACtx);
  98. {$ENDIF}
  99. end;
  100. function TIdHashInt.GetHashBytes(AStream: TStream; ASize: TIdStreamSize): TIdBytes;
  101. var LBuf : TIdBytes;
  102. LSize : Int64;
  103. LCtx : TIdHashIntCtx;
  104. begin
  105. LCtx := InitHash;
  106. try
  107. SetLength(LBuf,2048);
  108. repeat
  109. LSize := ReadTIdBytesFromStream(AStream,LBuf,2048);
  110. if LSize = 0 then begin
  111. break;
  112. end;
  113. if LSize < 2048 then begin
  114. SetLength(LBuf,LSize);
  115. UpdateHash(LCtx,LBuf);
  116. break;
  117. end else begin
  118. UpdateHash(LCtx,LBuf);
  119. end;
  120. until False;
  121. finally
  122. Result := FinalHash(LCtx);
  123. end;
  124. end;
  125. function TIdHashInt.HashToHex(const AHash: TIdBytes): String;
  126. begin
  127. Result := ToHex(AHash);
  128. end;
  129. function TIdHashInt.InitHash: TIdHashIntCtx;
  130. {$IFNDEF DOTNET}
  131. var
  132. LHash : TIdHashInst;
  133. LRet : TIdC_Int;
  134. {$ENDIF}
  135. begin
  136. {$IFDEF DOTNET}
  137. Result := GetHashInst;
  138. {$ELSE}
  139. LHash := GetHashInst;
  140. IdSslEvpMDCtxInit(@Result);
  141. LRet := IdSslEvpDigestInitEx(@Result, LHash, nil);
  142. if LRet <> 1 then begin
  143. EIdDigestInitEx.RaiseException('EVP_DigestInit_ex error');
  144. end;
  145. {$ENDIF}
  146. end;
  147. {$IFNDEF DOTNET}
  148. class function TIdHashInt.IsAvailable: Boolean;
  149. begin
  150. Result := Assigned(IdSslEvpDigestInitEx) and
  151. Assigned(IdSslEvpDigestUpdate) and
  152. Assigned(IdSslEvpDigestFinalEx);
  153. end;
  154. {$ENDIF}
  155. procedure TIdHashInt.UpdateHash(ACtx: TIdHashIntCtx; const AIn: TIdBytes);
  156. {$IFNDEF DOTNET}
  157. var LRet : TIdC_Int;
  158. {$ENDIF}
  159. begin
  160. {$IFDEF DOTNET}
  161. ACtx.TransformBlock(AIn,0,Length(AIn),AIn,0);
  162. {$ELSE}
  163. LRet := IdSslEvpDigestUpdate(@ACtx,@Ain[0],Length(AIn));
  164. if LRet <> 1 then begin
  165. EIdDigestInitEx.RaiseException('EVP_DigestUpdate error');
  166. end;
  167. {$ENDIF}
  168. end;
  169. { TIdHashSHA224 }
  170. function TIdHashSHA224.GetHashInst: TIdHashInst;
  171. begin
  172. {$IFDEF DOTNET}
  173. Result := nil;
  174. Raise EIdSHA224NotSupported.Create('SHA224 not supported.');
  175. {$ELSE}
  176. Result := IdSslEvpSHA224;
  177. {$ENDIF}
  178. end;
  179. {$IFNDEF DOTNET}
  180. class function TIdHashSHA224.IsAvailable: Boolean;
  181. begin
  182. Result := Assigned(IdSslEvpSHA224) and inherited IsAvailable;
  183. end;
  184. {$ENDIF}
  185. { TIdHashSHA256 }
  186. function TIdHashSHA256.GetHashInst: TIdHashInst;
  187. begin
  188. {$IFDEF DOTNET}
  189. Result := System.Security.Cryptography.SHA256Managed.Create;
  190. {$ELSE}
  191. Result := IdSslEvpSHA256;
  192. {$ENDIF}
  193. end;
  194. {$IFNDEF DOTNET}
  195. class function TIdHashSHA256.IsAvailable: Boolean;
  196. begin
  197. Result := Assigned(IdSslEvpSHA256) and inherited IsAvailable;
  198. end;
  199. {$ENDIF}
  200. { TIdHashSHA386 }
  201. function TIdHashSHA386.GetHashInst: TIdHashInst;
  202. begin
  203. {$IFDEF DOTNET}
  204. Result := System.Security.Cryptography.SHA384Managed.Create;
  205. {$ELSE}
  206. Result := IdSslEvpSHA384;
  207. {$ENDIF}
  208. end;
  209. {$IFNDEF DOTNET}
  210. class function TIdHashSHA386.IsAvailable: Boolean;
  211. begin
  212. Result := Assigned(IdSslEvpSHA384) and inherited IsAvailable;
  213. end;
  214. {$ENDIF}
  215. { TIdHashSHA512 }
  216. function TIdHashSHA512.GetHashInst: TIdHashInst;
  217. begin
  218. {$IFDEF DOTNET}
  219. Result := System.Security.Cryptography.SHA512Managed.Create;
  220. {$ELSE}
  221. Result := IdSslEvpSHA512;
  222. {$ENDIF}
  223. end;
  224. {$IFNDEF DOTNET}
  225. class function TIdHashSHA512.IsAvailable: Boolean;
  226. begin
  227. Result := Assigned(IdSslEvpSHA512) and inherited IsAvailable;
  228. end;
  229. {$ENDIF}
  230. end.