255 lines
6.0 KiB
Plaintext
255 lines
6.0 KiB
Plaintext
|
unit IdHashIntf;
|
||
|
|
||
|
interface
|
||
|
{$i IdCompilerDefines.inc}
|
||
|
|
||
|
uses
|
||
|
Classes,
|
||
|
IdFIPS,
|
||
|
IdGlobal, IdHash,
|
||
|
{$IFDEF DOTNET}
|
||
|
System.Security.Cryptography,
|
||
|
IdException
|
||
|
{$ELSE}
|
||
|
IdStreamVCL
|
||
|
{$ENDIF}
|
||
|
;
|
||
|
|
||
|
type
|
||
|
TIdHashInt = class(TIdHash)
|
||
|
protected
|
||
|
function HashToHex(const AHash: TIdBytes): String; override;
|
||
|
function GetHashInst : TIdHashInst; virtual; abstract;
|
||
|
function InitHash : TIdHashIntCtx; virtual;
|
||
|
procedure UpdateHash(ACtx : TIdHashIntCtx; const AIn : TIdBytes);
|
||
|
function FinalHash(ACtx : TIdHashIntCtx) : TIdBytes;
|
||
|
function GetHashBytes(AStream: TStream; ASize: TIdStreamSize): TIdBytes; override;
|
||
|
{$IFNDEF DOTNET}
|
||
|
public
|
||
|
class function IsAvailable : Boolean; override;
|
||
|
{$ENDIF}
|
||
|
end;
|
||
|
TIdHashSHA224 = class(TIdHashInt)
|
||
|
protected
|
||
|
function GetHashInst : TIdHashInst; override;
|
||
|
{$IFNDEF DOTNET}
|
||
|
public
|
||
|
class function IsAvailable : Boolean; override;
|
||
|
{$ENDIF}
|
||
|
end;
|
||
|
TIdHashSHA256 = class(TIdHashInt)
|
||
|
protected
|
||
|
function GetHashInst : TIdHashInst; override;
|
||
|
{$IFNDEF DOTNET}
|
||
|
public
|
||
|
class function IsAvailable : Boolean; override;
|
||
|
{$ENDIF}
|
||
|
end;
|
||
|
TIdHashSHA386 = class(TIdHashInt)
|
||
|
protected
|
||
|
function GetHashInst : TIdHashInst; override;
|
||
|
{$IFNDEF DOTNET}
|
||
|
public
|
||
|
class function IsAvailable : Boolean; override;
|
||
|
{$ENDIF}
|
||
|
end;
|
||
|
TIdHashSHA512 = class(TIdHashInt)
|
||
|
protected
|
||
|
function GetHashInst : TIdHashInst; override;
|
||
|
{$IFNDEF DOTNET}
|
||
|
public
|
||
|
class function IsAvailable : Boolean; override;
|
||
|
{$ENDIF}
|
||
|
end;
|
||
|
{$IFDEF DOTNET}
|
||
|
EIdSecurityAPIException = class(EIdException);
|
||
|
EIdSHA224NotSupported = class(EIdSecurityAPIException);
|
||
|
{$ELSE}
|
||
|
EIdDigestError = class(EIdOpenSSLAPICryptoError);
|
||
|
EIdDigestFinalEx = class(EIdDigestError);
|
||
|
EIdDigestInitEx = class(EIdDigestError);
|
||
|
EIdDigestUpdate = class(EIdDigestError);
|
||
|
{$ENDIF}
|
||
|
|
||
|
implementation
|
||
|
{$IFNDEF DOTNET}
|
||
|
uses IdCTypes;
|
||
|
{$ENDIF}
|
||
|
|
||
|
{ TIdHashInt }
|
||
|
|
||
|
function TIdHashInt.FinalHash(ACtx: TIdHashIntCtx): TIdBytes;
|
||
|
var
|
||
|
{$IFDEF DOTNET}
|
||
|
LDummy : TIdBytes;
|
||
|
{$ELSE}
|
||
|
LLen, LRet : TIdC_UInt;
|
||
|
{$ENDIF}
|
||
|
begin
|
||
|
{$IFDEF DOTNET}
|
||
|
//This is a funny way of coding. I have to pass a dummy value to
|
||
|
//TransformFinalBlock so that things can work similarly to the OpenSSL
|
||
|
//Crypto API. You can't pass nul to TransformFinalBlock without an exception.
|
||
|
SetLength(LDummy,0);
|
||
|
ACtx.TransformFinalBlock(LDummy,0,0);
|
||
|
Result := ACtx.Hash;
|
||
|
{$ELSE}
|
||
|
SetLength(Result,OPENSSL_EVP_MAX_MD_SIZE);
|
||
|
LRet := IdSslEvpDigestFinalEx(@ACtx,@Result[0],LLen);
|
||
|
if LRet <> 1 then begin
|
||
|
EIdDigestFinalEx.RaiseException('EVP_DigestFinal_ex error');
|
||
|
end;
|
||
|
SetLength(Result,LLen);
|
||
|
IdSslEvpMDCtxCleanup(@ACtx);
|
||
|
{$ENDIF}
|
||
|
end;
|
||
|
|
||
|
function TIdHashInt.GetHashBytes(AStream: TStream; ASize: TIdStreamSize): TIdBytes;
|
||
|
var LBuf : TIdBytes;
|
||
|
LSize : Int64;
|
||
|
LCtx : TIdHashIntCtx;
|
||
|
begin
|
||
|
LCtx := InitHash;
|
||
|
try
|
||
|
SetLength(LBuf,2048);
|
||
|
repeat
|
||
|
LSize := ReadTIdBytesFromStream(AStream,LBuf,2048);
|
||
|
if LSize = 0 then begin
|
||
|
break;
|
||
|
end;
|
||
|
if LSize < 2048 then begin
|
||
|
SetLength(LBuf,LSize);
|
||
|
UpdateHash(LCtx,LBuf);
|
||
|
break;
|
||
|
end else begin
|
||
|
UpdateHash(LCtx,LBuf);
|
||
|
end;
|
||
|
until False;
|
||
|
finally
|
||
|
Result := FinalHash(LCtx);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
function TIdHashInt.HashToHex(const AHash: TIdBytes): String;
|
||
|
begin
|
||
|
Result := ToHex(AHash);
|
||
|
end;
|
||
|
|
||
|
function TIdHashInt.InitHash: TIdHashIntCtx;
|
||
|
{$IFNDEF DOTNET}
|
||
|
var
|
||
|
LHash : TIdHashInst;
|
||
|
LRet : TIdC_Int;
|
||
|
{$ENDIF}
|
||
|
begin
|
||
|
{$IFDEF DOTNET}
|
||
|
Result := GetHashInst;
|
||
|
{$ELSE}
|
||
|
LHash := GetHashInst;
|
||
|
IdSslEvpMDCtxInit(@Result);
|
||
|
LRet := IdSslEvpDigestInitEx(@Result, LHash, nil);
|
||
|
if LRet <> 1 then begin
|
||
|
EIdDigestInitEx.RaiseException('EVP_DigestInit_ex error');
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
end;
|
||
|
|
||
|
{$IFNDEF DOTNET}
|
||
|
class function TIdHashInt.IsAvailable: Boolean;
|
||
|
begin
|
||
|
Result := Assigned(IdSslEvpDigestInitEx) and
|
||
|
Assigned(IdSslEvpDigestUpdate) and
|
||
|
Assigned(IdSslEvpDigestFinalEx);
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
|
||
|
procedure TIdHashInt.UpdateHash(ACtx: TIdHashIntCtx; const AIn: TIdBytes);
|
||
|
{$IFNDEF DOTNET}
|
||
|
var LRet : TIdC_Int;
|
||
|
{$ENDIF}
|
||
|
begin
|
||
|
{$IFDEF DOTNET}
|
||
|
ACtx.TransformBlock(AIn,0,Length(AIn),AIn,0);
|
||
|
{$ELSE}
|
||
|
LRet := IdSslEvpDigestUpdate(@ACtx,@Ain[0],Length(AIn));
|
||
|
if LRet <> 1 then begin
|
||
|
EIdDigestInitEx.RaiseException('EVP_DigestUpdate error');
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
end;
|
||
|
|
||
|
{ TIdHashSHA224 }
|
||
|
|
||
|
function TIdHashSHA224.GetHashInst: TIdHashInst;
|
||
|
begin
|
||
|
{$IFDEF DOTNET}
|
||
|
Result := nil;
|
||
|
Raise EIdSHA224NotSupported.Create('SHA224 not supported.');
|
||
|
{$ELSE}
|
||
|
Result := IdSslEvpSHA224;
|
||
|
{$ENDIF}
|
||
|
end;
|
||
|
|
||
|
{$IFNDEF DOTNET}
|
||
|
class function TIdHashSHA224.IsAvailable: Boolean;
|
||
|
begin
|
||
|
Result := Assigned(IdSslEvpSHA224) and inherited IsAvailable;
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
|
||
|
{ TIdHashSHA256 }
|
||
|
|
||
|
function TIdHashSHA256.GetHashInst: TIdHashInst;
|
||
|
begin
|
||
|
{$IFDEF DOTNET}
|
||
|
Result := System.Security.Cryptography.SHA256Managed.Create;
|
||
|
{$ELSE}
|
||
|
Result := IdSslEvpSHA256;
|
||
|
{$ENDIF}
|
||
|
end;
|
||
|
|
||
|
{$IFNDEF DOTNET}
|
||
|
class function TIdHashSHA256.IsAvailable: Boolean;
|
||
|
begin
|
||
|
Result := Assigned(IdSslEvpSHA256) and inherited IsAvailable;
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
|
||
|
{ TIdHashSHA386 }
|
||
|
|
||
|
function TIdHashSHA386.GetHashInst: TIdHashInst;
|
||
|
begin
|
||
|
{$IFDEF DOTNET}
|
||
|
Result := System.Security.Cryptography.SHA384Managed.Create;
|
||
|
{$ELSE}
|
||
|
Result := IdSslEvpSHA384;
|
||
|
{$ENDIF}
|
||
|
end;
|
||
|
|
||
|
{$IFNDEF DOTNET}
|
||
|
class function TIdHashSHA386.IsAvailable: Boolean;
|
||
|
begin
|
||
|
Result := Assigned(IdSslEvpSHA384) and inherited IsAvailable;
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
|
||
|
{ TIdHashSHA512 }
|
||
|
|
||
|
function TIdHashSHA512.GetHashInst: TIdHashInst;
|
||
|
begin
|
||
|
{$IFDEF DOTNET}
|
||
|
Result := System.Security.Cryptography.SHA512Managed.Create;
|
||
|
{$ELSE}
|
||
|
Result := IdSslEvpSHA512;
|
||
|
{$ENDIF}
|
||
|
end;
|
||
|
|
||
|
{$IFNDEF DOTNET}
|
||
|
class function TIdHashSHA512.IsAvailable: Boolean;
|
||
|
begin
|
||
|
Result := Assigned(IdSslEvpSHA512) and inherited IsAvailable;
|
||
|
end;
|
||
|
{$ENDIF}
|
||
|
|
||
|
end.
|