| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513 |
- {
- $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$
- }
- {
- Rev 1.10 7/24/04 12:54:32 PM RLebeau
- Compiler fix for TIdHash128.HashValue()
- Rev 1.9 7/23/04 7:09:12 PM RLebeau
- Added extra exception handling to various HashValue() methods
- Rev 1.8 2004.05.20 11:37:06 AM czhower
- IdStreamVCL
- Rev 1.7 2004.03.03 11:54:30 AM czhower
- IdStream change
- Rev 1.6 2004.02.03 5:44:48 PM czhower
- Name changes
- Rev 1.5 1/27/2004 4:00:08 PM SPerry
- StringStream ->IdStringStream
- Rev 1.4 11/10/2003 7:39:22 PM BGooijen
- Did all todo's ( TStream to TIdStream mainly )
- Rev 1.3 2003.10.24 10:43:08 AM czhower
- TIdSTream to dos
- Rev 1.2 10/18/2003 4:28:30 PM BGooijen
- Removed the pchar for DotNet
- Rev 1.1 10/8/2003 10:15:10 PM GGrieve
- replace TIdReadMemoryStream (might be fast, but not compatible with DotNet)
- Rev 1.0 11/13/2002 08:30:24 AM JPMugaas
- Initial import from FTP VC.
- }
- unit IdHash;
- interface
- {$i IdCompilerDefines.inc}
- uses
- Classes,
- IdFIPS,
- IdGlobal;
- type
- TIdHash = class(TObject)
- protected
- function GetHashBytes(AStream: TStream; ASize: TIdStreamSize): TIdBytes; virtual; abstract;
- function HashToHex(const AHash: TIdBytes): String; virtual; abstract;
- function WordHashToHex(const AHash: TIdBytes; const ACount: Integer): String;
- function LongWordHashToHex(const AHash: TIdBytes; const ACount: Integer): String;
- public
- constructor Create; virtual;
- class function IsAvailable : Boolean; virtual;
- function HashString(const ASrc: string; ADestEncoding: IIdTextEncoding = nil{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}): TIdBytes;
- function HashStringAsHex(const AStr: String; ADestEncoding: IIdTextEncoding = nil{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}): String;
- function HashBytes(const ASrc: TIdBytes): TIdBytes;
- function HashBytesAsHex(const ASrc: TIdBytes): String;
- function HashStream(AStream: TStream): TIdBytes; overload;
- function HashStreamAsHex(AStream: TStream): String; overload;
- function HashStream(AStream: TStream; const AStartPos, ASize: TIdStreamSize): TIdBytes; overload;
- function HashStreamAsHex(AStream: TStream; const AStartPos, ASize: TIdStreamSize): String; overload;
- end;
- TIdHash16 = class(TIdHash)
- protected
- function GetHashBytes(AStream: TStream; ASize: TIdStreamSize): TIdBytes; override;
- function HashToHex(const AHash: TIdBytes): String; override;
- public
- function HashValue(const ASrc: string; ADestEncoding: IIdTextEncoding = nil{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}): UInt16; overload;
- function HashValue(const ASrc: TIdBytes): UInt16; overload;
- function HashValue(AStream: TStream): UInt16; overload;
- function HashValue(AStream: TStream; const AStartPos, ASize: TIdStreamSize): UInt16; overload;
- procedure HashStart(var VRunningHash : UInt16); virtual; abstract;
- procedure HashEnd(var VRunningHash : UInt16); virtual;
- procedure HashByte(var VRunningHash : UInt16; const AByte : Byte); virtual; abstract;
- end;
- TIdHash32 = class(TIdHash)
- protected
- function GetHashBytes(AStream: TStream; ASize: TIdStreamSize): TIdBytes; override;
- function HashToHex(const AHash: TIdBytes): String; override;
- public
- function HashValue(const ASrc: string; ADestEncoding: IIdTextEncoding = nil{$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}): UInt32; overload;
- function HashValue(const ASrc: TIdBytes): UInt32; overload;
- function HashValue(AStream: TStream): UInt32; overload;
- function HashValue(AStream: TStream; const AStartPos, ASize: TIdStreamSize): UInt32; overload;
- procedure HashStart(var VRunningHash : UInt32); virtual; abstract;
- procedure HashEnd(var VRunningHash : UInt32); virtual;
- procedure HashByte(var VRunningHash : UInt32; const AByte : Byte); virtual; abstract;
- end;
- TIdHashClass = class of TIdHash;
- TIdHashIntF = class(TIdHash)
- protected
- function HashToHex(const AHash: TIdBytes): String; override;
- function InitHash : TIdHashIntCtx; virtual; abstract;
- procedure UpdateHash(ACtx : TIdHashIntCtx; const AIn : TIdBytes);
- function FinalHash(ACtx : TIdHashIntCtx) : TIdBytes;
- function GetHashBytes(AStream: TStream; ASize: TIdStreamSize): TIdBytes; override;
- public
- {$IFNDEF DOTNET}
- constructor Create; override;
- {$ENDIF}
- class function IsAvailable : Boolean; override;
- class function IsIntfAvailable : Boolean; virtual;
- end;
- TIdHashNativeAndIntF = class(TIdHashIntF)
- protected
- function NativeGetHashBytes(AStream: TStream; ASize: TIdStreamSize): TIdBytes; virtual;
- function GetHashBytes(AStream: TStream; ASize: TIdStreamSize): TIdBytes; override;
- end;
- {$IFDEF DOTNET}
- EIdSecurityAPIException = class(EIdException);
- EIdSHA224NotSupported = class(EIdSecurityAPIException);
- {$ENDIF}
- function HashFunctionsLoaded: Boolean;
- implementation
- uses
- {$IFDEF DOTNET}
- IdStreamNET,
- {$ELSE}
- IdStreamVCL,
- {$ENDIF}
- IdGlobalProtocols, SysUtils;
- {$IFDEF DOTNET}
- function HashFunctionsLoaded : Boolean;
- {$IFDEF USE_INLINE} inline; {$ENDIF}
- begin
- Result := True;
- end;
- {$ELSE}
- function HashFunctionsLoaded : Boolean;
- begin
- Result := LoadHashLibrary;
- if Result then begin
- Result := IsHashingIntfAvail;
- end;
- end;
- {$ENDIF}
- { TIdHash }
- constructor TIdHash.Create;
- begin
- inherited Create;
- end;
- function TIdHash.HashString(const ASrc: string; ADestEncoding: IIdTextEncoding = nil
- {$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
- ): TIdBytes;
- var
- LStream: TStream; // not TIdStringStream - Unicode on DotNet!
- begin
- LStream := TMemoryStream.Create; try
- WriteStringToStream(LStream, ASrc, ADestEncoding{$IFDEF STRING_IS_ANSI}, ASrcEncoding{$ENDIF});
- LStream.Position := 0;
- Result := HashStream(LStream);
- finally FreeAndNil(LStream); end;
- end;
- function TIdHash.HashStringAsHex(const AStr: String; ADestEncoding: IIdTextEncoding = nil
- {$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
- ): String;
- begin
- Result := HashToHex(HashString(AStr, ADestEncoding{$IFDEF STRING_IS_ANSI}, ASrcEncoding{$ENDIF}));
- end;
- function TIdHash.HashBytes(const ASrc: TIdBytes): TIdBytes;
- var
- LStream: TStream;
- begin
- // TODO: use TBytesStream on versions that support it
- LStream := TMemoryStream.Create; try
- WriteTIdBytesToStream(LStream, ASrc);
- LStream.Position := 0;
- Result := HashStream(LStream);
- finally FreeAndNil(LStream); end;
- end;
- function TIdHash.HashBytesAsHex(const ASrc: TIdBytes): String;
- begin
- Result := HashToHex(HashBytes(ASrc));
- end;
- function TIdHash.HashStream(AStream: TStream): TIdBytes;
- begin
- Result := HashStream(AStream, -1, -1);
- end;
- function TIdHash.HashStreamAsHex(AStream: TStream): String;
- begin
- Result := HashToHex(HashStream(AStream));
- end;
- function TIdHash.HashStream(AStream: TStream; const AStartPos, ASize: TIdStreamSize): TIdBytes;
- var
- LSize, LAvailable: TIdStreamSize;
- begin
- if AStartPos >= 0 then begin
- AStream.Position := AStartPos;
- end;
- LAvailable := AStream.Size - AStream.Position;
- if ASize < 0 then begin
- LSize := LAvailable;
- end else begin
- LSize := IndyMin(LAvailable, ASize);
- end;
- Result := GetHashBytes(AStream, LSize);
- end;
- function TIdHash.HashStreamAsHex(AStream: TStream; const AStartPos, ASize: TIdStreamSize): String;
- begin
- Result := HashToHex(HashStream(AStream, AStartPos, ASize));
- end;
- function TIdHash.WordHashToHex(const AHash: TIdBytes; const ACount: Integer): String;
- var
- LValue: UInt16;
- I: Integer;
- begin
- Result := '';
- for I := 0 to ACount-1 do begin
- LValue := BytesToUInt16(AHash, SizeOf(UInt16)*I);
- Result := Result + IntToHex(LValue, 4);
- end;
- end;
- function TIdHash.LongWordHashToHex(const AHash: TIdBytes; const ACount: Integer): String;
- begin
- Result := ToHex(AHash, ACount*SizeOf(UInt32));
- end;
- class function TIdHash.IsAvailable : Boolean;
- begin
- Result := True;
- end;
- { TIdHash16 }
- function TIdHash16.GetHashBytes(AStream: TStream; ASize: TIdStreamSize): TIdBytes;
- const
- cBufSize = 1024; // Keep it small for dotNet
- var
- I: Integer;
- LBuffer: TIdBytes;
- LSize: Integer;
- LHash: UInt16;
- begin
- Result := nil;
- HashStart(LHash);
- SetLength(LBuffer, cBufSize);
- while ASize > 0 do
- begin
- LSize := ReadTIdBytesFromStream(AStream, LBuffer, IndyMin(cBufSize, ASize));
- if LSize < 1 then begin
- Break; // TODO: throw a stream read exception instead?
- end;
- for i := 0 to LSize - 1 do begin
- HashByte(LHash, LBuffer[i]);
- end;
- Dec(ASize, LSize);
- end;
- HashEnd(LHash);
- SetLength(Result, SizeOf(UInt16));
- CopyTIdUInt16(LHash, Result, 0);
- end;
- function TIdHash16.HashToHex(const AHash: TIdBytes): String;
- begin
- Result := IntToHex(BytesToUInt16(AHash), 4);
- end;
- procedure TIdHash16.HashEnd(var VRunningHash : UInt16);
- begin
- end;
- function TIdHash16.HashValue(const ASrc: string; ADestEncoding: IIdTextEncoding = nil
- {$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
- ): UInt16;
- begin
- Result := BytesToUInt16(HashString(ASrc, ADestEncoding{$IFDEF STRING_IS_ANSI}, ASrcEncoding{$ENDIF}));
- end;
- function TIdHash16.HashValue(const ASrc: TIdBytes): UInt16;
- begin
- Result := BytesToUInt16(HashBytes(ASrc));
- end;
- function TIdHash16.HashValue(AStream: TStream): UInt16;
- begin
- Result := BytesToUInt16(HashStream(AStream));
- end;
- function TIdHash16.HashValue(AStream: TStream; const AStartPos, ASize: TIdStreamSize): UInt16;
- begin
- Result := BytesToUInt16(HashStream(AStream, AStartPos, ASize));
- end;
- { TIdHash32 }
- function TIdHash32.GetHashBytes(AStream: TStream; ASize: TIdStreamSize): TIdBytes;
- const
- cBufSize = 1024; // Keep it small for dotNet
- var
- I: Integer;
- LBuffer: TIdBytes;
- LSize: Integer;
- LHash: UInt32;
- begin
- Result := nil;
- HashStart(LHash);
- SetLength(LBuffer, cBufSize);
- while ASize > 0 do
- begin
- LSize := ReadTIdBytesFromStream(AStream, LBuffer, IndyMin(cBufSize, ASize));
- if LSize < 1 then begin
- Break; // TODO: throw a stream read exception instead?
- end;
- for i := 0 to LSize - 1 do begin
- HashByte(LHash, LBuffer[i]);
- end;
- Dec(ASize, LSize);
- end;
- HashEnd(LHash); // RLebeau: TIdHashCRC32 uses this to XOR the hash with $FFFFFFFF
- SetLength(Result, SizeOf(UInt32));
- CopyTIdUInt32(LHash, Result, 0);
- end;
- function TIdHash32.HashToHex(const AHash: TIdBytes): String;
- begin
- Result := UInt32ToHex(BytesToUInt32(AHash));
- end;
- procedure TIdHash32.HashEnd(var VRunningHash : UInt32);
- begin
- end;
- function TIdHash32.HashValue(const ASrc: string; ADestEncoding: IIdTextEncoding = nil
- {$IFDEF STRING_IS_ANSI}; ASrcEncoding: IIdTextEncoding = nil{$ENDIF}
- ): UInt32;
- begin
- Result := BytesToUInt32(HashString(ASrc, ADestEncoding{$IFDEF STRING_IS_ANSI}, ASrcEncoding{$ENDIF}));
- end;
- function TIdHash32.HashValue(const ASrc: TIdBytes): UInt32;
- begin
- Result := BytesToUInt32(HashBytes(ASrc));
- end;
- function TIdHash32.HashValue(AStream: TStream) : UInt32;
- begin
- Result := BytesToUInt32(HashStream(AStream));
- end;
- function TIdHash32.HashValue(AStream: TStream; const AStartPos, ASize: TIdStreamSize) : UInt32;
- begin
- Result := BytesToUInt32(HashStream(AStream, AStartPos, ASize));
- end;
- { TIdHashIntf }
- {$IFNDEF DOTNET}
- constructor TIdHashIntf.Create;
- begin
- inherited;
- // not checking for load failure here, in case the library
- // is not available but a native implementation is...
- LoadHashLibrary;
- end;
- {$ENDIF}
- function TIdHashIntf.FinalHash(ACtx: TIdHashIntCtx): TIdBytes;
- {$IFDEF DOTNET}
- var
- LDummy : TIdBytes;
- {$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}
- Result := IdFIPS.FinalHashInst(ACtx);
- {$ENDIF}
- end;
- function TIdHashIntf.GetHashBytes(AStream: TStream; ASize: TIdStreamSize): TIdBytes;
- var
- LBuf : TIdBytes;
- LSize : Int64;
- LCtx : TIdHashIntCtx;
- begin
- LCtx := InitHash;
- try
- if ASize > 0 then begin
- SetLength(LBuf, 2048);
- repeat
- LSize := ReadTIdBytesFromStream(AStream,LBuf,IndyMin(ASize, 2048));
- if LSize < 1 then begin
- break; // TODO: throw a stream read exception?
- end;
- if LSize < 2048 then begin
- SetLength(LBuf,LSize);
- UpdateHash(LCtx,LBuf);
- break;
- end;
- UpdateHash(LCtx,LBuf);
- Dec(ASize, LSize);
- until ASize = 0;
- end;
- finally
- Result := FinalHash(LCtx);
- end;
- end;
- function TIdHashIntf.HashToHex(const AHash: TIdBytes): String;
- begin
- Result := ToHex(AHash);
- end;
- {$IFDEF DOTNET}
- class function TIdHashIntf.IsAvailable: Boolean;
- begin
- Result := True;
- end;
- class function TIdHashIntF.IsIntfAvailable: Boolean;
- begin
- Result := False;
- end;
- {$ELSE}
- //done this way so we can override IsAvailble if there is a native
- //implementation.
- class function TIdHashIntf.IsAvailable: Boolean;
- begin
- Result := IsIntfAvailable;
- end;
- class function TIdHashIntF.IsIntfAvailable: Boolean;
- begin
- Result := IsHashingIntfAvail;
- end;
- {$ENDIF}
- procedure TIdHashIntf.UpdateHash(ACtx: TIdHashIntCtx; const AIn: TIdBytes);
- begin
- UpdateHashInst(ACtx,AIn);
- {$IFDEF DOTNET}
- ACtx.TransformBlock(AIn,0,Length(AIn),AIn,0);
- {$ELSE}
- {$ENDIF}
- end;
- { TIdHashNativeAndIntF }
- function TIdHashNativeAndIntF.GetHashBytes(AStream: TStream;
- ASize: TIdStreamSize): TIdBytes;
- begin
- if IsIntfAvailable then begin
- Result := inherited GetHashBytes(AStream, ASize);
- end else begin
- Result := NativeGetHashBytes(AStream, ASize);
- end;
- end;
- function TIdHashNativeAndIntF.NativeGetHashBytes(AStream: TStream;
- ASize: TIdStreamSize): TIdBytes;
- begin
- Result := nil;
- end;
- end.
|