12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169 |
- {
- This file is part of the Free Component Library (FCL)
- Copyright (c) 2023 the Free Pascal team
- Delphi-compatible hash unit
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- unit System.Hash;
- {$mode objfpc}
- {$modeswitch advancedrecords}
- {$macro on}
- interface
- uses
- {$IFDEF FPC_DOTTEDUNITS}
- System.Classes, System.SysUtils, System.Hash.Md5, System.Hash.Sha1, System.Hash.Fnv, System.Hash.Sha256, System.Hash.Sha512;
- {$ELSE}
- Classes, SysUtils, md5, sha1, fnvhash, fpsha256, fpsha512;
- {$ENDIF}
- const
- HashReadBufferSize = 4096; // Use 4k buffer.
- type
- EHashException = class(Exception);
- { THash }
- THash = record
- class function DigestAsInteger(const aDigest: TBytes): Integer; static;
- class function DigestAsString(const aDigest: TBytes; UpperCase : Boolean = false): UnicodeString; static;
- class function DigestAsStringGUID(const aDigest: TBytes): UnicodeString; static;
- class function GetRandomString(const aLen: Integer = 10): UnicodeString; static;
- class function ToBigEndian(aValue: Cardinal): Cardinal; overload; static; inline;
- class function ToBigEndian(aValue: UInt64): UInt64; overload; static; inline;
- end;
- { THashMD5 }
- THashMD5 = record
- Private
- _MD5 : TMD5Context;
- _Digest : TMD5Digest;
- _DidFinal : Boolean;
- public
- class function Create: THashMD5; static; inline;
- class function GetHashBytes(const aData: UnicodeString): TBytes; overload; static;
- class function GetHashString(const aData: UnicodeString): UnicodeString; overload; static; inline;
- class function GetHashBytes(const aStream: TStream): TBytes; overload; static;
- class function GetHashString(const aStream: TStream): UnicodeString; overload; static; inline;
- class function GetHashBytesFromFile(const aFileName: TFileName): TBytes; static;
- class function GetHashStringFromFile(const aFileName: TFileName): UnicodeString; static; inline;
- class function GetHMAC(const aData,aKey: UnicodeString): UnicodeString; static; inline;
- class function GetHMACAsBytes(const aData,aKey: UnicodeString): TBytes; overload; static;
- class function GetHMACAsBytes(const aData: UnicodeString; const aKey: TBytes): TBytes; overload; static;
- class function GetHMACAsBytes(const aData: TBytes; const aKey: UnicodeString): TBytes; overload; static;
- class function GetHMACAsBytes(const aData,aKey: TBytes): TBytes; overload; static;
- procedure Reset;
- procedure Update(var aData; aLength: Cardinal); overload;
- procedure Update(const aData: TBytes; aLength: Cardinal = 0); overload; {inline;}
- procedure Update(const aData: UnicodeString); overload; {inline;}
- function GetDigest: TBytes;
- function GetBlockSize: Integer; inline;
- function GetHashSize: Integer; inline;
- function HashAsBytes: TBytes; inline;
- function HashAsString: UnicodeString; // inline;
- end;
- { THashSHA1 }
- THashSHA1 = record
- private
- _SHA1 : TSHA1Context;
- _Digest : TSHA1Digest;
- _DidFinal : Boolean;
- public
- class function Create: THashSHA1; static; // inline;
- class function GetHashBytes(const aData: UnicodeString): TBytes; overload; static;
- class function GetHashString(const aData: UnicodeString): UnicodeString; overload; static; // inline;
- class function GetHashBytes(const aStream: TStream): TBytes; overload; static;
- class function GetHashString(const aStream: TStream): UnicodeString; overload; static; // inline;
- class function GetHashBytesFromFile(const aFileName: TFileName): TBytes; static;
- class function GetHashStringFromFile(const aFileName: TFileName): UnicodeString; static; // inline;
- class function GetHMAC(const aData, aKey: UnicodeString): UnicodeString; static; // inline;
- class function GetHMACAsBytes(const aData, aKey: UnicodeString): TBytes; overload; static;
- class function GetHMACAsBytes(const aData: UnicodeString; const aKey: TBytes): TBytes; overload; static;
- class function GetHMACAsBytes(const aData: TBytes; const aKey: UnicodeString): TBytes; overload; static;
- class function GetHMACAsBytes(const aData, aKey: TBytes): TBytes; overload; static;
- procedure Reset; inline;
- procedure Update(var aData; aLength: Cardinal); overload;
- procedure Update(const aData: TBytes; aLength: Cardinal = 0); overload;
- procedure Update(const aData: UnicodeString); overload; // inline;
- function GetDigest: TBytes;
- function GetBlockSize: Integer; inline;
- function GetHashSize: Integer; inline;
- function HashAsBytes: TBytes; inline;
- function HashAsString: UnicodeString; // inline;
- end;
- { THashSHA2 }
- THashSHA2 = record
- public type
- TSHA2Version = (SHA224, SHA256, SHA384, SHA512, SHA512_224, SHA512_256);
- public
- class function Create(aHashVersion: TSHA2Version = TSHA2Version.SHA256): THashSHA2; static; inline;
- class function GetHashBytes(const aData: UnicodeString; aHashVersion: TSHA2Version = TSHA2Version.SHA256): TBytes; overload; static;
- class function GetHashString(const aData: UnicodeString; aHashVersion: TSHA2Version = TSHA2Version.SHA256): UnicodeString; overload; static; inline;
- class function GetHashBytes(const aStream: TStream; aHashVersion: TSHA2Version = TSHA2Version.SHA256): TBytes; overload; static;
- class function GetHashString(const aStream: TStream; aHashVersion: TSHA2Version = TSHA2Version.SHA256): UnicodeString; overload; static; inline;
- class function GetHashBytesFromFile(const aFileName: TFileName; aHashVersion: TSHA2Version = TSHA2Version.SHA256): TBytes; static;
- class function GetHashStringFromFile(const aFileName: TFileName; aHashVersion: TSHA2Version = TSHA2Version.SHA256): UnicodeString; static; inline;
- class function GetHMAC(const aData, aKey: UnicodeString; aHashVersion: TSHA2Version = TSHA2Version.SHA256): UnicodeString; static; inline;
- class function GetHMACAsBytes(const aData, aKey: UnicodeString; aHashVersion: TSHA2Version = TSHA2Version.SHA256): TBytes; overload; static;
- class function GetHMACAsBytes(const aData: UnicodeString; const aKey: TBytes; aHashVersion: TSHA2Version = TSHA2Version.SHA256): TBytes; overload; static;
- class function GetHMACAsBytes(const aData: TBytes; const aKey: UnicodeString; aHashVersion: TSHA2Version = TSHA2Version.SHA256): TBytes; overload; static;
- class function GetHMACAsBytes(const aData, aKey: TBytes; aHashVersion: TSHA2Version = TSHA2Version.SHA256): TBytes; overload; static;
- procedure Reset; inline;
- procedure Update(var aData; aLength: Cardinal); overload;
- procedure Update(const aData : PByte; aLength: Cardinal); overload;
- procedure Update(const aData: TBytes; aLength: Cardinal = 0); overload;
- procedure Update(const aData: UnicodeString); overload;
- procedure Update(const aData: RawByteString); overload;
- function GetDigest: TBytes;
- function GetBlockSize: Integer; inline;
- function GetHashSize: Integer; inline;
- function HashAsBytes: TBytes; // inline;
- function HashAsString: UnicodeString; // inline;
- Private
- procedure DoFinal;
- private
- FDidFinal : Boolean;
- case FHashVersion: TSHA2Version of
- Sha224 : (_S224 : TSHA224);
- Sha256 : (_S256 : TSHA256);
- Sha384 : (_S384 : TSHA384);
- Sha512 : (_S512 : TSHA512);
- end;
- { THashBobJenkins }
- THashBobJenkins = record
- Private
- FCurrent : Cardinal;
- public
- class function Create: THashBobJenkins; static;
- class function GetHashBytes(const aData: UnicodeString): TBytes; static;
- class function GetHashString(const aData: UnicodeString): UnicodeString; static;
- class function GetHashString(const aData: RawByteString): UnicodeString; static;
- class function GetHashValue(const aData: UnicodeString): Integer; overload; static;
- class function GetHashValue(const aData: RawByteString): Integer; overload; static;
- class function GetHashValue(var aData; aLength: Integer; aInitialValue: Integer = 0): Integer; overload; static;
- class function GetHashValue(const aData : PByte; aLength: Integer; aInitialValue: Integer = 0): Integer; overload; static;
- procedure Reset(aInitialValue: Integer = 0);
- procedure Update(var aData; aLength: Cardinal); overload;
- procedure Update(aData : PByte; aLength: Cardinal); overload;
- procedure Update(const aData: TBytes; aLength: Cardinal = 0); overload;
- procedure Update(const aData: UnicodeString); overload;
- procedure Update(const aData: RawByteString); overload;
- function HashAsBytes: TBytes;
- function HashAsInteger: Integer;
- function HashAsString: UnicodeString;
- end;
- { THashFNV1a32 }
- THashFNV1a32 = record
- public const
- FNV_PRIME = FNV_32_PRIME;
- FNV_SEED = FNV1_32_INIT;
- private
- FCurrent : Fnv32_t;
- public
- class function Create: THashFNV1a32; static;
- class function GetHashBytes(const aData: UnicodeString): TBytes; static;
- class function GetHashString(const aData: UnicodeString): UnicodeString; overload; static;
- class function GetHashString(const aData: RawByteString): UnicodeString; overload; static;
- class function GetHashValue(const aData: UnicodeString): Integer; overload; static; // inline;
- class function GetHashValue(const aData: RawByteString): Integer; overload; static; // inline;
- class function GetHashValue(const aData; aLength: Cardinal; aInitialValue: Cardinal = FNV_SEED): Integer; overload; static; // inline;
- procedure Reset(aInitialValue: Cardinal = FNV_SEED);
- procedure Update(const aData; aLength: Cardinal); overload; // inline;
- procedure Update(const aData: TBytes; aLength: Cardinal = 0); overload; // inline;
- procedure Update(const aData: UnicodeString); overload; // inline;
- procedure Update(const aData: RawByteString); overload; // inline;
- function GetDigest : TBytes;
- function HashAsBytes: TBytes;
- function HashAsInteger: Integer;
- function HashAsString: UnicodeString;
- end;
- const
- SHashCanNotUpdateMD5 = 'MD5: Cannot update a finalized hash';
- SHashCanNotUpdateSHA1 = 'SHA1: Cannot update a finalized hash';
- SHashCanNotUpdateSHA2 = 'SHA2: Cannot update a finalized hash';
- RandomStringChars = UnicodeString('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+-/*_');
- RandomStringCharCount = Length(RandomStringChars);
- implementation
- Uses
- {$IFDEF FPC_DOTTEDUNITS}
- System.Types, System.SysConst, System.Generics.Hashes;
- {$ELSE}
- Types, SysConst, Generics.Hashes;
- {$ENDIF}
- Resourcestring
- SErrDigestSizeMustBe4 = 'Digest size must be 4, got %d instead.';
- { THash }
- class function THash.ToBigEndian(aValue: Cardinal): Cardinal;
- begin
- Result:=NtoBE(aValue);
- end;
- class function THash.ToBigEndian(aValue: UInt64): UInt64;
- begin
- Result:=NtoBE(aValue);
- end;
- class function THash.DigestAsInteger(const aDigest: TBytes): Integer;
- begin
- if Length(aDigest) <> 4 then
- raise EHashException.CreateFmt(SErrDigestSizeMustBe4,[Length(aDigest)]);
- Result:= PLongInt(@ADigest[0])^;
- end;
- class function THash.DigestAsString(const aDigest: TBytes; UpperCase: Boolean): UnicodeString;
- const
- HexDigitsWL: array[0..15] of widechar = '0123456789abcdef';
- var
- S : UnicodeString;
- I,Len: Integer;
- H,Res : PWideChar;
- PB : PByte;
- B : Byte;
- begin
- S:='';
- if Uppercase then
- H:=@HexDigitsW
- else
- H:=@HexDigitsWL;
- Len:=Length(aDigest);
- SetLength(S,2*Len);
- Res:=PWideChar(S);
- PB:=PByte(aDigest);
- for I:=1 to Len do
- begin
- B:=PB^;
- Res^:=H[B shr 4];
- inc(Res);
- Res^:=H[B and 15];
- Inc(Res);
- Inc(PB);
- end;
- Result:=S;
- end;
- class function THash.DigestAsStringGUID(const aDigest: TBytes): UnicodeString;
- begin
- With TGUID.Create(aDigest,TEndian.Little) do
- begin
- D1:=ToBigEndian(D1);
- D2:=Swap(D2);
- D3:=Swap(D3);
- {$IF SIZEOF(Char)=2}
- Result:=ToString;
- {$ELSE}
- Result:=Utf8Decode(ToString);
- {$ENDIF}
- end;
- end;
- class function THash.GetRandomString(const aLen: Integer): UnicodeString;
- var
- I : Integer;
- Res: PWideChar;
- begin
- Result:='';
- SetLength(Result,aLen);
- Res:=PWideChar(Result);
- for I:=1 to ALen do
- begin
- Res^:=RandomStringChars[1+Random(RandomStringCharCount)];
- Inc(Res);
- end;
- end;
- { THashMD5 }
- class function THashMD5.Create: THashMD5;
- begin
- Result:=Default(THashMD5);
- Result.Reset;
- end;
- function THashMD5.GetBlockSize: Integer;
- begin
- Result:=64;
- end;
- function THashMD5.GetHashSize: Integer;
- begin
- Result:=SizeOf(TMD5Digest);
- end;
- class function THashMD5.GetHashBytes(const aData: UnicodeString): TBytes;
- begin
- With THashMD5.Create do
- begin
- Update(aData);
- Result:=GetDigest;
- end;
- end;
- class function THashMD5.GetHashString(const aData: UnicodeString): UnicodeString;
- begin
- With THashMD5.Create do
- begin
- Update(aData);
- Result:=HashAsString;
- end;
- end;
- class function THashMD5.GetHashBytes(const aStream: TStream): TBytes;
- var
- Buf: TBytes;
- Len,Count: Longint;
- begin
- Buf:=Default(TBytes);
- Len:=HashReadBufferSize;
- SetLength(Buf,Len);
- With THashMD5.Create do
- begin
- Count:=aStream.Read(Buf,Len);
- While (Count>0) do
- begin
- Update(Buf,Count);
- Count:=aStream.Read(Buf,Len);
- end;
- Result:=GetDigest;
- end;
- end;
- class function THashMD5.GetHashString(const aStream: TStream): UnicodeString;
- begin
- Result:=THash.DigestAsString(GetHashBytes(aStream));
- end;
- class function THashMD5.GetHashBytesFromFile(const aFileName: TFileName): TBytes;
- var
- F: TFileStream;
- begin
- F:=TFileStream.Create(aFileName,fmOpenRead or fmShareDenyWrite);
- try
- Result:=GetHashBytes(F);
- finally
- F.Free;
- end;
- end;
- class function THashMD5.GetHashStringFromFile(const aFileName: TFileName): UnicodeString;
- begin
- Result:=THash.DigestAsString(GetHashBytesFromFile(aFileName));
- end;
- class function THashMD5.GetHMAC(const aData,aKey: UnicodeString): UnicodeString;
- begin
- Result:=THash.DigestAsString(GetHMACAsBytes(aData,aKey));
- end;
- class function THashMD5.GetHMACAsBytes(const aData, aKey: UnicodeString): TBytes;
- begin
- With TEncoding.UTF8 do
- Result:=GetHMACAsBytes(GetBytes(aData),GetBytes(aKey));
- end;
- class function THashMD5.GetHMACAsBytes(const aData: UnicodeString; const aKey: TBytes): TBytes;
- begin
- With TEncoding.UTF8 do
- Result:=GetHMACAsBytes(GetBytes(aData),aKey);
- end;
- class function THashMD5.GetHMACAsBytes(const aData: TBytes; const aKey: UnicodeString): TBytes;
- begin
- With TEncoding.UTF8 do
- Result:=GetHMACAsBytes(aData,GetBytes(aKey));
- end;
- class function THashMD5.GetHMACAsBytes(const aData, aKey: TBytes): TBytes;
- var
- I: Byte;
- MD5_BLOCK_SIZE : Integer;
- VLength: PtrUInt;
- PKey, POPad, PIPad: PByte;
- VKey, VOPad, VIPad: TBytes;
- MD5 : THashMD5;
- begin
- VKey:=Default(TBytes);
- VOPad:=Default(TBytes);
- VIPad:=Default(TBytes);
- MD5:=THashMD5.Create;
- MD5_BLOCK_SIZE:=MD5.GetBlockSize;
- VLength:=Length(aKey);
- if VLength > MD5_BLOCK_SIZE then
- begin
- SetLength(VKey,MD5_BLOCK_SIZE);
- FillChar(VKey[0],MD5_BLOCK_SIZE, #0);
- MD5.Update(aKey);
- VKey:=Concat(MD5.GetDigest,VKey);
- end
- else
- begin
- SetLength(VKey,MD5_BLOCK_SIZE-VLength);
- FillChar(VKey[0],MD5_BLOCK_SIZE-VLength, #0);
- VKey:=Concat(aKey,VKey);
- end;
- SetLength(VOPad,MD5_BLOCK_SIZE);
- POPad:=PByte(VOPad);
- FillChar(POPad^, MD5_BLOCK_SIZE, $5c);
- SetLength(VIPad, MD5_BLOCK_SIZE);
- PIPad := PByte(VIPad);
- FillChar(PIPad^, MD5_BLOCK_SIZE, $36);
- PKey := PByte(VKey);
- for I:=1 to VLength do
- begin
- POPad^:=(POPad^ xor PKey^);
- PIPad^:=(PIPad^ xor PKey^);
- Inc(POPad);
- Inc(PIPad);
- Inc(PKey);
- end;
- VIPad:=Concat(VIPad,aData);
- MD5.Reset;
- MD5.Update(VIPad);
- Result:=Concat(VOPad,MD5.GetDigest);
- end;
- procedure THashMD5.Reset;
- begin
- MD5Init(_MD5);
- end;
- procedure THashMD5.Update(var aData; aLength: Cardinal);
- begin
- MD5Update(_MD5,aData,aLength);
- end;
- procedure THashMD5.Update(const aData: TBytes; aLength: Cardinal);
- begin
- if aLength=0 then
- aLength:=Length(aData);
- MD5Update(_MD5,aData[0],aLength);
- end;
- procedure THashMD5.Update(const aData: UnicodeString);
- begin
- Update(TEncoding.UTF8.GetBytes(aData));
- end;
- function THashMD5.GetDigest: TBytes;
- begin
- Result:=[];
- if not _DidFinal then
- begin
- _DidFinal:=True;
- MD5Final(_MD5,_Digest);
- end;
- SetLength(Result,Length(_Digest));
- Move(_Digest,Result[0],Length(_Digest));
- end;
- function THashMD5.HashAsBytes: TBytes;
- begin
- Result:=GetDigest;
- end;
- function THashMD5.HashAsString: UnicodeString;
- begin
- Result:=THash.DigestAsString(GetDigest);
- end;
- { THashSHA1 }
- procedure THashSHA1.Reset;
- begin
- SHA1Init(_SHA1);
- end;
- class function THashSHA1.Create: THashSHA1;
- begin
- Result:=Default(THashSHA1);
- Result.Reset;
- end;
- procedure THashSHA1.Update(var aData; aLength: Cardinal);
- begin
- SHA1Update(_SHA1,aData,aLength);
- end;
- procedure THashSHA1.Update(const aData: TBytes; aLength: Cardinal);
- begin
- if ALength=0 then
- ALength:=Length(aData);
- Update(aData[0],aLength);
- end;
- procedure THashSHA1.Update(const aData: UnicodeString);
- begin
- Update(TEncoding.UTF8.GetBytes(aData));
- end;
- function THashSHA1.GetBlockSize: Integer;
- begin
- Result:=64;
- end;
- function THashSHA1.GetHashSize: Integer;
- begin
- Result:=20;
- end;
- function THashSHA1.HashAsBytes: TBytes;
- begin
- Result:=GetDigest;
- end;
- function THashSHA1.HashAsString: UnicodeString;
- begin
- Result:=THash.DigestAsString(GetDigest);
- end;
- class function THashSHA1.GetHashBytes(const aData: UnicodeString): TBytes;
- begin
- With THashSha1.Create do
- begin
- Update(aData);
- Result:=GetDigest;
- end;
- end;
- class function THashSHA1.GetHashString(const aData: UnicodeString): UnicodeString;
- begin
- With THashSha1.Create do
- begin
- Update(aData);
- Result:=HashAsString;
- end;
- end;
- class function THashSHA1.GetHashBytes(const aStream: TStream): TBytes;
- var
- Buf: TBytes;
- Len,Count: Longint;
- begin
- Buf:=Default(TBytes);
- Len:=HashReadBufferSize;
- SetLength(Buf,Len);
- With THashSha1.Create do
- begin
- Count:=aStream.Read(Buf,Len);
- While (Count>0) do
- begin
- Update(Buf,Count);
- Count:=aStream.Read(Buf,Len);
- end;
- Result:=GetDigest;
- end;
- end;
- class function THashSHA1.GetHashString(const aStream: TStream): UnicodeString;
- begin
- Result:=THash.DigestAsString(GetHashBytes(aStream));
- end;
- class function THashSHA1.GetHashBytesFromFile(const aFileName: TFileName): TBytes;
- var
- F: TFileStream;
- begin
- F:=TFileStream.Create(aFileName,fmOpenRead or fmShareDenyWrite);
- try
- Result:=GetHashBytes(F);
- finally
- F.Free;
- end;
- end;
- class function THashSHA1.GetHashStringFromFile(const aFileName: TFileName): UnicodeString;
- begin
- Result:=THash.DigestAsString(GetHashBytesFromFile(aFileName));
- end;
- class function THashSHA1.GetHMAC(const aData, aKey: UnicodeString): UnicodeString;
- begin
- Result:=THash.DigestAsString(GetHMACAsBytes(aData,aKey));
- end;
- class function THashSHA1.GetHMACAsBytes(const aData, aKey: UnicodeString): TBytes;
- begin
- With TEncoding.UTF8 do
- Result:=GetHMACAsBytes(GetBytes(aData),GetBytes(aKey));
- end;
- class function THashSHA1.GetHMACAsBytes(const aData: UnicodeString; const aKey: TBytes): TBytes;
- begin
- With TEncoding.UTF8 do
- Result:=GetHMACAsBytes(GetBytes(aData),aKey);
- end;
- class function THashSHA1.GetHMACAsBytes(const aData: TBytes; const aKey: UnicodeString): TBytes;
- begin
- With TEncoding.UTF8 do
- Result:=GetHMACAsBytes(aData,GetBytes(aKey));
- end;
- class function THashSHA1.GetHMACAsBytes(const aData, aKey: TBytes): TBytes;
- var
- I: Byte;
- SHA1_BLOCK_SIZE : Integer;
- VLength: PtrUInt;
- PKey, POPad, PIPad: PByte;
- VKey, VOPad, VIPad: TBytes;
- Sha1 : THashSha1;
- begin
- VKey:=Default(TBytes);
- VOPad:=Default(TBytes);
- VIPad:=Default(TBytes);
- Sha1:=THashSha1.Create;
- SHA1_BLOCK_SIZE:=Sha1.GetBlockSize;
- VLength:=Length(aKey);
- if VLength > SHA1_BLOCK_SIZE then
- begin
- SetLength(VKey,SHA1_BLOCK_SIZE);
- FillChar(VKey[0],SHA1_BLOCK_SIZE, #0);
- Sha1.Update(aKey);
- VKey:=Concat(Sha1.GetDigest,VKey);
- end
- else
- begin
- SetLength(VKey,SHA1_BLOCK_SIZE-VLength);
- FillChar(VKey[0],SHA1_BLOCK_SIZE-VLength, #0);
- VKey:=Concat(aKey,VKey);
- end;
- SetLength(VOPad,SHA1_BLOCK_SIZE);
- POPad:=PByte(VOPad);
- FillChar(POPad^, SHA1_BLOCK_SIZE, $5c);
- SetLength(VIPad, SHA1_BLOCK_SIZE);
- PIPad := PByte(VIPad);
- FillChar(PIPad^, SHA1_BLOCK_SIZE, $36);
- PKey := PByte(VKey);
- for I:=1 to VLength do
- begin
- POPad^:=(POPad^ xor PKey^);
- PIPad^:=(PIPad^ xor PKey^);
- Inc(POPad);
- Inc(PIPad);
- Inc(PKey);
- end;
- VIPad:=Concat(VIPad,aData);
- Sha1.Reset;
- Sha1.Update(VIPad);
- Result:=Concat(VOPad,Sha1.GetDigest);
- end;
- function THashSHA1.GetDigest: TBytes;
- begin
- Result:=[];
- if not _DidFinal then
- begin
- _DidFinal:=True;
- SHA1Final(_SHA1,_Digest);
- end;
- SetLength(Result,Length(_Digest));
- Move(_Digest,Result[0],Length(_Digest));
- end;
- { THashSHA2 }
- Procedure NotSupportedVersion(aHashVersion : THashSHA2.TSHA2Version);
- var
- S : String;
- begin
- WriteStr(S,aHashversion);
- Raise EHashException.CreateFmt('SHA2 - %s not yet supported',[S]);
- end;
- class function THashSHA2.Create(aHashVersion: TSHA2Version): THashSHA2;
- begin
- if aHashVersion in [SHA512_224, SHA512_256] then
- NotSupportedVersion(aHashVersion);
- Result.FHashVersion:=aHashVersion;
- Result.Reset;
- end;
- class function THashSHA2.GetHashBytes(const aData: UnicodeString; aHashVersion: TSHA2Version): TBytes;
- var
- H : THashSHA2;
- begin
- H:=THashSHA2.Create(aHashVersion);
- H.Update(AData);
- Result:=H.GetDigest;
- end;
- class function THashSHA2.GetHashString(const aData: UnicodeString; aHashVersion: TSHA2Version): UnicodeString;
- var
- H: THashSHA2;
- begin
- H:=THashSHA2.Create(aHashVersion);
- H.Update(aData);
- Result:=H.HashAsString;
- end;
- class function THashSHA2.GetHashBytes(const aStream: TStream; aHashVersion: TSHA2Version): TBytes;
- var
- Buf: TBytes;
- Len,Count: Longint;
- begin
- Buf:=Default(TBytes);
- Len:=HashReadBufferSize;
- SetLength(Buf,Len);
- With THashSha2.Create(aHashVersion) do
- begin
- Count:=aStream.Read(Buf,Len);
- While (Count>0) do
- begin
- Update(Buf,Count);
- Count:=aStream.Read(Buf,Len);
- end;
- Result:=GetDigest;
- end;
- end;
- class function THashSHA2.GetHashString(const aStream: TStream; aHashVersion: TSHA2Version): UnicodeString;
- begin
- Result:=THash.DigestAsString(GetHashBytes(aStream,aHashVersion));
- end;
- class function THashSHA2.GetHashBytesFromFile(const aFileName: TFileName; aHashVersion: TSHA2Version): TBytes;
- var
- F: TFileStream;
- begin
- F:=TFileStream.Create(aFileName,fmOpenRead or fmShareDenyWrite);
- try
- Result:=GetHashBytes(F,aHashVersion);
- finally
- F.Free;
- end;
- end;
- class function THashSHA2.GetHashStringFromFile(const aFileName: TFileName; aHashVersion: TSHA2Version): UnicodeString;
- begin
- Result:=THash.DigestAsString(GetHashBytesFromFile(aFileName,aHashVersion));
- end;
- class function THashSHA2.GetHMAC(const aData, aKey: UnicodeString; aHashVersion: TSHA2Version): UnicodeString;
- begin
- Result:=THash.DigestAsString(GetHMACAsBytes(aData,aKey,aHashVersion));
- end;
- class function THashSHA2.GetHMACAsBytes(const aData, aKey: UnicodeString; aHashVersion: TSHA2Version): TBytes;
- begin
- With TEncoding.UTF8 do
- Result:=GetHMACAsBytes(GetBytes(aData),GetBytes(aKey),aHashVersion);
- end;
- class function THashSHA2.GetHMACAsBytes(const aData: UnicodeString; const aKey: TBytes; aHashVersion: TSHA2Version): TBytes;
- begin
- With TEncoding.UTF8 do
- Result:=GetHMACAsBytes(GetBytes(aData),aKey,aHashVersion);
- end;
- class function THashSHA2.GetHMACAsBytes(const aData: TBytes; const aKey: UnicodeString; aHashVersion: TSHA2Version): TBytes;
- begin
- With TEncoding.UTF8 do
- Result:=GetHMACAsBytes(aData,GetBytes(aKey),aHashVersion);
- end;
- class function THashSHA2.GetHMACAsBytes(const aData, aKey: TBytes; aHashVersion: TSHA2Version): TBytes;
- var
- Count: UInt32;
- KeySize,DataSize,BufSize : Integer;
- aDigest,KeyBuffer, PadBuffer: TBytes;
- SHA2,SHA2_ : THashSHA2;
- begin
- Result:=[];
- KeySize:=Length(akey);
- DataSize:=Length(aData);
- if aKey = nil then
- Exit;
- if aData = nil then
- Exit;
- SHA2:=THashSHA2.Create(aHashversion);
- BufSize:=SHA2.GetBlockSize;
- SetLength(KeyBuffer,BufSize);
- SetLength(PadBuffer,BufSize);
- if KeySize>BufSize then
- begin
- SHA2.Update(aKey);
- aDigest:=SHA2.GetDigest;
- System.Move(aDigest[0],KeyBuffer[0],SHA2.GetHashSize);
- end else
- System.Move(aKey[0], KeyBuffer[0], KeySize);
- // XOR the key buffer with the iPad value
- for Count := 0 to BufSize do
- PadBuffer[Count] := KeyBuffer[Count] xor $36;
- SHA2.Reset;
- SHA2.Update(PadBuffer);
- SHA2.Update(aData);
- aDigest:=SHA2.GetDigest;
- // XOR the key buffer with the oPad value
- for Count := 0 to 63 do
- PadBuffer[Count] := KeyBuffer[Count] xor $5C;
- // SHA256 the key buffer and the result of the inner SHA256 (Outer)
- SHA2.Reset;
- SHA2.Update(PadBuffer);
- SHA2.Update(aDigest);
- Result:=SHA2_.GetDigest;
- end;
- procedure THashSHA2.Reset;
- begin
- case FHashVersion of
- Sha224 : _S224.Init;
- Sha256 : _S256.Init;
- Sha384 : _S384.Init;
- Sha512 : _S512.Init;
- end;
- FDidFinal:=False;
- end;
- procedure THashSHA2.Update(var aData; aLength: Cardinal);
- begin
- Update(PByte(@aData),aLength);
- end;
- procedure THashSHA2.Update(const aData: PByte; aLength: Cardinal);
- begin
- case FHashVersion of
- Sha224 : _S224.Update(aData,aLength);
- Sha256 : _S256.Update(aData,aLength);
- Sha384 : _S384.Update(aData,aLength);
- Sha512 : _S512.Update(aData,aLength);
- end;
- end;
- procedure THashSHA2.Update(const aData: TBytes; aLength: Cardinal);
- begin
- if aLength=0 then
- aLength:=Length(aData);
- Update(PByte(aData),aLength);
- end;
- procedure THashSHA2.Update(const aData: UnicodeString);
- begin
- Update(TEncoding.UTF8.GetBytes(aData));
- end;
- procedure THashSHA2.Update(const aData: RawByteString);
- begin
- Update(PByte(aData),Length(aData)*SizeOf(AnsiChar));
- end;
- procedure THashSHA2.DoFinal;
- begin
- case FHashVersion of
- Sha224 : _S224.Final;
- Sha256 : _S256.Final;
- Sha384 : _S384.Final;
- Sha512 : _S512.Final;
- end;
- FDidFinal:=True;
- end;
- function THashSHA2.GetDigest: TBytes;
- Var
- P : PByte;
- L : Integer;
- begin
- if Not FDidFinal then
- DoFinal;
- // These should normally all be the same...
- case FHashVersion of
- Sha224 : P:=@_S224.Digest;
- Sha256 : P:=@_S256.Digest;
- Sha384 : P:=@_S384.Digest;
- Sha512 : P:=@_S512.Digest;
- end;
- L:=GetHashSize;
- SetLength(Result,L);
- Move(P^,Result[0],L);
- end;
- function THashSHA2.GetBlockSize: Integer;
- Const
- Sizes : Array[TSHA2Version] of integer
- = (64,64,128,128,128,128);
- begin
- Result:=Sizes[FHashVersion];
- end;
- function THashSHA2.GetHashSize: Integer;
- Const
- Sizes : Array[TSHA2Version] of integer
- = (28,32,48,64,28,32);
- begin
- Result:=Sizes[FHashVersion];
- end;
- function THashSHA2.HashAsBytes: TBytes;
- begin
- Result:=GetDigest;
- end;
- function THashSHA2.HashAsString: UnicodeString;
- begin
- Result:=THash.DigestAsString(GetDigest);
- end;
- { THashBobJenkins }
- class function THashBobJenkins.Create: THashBobJenkins;
- begin
- Result.Reset;
- end;
- class function THashBobJenkins.GetHashBytes(const aData: UnicodeString): TBytes;
- begin
- Result:=Default(TBytes);
- SetLength(Result,SizeOf(Cardinal));
- PCardinal(Result)^:=GetHashValue(aData)
- end;
- class function THashBobJenkins.GetHashString(const aData: UnicodeString): UnicodeString;
- begin
- Result:=HexStr(GetHashValue(aData),8);
- end;
- class function THashBobJenkins.GetHashString(const aData: RawByteString): UnicodeString;
- begin
- Result:=HexStr(GetHashValue(aData),8);
- end;
- class function THashBobJenkins.GetHashValue(var aData; aLength: Integer; aInitialValue: Integer): Integer;
- begin
- Result:=Integer(DelphiHashLittle(PByte(@AData),aLength,aInitialValue));
- end;
- class function THashBobJenkins.GetHashValue(const aData: PByte; aLength: Integer; aInitialValue: Integer): Integer;
- begin
- Result:=DelphiHashLittle(AData,aLength,aInitialValue);
- end;
- class function THashBobJenkins.GetHashValue(const aData: UnicodeString): Integer;
- begin
- Result:=GetHashValue(PByte(aData),Length(aData)*SizeOf(UnicodeChar),0);
- end;
- class function THashBobJenkins.GetHashValue(const aData: RawByteString): Integer;
- begin
- Result:=GetHashValue(PByte(aData),Length(aData)*SizeOf(AnsiChar),0);
- end;
- procedure THashBobJenkins.Reset(aInitialValue: Integer);
- begin
- FCurrent:=aInitialValue;
- end;
- procedure THashBobJenkins.Update(aData: PByte; aLength: Cardinal);
- begin
- FCurrent:=DelphiHashLittle(AData,aLength,FCurrent);
- end;
- procedure THashBobJenkins.Update(var aData; aLength: Cardinal);
- begin
- Update(PByte(@AData),aLength);
- end;
- procedure THashBobJenkins.Update(const aData: TBytes; aLength: Cardinal);
- begin
- if aLength=0 then
- aLength:=Length(aData);
- Update(PByte(aData),aLength);
- end;
- procedure THashBobJenkins.Update(const aData: UnicodeString);
- begin
- Update(PByte(aData),Length(aData)*SizeOf(UnicodeChar));
- end;
- procedure THashBobJenkins.Update(const aData: RawByteString);
- begin
- Update(PByte(aData),Length(aData)*SizeOf(AnsiChar));
- end;
- function THashBobJenkins.HashAsBytes: TBytes;
- begin
- Result:=[];
- SetLength(Result,Sizeof(Cardinal));
- PCardinal(Result)^:=FCurrent;
- end;
- function THashBobJenkins.HashAsInteger: Integer;
- begin
- Result:=FCurrent;
- end;
- function THashBobJenkins.HashAsString: UnicodeString;
- begin
- Result:=HexStr(HashAsInteger,8);
- end;
- { THashFNV1a32 }
- class function THashFNV1a32.Create: THashFNV1a32;
- begin
- Result.Reset;
- end;
- class function THashFNV1a32.GetHashBytes(const aData: UnicodeString): TBytes;
- var
- C : Cardinal;
- begin
- Result:=Default(TBytes);
- SetLength(Result,SizeOf(Fnv32_t));
- C:=Cardinal(GetHashValue(aData));
- PFnv32_t(@Result[0])^:=C;
- end;
- class function THashFNV1a32.GetHashString(const aData: UnicodeString): UnicodeString;
- begin
- Result:=HexStr(FNV1_32a(Pointer(aData)^,Length(aData)*SizeOf(UnicodeChar),FNV_SEED),8);
- end;
- class function THashFNV1a32.GetHashString(const aData: RawByteString): UnicodeString;
- begin
- Result:=HexStr(FNV1_32a(Pointer(aData)^,Length(aData),FNV_SEED),8);
- end;
- class function THashFNV1a32.GetHashValue(const aData: UnicodeString): Integer;
- var
- C : Cardinal;
- begin
- C:=FNV1_32a(PByte(aData),Length(aData)*SizeOf(UnicodeChar),FNV_SEED);
- Result:=Integer(C);
- end;
- class function THashFNV1a32.GetHashValue(const aData: RawByteString): Integer;
- begin
- Result:=Integer(FNV1_32a(Pointer(aData)^,Length(aData), FNV_SEED));
- end;
- class function THashFNV1a32.GetHashValue(const aData; aLength: Cardinal; aInitialValue: Cardinal): Integer;
- begin
- Result:=Integer(FNV1_32a(aData,aLength,aInitialValue));
- end;
- procedure THashFNV1a32.Reset(aInitialValue: Cardinal);
- begin
- FCurrent:=aInitialValue;
- end;
- procedure THashFNV1a32.Update(const aData; aLength: Cardinal);
- begin
- FCurrent:=FNV1_32a(aData,aLength,FCurrent);
- end;
- procedure THashFNV1a32.Update(const aData: TBytes; aLength: Cardinal);
- begin
- if aLength=0 then
- aLength:=Length(aData);
- Update(aData[0],aLength);
- end;
- procedure THashFNV1a32.Update(const aData: UnicodeString);
- begin
- FCurrent:=FNV1_32a(PByte(aData),Length(aData)*SizeOf(UnicodeChar),FCurrent);
- end;
- procedure THashFNV1a32.Update(const aData: RawByteString);
- begin
- FCurrent:=FNV1_32a(PByte(aData),Length(aData)*SizeOf(AnsiChar),FCurrent);
- end;
- function THashFNV1a32.GetDigest: TBytes;
- begin
- Result:=Default(TBytes);
- SetLength(Result,SizeOf(Fnv32_t));
- PFnv32_t(@Result[0])^:=FCurrent;
- end;
- function THashFNV1a32.HashAsBytes: TBytes;
- begin
- Result:=GetDigest;
- end;
- function THashFNV1a32.HashAsInteger: Integer;
- begin
- Result:=Integer(FCurrent);
- end;
- function THashFNV1a32.HashAsString: UnicodeString;
- begin
- Result:=HexStr(FCurrent,8);
- end;
- end.
|