system.hash.pp 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 2023 the Free Pascal team
  4. Delphi-compatible hash unit
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit System.Hash;
  12. {$mode objfpc}
  13. {$modeswitch advancedrecords}
  14. {$macro on}
  15. interface
  16. uses
  17. {$IFDEF FPC_DOTTEDUNITS}
  18. System.Classes, System.SysUtils, System.Hash.Md5, System.Hash.Sha1, System.Hash.Fnv, System.Hash.Sha256, System.Hash.Sha512;
  19. {$ELSE}
  20. Classes, SysUtils, md5, sha1, fnvhash, fpsha256, fpsha512;
  21. {$ENDIF}
  22. const
  23. HashReadBufferSize = 4096; // Use 4k buffer.
  24. type
  25. EHashException = class(Exception);
  26. { THash }
  27. THash = record
  28. class function DigestAsInteger(const aDigest: TBytes): Integer; static;
  29. class function DigestAsString(const aDigest: TBytes; UpperCase : Boolean = false): UnicodeString; static;
  30. class function DigestAsStringGUID(const aDigest: TBytes): UnicodeString; static;
  31. class function GetRandomString(const aLen: Integer = 10): UnicodeString; static;
  32. class function ToBigEndian(aValue: Cardinal): Cardinal; overload; static; inline;
  33. class function ToBigEndian(aValue: UInt64): UInt64; overload; static; inline;
  34. end;
  35. { THashMD5 }
  36. THashMD5 = record
  37. Private
  38. _MD5 : TMD5Context;
  39. _Digest : TMD5Digest;
  40. _DidFinal : Boolean;
  41. public
  42. class function Create: THashMD5; static; inline;
  43. class function GetHashBytes(const aData: UnicodeString): TBytes; overload; static;
  44. class function GetHashString(const aData: UnicodeString): UnicodeString; overload; static; inline;
  45. class function GetHashBytes(const aStream: TStream): TBytes; overload; static;
  46. class function GetHashString(const aStream: TStream): UnicodeString; overload; static; inline;
  47. class function GetHashBytesFromFile(const aFileName: TFileName): TBytes; static;
  48. class function GetHashStringFromFile(const aFileName: TFileName): UnicodeString; static; inline;
  49. class function GetHMAC(const aData,aKey: UnicodeString): UnicodeString; static; inline;
  50. class function GetHMACAsBytes(const aData,aKey: UnicodeString): TBytes; overload; static;
  51. class function GetHMACAsBytes(const aData: UnicodeString; const aKey: TBytes): TBytes; overload; static;
  52. class function GetHMACAsBytes(const aData: TBytes; const aKey: UnicodeString): TBytes; overload; static;
  53. class function GetHMACAsBytes(const aData,aKey: TBytes): TBytes; overload; static;
  54. procedure Reset;
  55. procedure Update(var aData; aLength: Cardinal); overload;
  56. procedure Update(const aData: TBytes; aLength: Cardinal = 0); overload; {inline;}
  57. procedure Update(const aData: UnicodeString); overload; {inline;}
  58. function GetDigest: TBytes;
  59. function GetBlockSize: Integer; inline;
  60. function GetHashSize: Integer; inline;
  61. function HashAsBytes: TBytes; inline;
  62. function HashAsString: UnicodeString; // inline;
  63. end;
  64. { THashSHA1 }
  65. THashSHA1 = record
  66. private
  67. _SHA1 : TSHA1Context;
  68. _Digest : TSHA1Digest;
  69. _DidFinal : Boolean;
  70. public
  71. class function Create: THashSHA1; static; // inline;
  72. class function GetHashBytes(const aData: UnicodeString): TBytes; overload; static;
  73. class function GetHashString(const aData: UnicodeString): UnicodeString; overload; static; // inline;
  74. class function GetHashBytes(const aStream: TStream): TBytes; overload; static;
  75. class function GetHashString(const aStream: TStream): UnicodeString; overload; static; // inline;
  76. class function GetHashBytesFromFile(const aFileName: TFileName): TBytes; static;
  77. class function GetHashStringFromFile(const aFileName: TFileName): UnicodeString; static; // inline;
  78. class function GetHMAC(const aData, aKey: UnicodeString): UnicodeString; static; // inline;
  79. class function GetHMACAsBytes(const aData, aKey: UnicodeString): TBytes; overload; static;
  80. class function GetHMACAsBytes(const aData: UnicodeString; const aKey: TBytes): TBytes; overload; static;
  81. class function GetHMACAsBytes(const aData: TBytes; const aKey: UnicodeString): TBytes; overload; static;
  82. class function GetHMACAsBytes(const aData, aKey: TBytes): TBytes; overload; static;
  83. procedure Reset; inline;
  84. procedure Update(var aData; aLength: Cardinal); overload;
  85. procedure Update(const aData: TBytes; aLength: Cardinal = 0); overload;
  86. procedure Update(const aData: UnicodeString); overload; // inline;
  87. function GetDigest: TBytes;
  88. function GetBlockSize: Integer; inline;
  89. function GetHashSize: Integer; inline;
  90. function HashAsBytes: TBytes; inline;
  91. function HashAsString: UnicodeString; // inline;
  92. end;
  93. { THashSHA2 }
  94. THashSHA2 = record
  95. public type
  96. TSHA2Version = (SHA224, SHA256, SHA384, SHA512, SHA512_224, SHA512_256);
  97. public
  98. class function Create(aHashVersion: TSHA2Version = TSHA2Version.SHA256): THashSHA2; static; inline;
  99. class function GetHashBytes(const aData: UnicodeString; aHashVersion: TSHA2Version = TSHA2Version.SHA256): TBytes; overload; static;
  100. class function GetHashString(const aData: UnicodeString; aHashVersion: TSHA2Version = TSHA2Version.SHA256): UnicodeString; overload; static; inline;
  101. class function GetHashBytes(const aStream: TStream; aHashVersion: TSHA2Version = TSHA2Version.SHA256): TBytes; overload; static;
  102. class function GetHashString(const aStream: TStream; aHashVersion: TSHA2Version = TSHA2Version.SHA256): UnicodeString; overload; static; inline;
  103. class function GetHashBytesFromFile(const aFileName: TFileName; aHashVersion: TSHA2Version = TSHA2Version.SHA256): TBytes; static;
  104. class function GetHashStringFromFile(const aFileName: TFileName; aHashVersion: TSHA2Version = TSHA2Version.SHA256): UnicodeString; static; inline;
  105. class function GetHMAC(const aData, aKey: UnicodeString; aHashVersion: TSHA2Version = TSHA2Version.SHA256): UnicodeString; static; inline;
  106. class function GetHMACAsBytes(const aData, aKey: UnicodeString; aHashVersion: TSHA2Version = TSHA2Version.SHA256): TBytes; overload; static;
  107. class function GetHMACAsBytes(const aData: UnicodeString; const aKey: TBytes; aHashVersion: TSHA2Version = TSHA2Version.SHA256): TBytes; overload; static;
  108. class function GetHMACAsBytes(const aData: TBytes; const aKey: UnicodeString; aHashVersion: TSHA2Version = TSHA2Version.SHA256): TBytes; overload; static;
  109. class function GetHMACAsBytes(const aData, aKey: TBytes; aHashVersion: TSHA2Version = TSHA2Version.SHA256): TBytes; overload; static;
  110. procedure Reset; inline;
  111. procedure Update(var aData; aLength: Cardinal); overload;
  112. procedure Update(const aData : PByte; aLength: Cardinal); overload;
  113. procedure Update(const aData: TBytes; aLength: Cardinal = 0); overload;
  114. procedure Update(const aData: UnicodeString); overload;
  115. procedure Update(const aData: RawByteString); overload;
  116. function GetDigest: TBytes;
  117. function GetBlockSize: Integer; inline;
  118. function GetHashSize: Integer; inline;
  119. function HashAsBytes: TBytes; // inline;
  120. function HashAsString: UnicodeString; // inline;
  121. Private
  122. procedure DoFinal;
  123. private
  124. FDidFinal : Boolean;
  125. case FHashVersion: TSHA2Version of
  126. Sha224 : (_S224 : TSHA224);
  127. Sha256 : (_S256 : TSHA256);
  128. Sha384 : (_S384 : TSHA384);
  129. Sha512 : (_S512 : TSHA512);
  130. end;
  131. { THashBobJenkins }
  132. THashBobJenkins = record
  133. Private
  134. FCurrent : Cardinal;
  135. public
  136. class function Create: THashBobJenkins; static;
  137. class function GetHashBytes(const aData: UnicodeString): TBytes; static;
  138. class function GetHashString(const aData: UnicodeString): UnicodeString; static;
  139. class function GetHashString(const aData: RawByteString): UnicodeString; static;
  140. class function GetHashValue(const aData: UnicodeString): Integer; overload; static;
  141. class function GetHashValue(const aData: RawByteString): Integer; overload; static;
  142. class function GetHashValue(var aData; aLength: Integer; aInitialValue: Integer = 0): Integer; overload; static;
  143. class function GetHashValue(const aData : PByte; aLength: Integer; aInitialValue: Integer = 0): Integer; overload; static;
  144. procedure Reset(aInitialValue: Integer = 0);
  145. procedure Update(var aData; aLength: Cardinal); overload;
  146. procedure Update(aData : PByte; aLength: Cardinal); overload;
  147. procedure Update(const aData: TBytes; aLength: Cardinal = 0); overload;
  148. procedure Update(const aData: UnicodeString); overload;
  149. procedure Update(const aData: RawByteString); overload;
  150. function HashAsBytes: TBytes;
  151. function HashAsInteger: Integer;
  152. function HashAsString: UnicodeString;
  153. end;
  154. { THashFNV1a32 }
  155. THashFNV1a32 = record
  156. public const
  157. FNV_PRIME = FNV_32_PRIME;
  158. FNV_SEED = FNV1_32_INIT;
  159. private
  160. FCurrent : Fnv32_t;
  161. public
  162. class function Create: THashFNV1a32; static;
  163. class function GetHashBytes(const aData: UnicodeString): TBytes; static;
  164. class function GetHashString(const aData: UnicodeString): UnicodeString; overload; static;
  165. class function GetHashString(const aData: RawByteString): UnicodeString; overload; static;
  166. class function GetHashValue(const aData: UnicodeString): Integer; overload; static; // inline;
  167. class function GetHashValue(const aData: RawByteString): Integer; overload; static; // inline;
  168. class function GetHashValue(const aData; aLength: Cardinal; aInitialValue: Cardinal = FNV_SEED): Integer; overload; static; // inline;
  169. procedure Reset(aInitialValue: Cardinal = FNV_SEED);
  170. procedure Update(const aData; aLength: Cardinal); overload; // inline;
  171. procedure Update(const aData: TBytes; aLength: Cardinal = 0); overload; // inline;
  172. procedure Update(const aData: UnicodeString); overload; // inline;
  173. procedure Update(const aData: RawByteString); overload; // inline;
  174. function GetDigest : TBytes;
  175. function HashAsBytes: TBytes;
  176. function HashAsInteger: Integer;
  177. function HashAsString: UnicodeString;
  178. end;
  179. const
  180. SHashCanNotUpdateMD5 = 'MD5: Cannot update a finalized hash';
  181. SHashCanNotUpdateSHA1 = 'SHA1: Cannot update a finalized hash';
  182. SHashCanNotUpdateSHA2 = 'SHA2: Cannot update a finalized hash';
  183. RandomStringChars = UnicodeString('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+-/*_');
  184. RandomStringCharCount = Length(RandomStringChars);
  185. implementation
  186. Uses
  187. {$IFDEF FPC_DOTTEDUNITS}
  188. System.Types, System.SysConst, System.Generics.Hashes;
  189. {$ELSE}
  190. Types, SysConst, Generics.Hashes;
  191. {$ENDIF}
  192. Resourcestring
  193. SErrDigestSizeMustBe4 = 'Digest size must be 4, got %d instead.';
  194. { THash }
  195. class function THash.ToBigEndian(aValue: Cardinal): Cardinal;
  196. begin
  197. Result:=NtoBE(aValue);
  198. end;
  199. class function THash.ToBigEndian(aValue: UInt64): UInt64;
  200. begin
  201. Result:=NtoBE(aValue);
  202. end;
  203. class function THash.DigestAsInteger(const aDigest: TBytes): Integer;
  204. begin
  205. if Length(aDigest) <> 4 then
  206. raise EHashException.CreateFmt(SErrDigestSizeMustBe4,[Length(aDigest)]);
  207. Result:= PLongInt(@ADigest[0])^;
  208. end;
  209. class function THash.DigestAsString(const aDigest: TBytes; UpperCase: Boolean): UnicodeString;
  210. const
  211. HexDigitsWL: array[0..15] of widechar = '0123456789abcdef';
  212. var
  213. S : UnicodeString;
  214. I,Len: Integer;
  215. H,Res : PWideChar;
  216. PB : PByte;
  217. B : Byte;
  218. begin
  219. S:='';
  220. if Uppercase then
  221. H:=@HexDigitsW
  222. else
  223. H:=@HexDigitsWL;
  224. Len:=Length(aDigest);
  225. SetLength(S,2*Len);
  226. Res:=PWideChar(S);
  227. PB:=PByte(aDigest);
  228. for I:=1 to Len do
  229. begin
  230. B:=PB^;
  231. Res^:=H[B shr 4];
  232. inc(Res);
  233. Res^:=H[B and 15];
  234. Inc(Res);
  235. Inc(PB);
  236. end;
  237. Result:=S;
  238. end;
  239. class function THash.DigestAsStringGUID(const aDigest: TBytes): UnicodeString;
  240. begin
  241. With TGUID.Create(aDigest,TEndian.Little) do
  242. begin
  243. D1:=ToBigEndian(D1);
  244. D2:=Swap(D2);
  245. D3:=Swap(D3);
  246. {$IF SIZEOF(Char)=2}
  247. Result:=ToString;
  248. {$ELSE}
  249. Result:=Utf8Decode(ToString);
  250. {$ENDIF}
  251. end;
  252. end;
  253. class function THash.GetRandomString(const aLen: Integer): UnicodeString;
  254. var
  255. I : Integer;
  256. Res: PWideChar;
  257. begin
  258. Result:='';
  259. SetLength(Result,aLen);
  260. Res:=PWideChar(Result);
  261. for I:=1 to ALen do
  262. begin
  263. Res^:=RandomStringChars[1+Random(RandomStringCharCount)];
  264. Inc(Res);
  265. end;
  266. end;
  267. { THashMD5 }
  268. class function THashMD5.Create: THashMD5;
  269. begin
  270. Result:=Default(THashMD5);
  271. Result.Reset;
  272. end;
  273. function THashMD5.GetBlockSize: Integer;
  274. begin
  275. Result:=64;
  276. end;
  277. function THashMD5.GetHashSize: Integer;
  278. begin
  279. Result:=SizeOf(TMD5Digest);
  280. end;
  281. class function THashMD5.GetHashBytes(const aData: UnicodeString): TBytes;
  282. begin
  283. With THashMD5.Create do
  284. begin
  285. Update(aData);
  286. Result:=GetDigest;
  287. end;
  288. end;
  289. class function THashMD5.GetHashString(const aData: UnicodeString): UnicodeString;
  290. begin
  291. With THashMD5.Create do
  292. begin
  293. Update(aData);
  294. Result:=HashAsString;
  295. end;
  296. end;
  297. class function THashMD5.GetHashBytes(const aStream: TStream): TBytes;
  298. var
  299. Buf: TBytes;
  300. Len,Count: Longint;
  301. begin
  302. Buf:=Default(TBytes);
  303. Len:=HashReadBufferSize;
  304. SetLength(Buf,Len);
  305. With THashMD5.Create do
  306. begin
  307. Count:=aStream.Read(Buf,Len);
  308. While (Count>0) do
  309. begin
  310. Update(Buf,Count);
  311. Count:=aStream.Read(Buf,Len);
  312. end;
  313. Result:=GetDigest;
  314. end;
  315. end;
  316. class function THashMD5.GetHashString(const aStream: TStream): UnicodeString;
  317. begin
  318. Result:=THash.DigestAsString(GetHashBytes(aStream));
  319. end;
  320. class function THashMD5.GetHashBytesFromFile(const aFileName: TFileName): TBytes;
  321. var
  322. F: TFileStream;
  323. begin
  324. F:=TFileStream.Create(aFileName,fmOpenRead or fmShareDenyWrite);
  325. try
  326. Result:=GetHashBytes(F);
  327. finally
  328. F.Free;
  329. end;
  330. end;
  331. class function THashMD5.GetHashStringFromFile(const aFileName: TFileName): UnicodeString;
  332. begin
  333. Result:=THash.DigestAsString(GetHashBytesFromFile(aFileName));
  334. end;
  335. class function THashMD5.GetHMAC(const aData,aKey: UnicodeString): UnicodeString;
  336. begin
  337. Result:=THash.DigestAsString(GetHMACAsBytes(aData,aKey));
  338. end;
  339. class function THashMD5.GetHMACAsBytes(const aData, aKey: UnicodeString): TBytes;
  340. begin
  341. With TEncoding.UTF8 do
  342. Result:=GetHMACAsBytes(GetBytes(aData),GetBytes(aKey));
  343. end;
  344. class function THashMD5.GetHMACAsBytes(const aData: UnicodeString; const aKey: TBytes): TBytes;
  345. begin
  346. With TEncoding.UTF8 do
  347. Result:=GetHMACAsBytes(GetBytes(aData),aKey);
  348. end;
  349. class function THashMD5.GetHMACAsBytes(const aData: TBytes; const aKey: UnicodeString): TBytes;
  350. begin
  351. With TEncoding.UTF8 do
  352. Result:=GetHMACAsBytes(aData,GetBytes(aKey));
  353. end;
  354. class function THashMD5.GetHMACAsBytes(const aData, aKey: TBytes): TBytes;
  355. var
  356. I: Byte;
  357. MD5_BLOCK_SIZE : Integer;
  358. VLength: PtrUInt;
  359. PKey, POPad, PIPad: PByte;
  360. VKey, VOPad, VIPad: TBytes;
  361. MD5 : THashMD5;
  362. begin
  363. VKey:=Default(TBytes);
  364. VOPad:=Default(TBytes);
  365. VIPad:=Default(TBytes);
  366. MD5:=THashMD5.Create;
  367. MD5_BLOCK_SIZE:=MD5.GetBlockSize;
  368. VLength:=Length(aKey);
  369. if VLength > MD5_BLOCK_SIZE then
  370. begin
  371. SetLength(VKey,MD5_BLOCK_SIZE);
  372. FillChar(VKey[0],MD5_BLOCK_SIZE, #0);
  373. MD5.Update(aKey);
  374. VKey:=Concat(MD5.GetDigest,VKey);
  375. end
  376. else
  377. begin
  378. SetLength(VKey,MD5_BLOCK_SIZE-VLength);
  379. FillChar(VKey[0],MD5_BLOCK_SIZE-VLength, #0);
  380. VKey:=Concat(aKey,VKey);
  381. end;
  382. SetLength(VOPad,MD5_BLOCK_SIZE);
  383. POPad:=PByte(VOPad);
  384. FillChar(POPad^, MD5_BLOCK_SIZE, $5c);
  385. SetLength(VIPad, MD5_BLOCK_SIZE);
  386. PIPad := PByte(VIPad);
  387. FillChar(PIPad^, MD5_BLOCK_SIZE, $36);
  388. PKey := PByte(VKey);
  389. for I:=1 to VLength do
  390. begin
  391. POPad^:=(POPad^ xor PKey^);
  392. PIPad^:=(PIPad^ xor PKey^);
  393. Inc(POPad);
  394. Inc(PIPad);
  395. Inc(PKey);
  396. end;
  397. VIPad:=Concat(VIPad,aData);
  398. MD5.Reset;
  399. MD5.Update(VIPad);
  400. Result:=Concat(VOPad,MD5.GetDigest);
  401. end;
  402. procedure THashMD5.Reset;
  403. begin
  404. MD5Init(_MD5);
  405. end;
  406. procedure THashMD5.Update(var aData; aLength: Cardinal);
  407. begin
  408. MD5Update(_MD5,aData,aLength);
  409. end;
  410. procedure THashMD5.Update(const aData: TBytes; aLength: Cardinal);
  411. begin
  412. if aLength=0 then
  413. aLength:=Length(aData);
  414. MD5Update(_MD5,aData[0],aLength);
  415. end;
  416. procedure THashMD5.Update(const aData: UnicodeString);
  417. begin
  418. Update(TEncoding.UTF8.GetBytes(aData));
  419. end;
  420. function THashMD5.GetDigest: TBytes;
  421. begin
  422. Result:=[];
  423. if not _DidFinal then
  424. begin
  425. _DidFinal:=True;
  426. MD5Final(_MD5,_Digest);
  427. end;
  428. SetLength(Result,Length(_Digest));
  429. Move(_Digest,Result[0],Length(_Digest));
  430. end;
  431. function THashMD5.HashAsBytes: TBytes;
  432. begin
  433. Result:=GetDigest;
  434. end;
  435. function THashMD5.HashAsString: UnicodeString;
  436. begin
  437. Result:=THash.DigestAsString(GetDigest);
  438. end;
  439. { THashSHA1 }
  440. procedure THashSHA1.Reset;
  441. begin
  442. SHA1Init(_SHA1);
  443. end;
  444. class function THashSHA1.Create: THashSHA1;
  445. begin
  446. Result:=Default(THashSHA1);
  447. Result.Reset;
  448. end;
  449. procedure THashSHA1.Update(var aData; aLength: Cardinal);
  450. begin
  451. SHA1Update(_SHA1,aData,aLength);
  452. end;
  453. procedure THashSHA1.Update(const aData: TBytes; aLength: Cardinal);
  454. begin
  455. if ALength=0 then
  456. ALength:=Length(aData);
  457. Update(aData[0],aLength);
  458. end;
  459. procedure THashSHA1.Update(const aData: UnicodeString);
  460. begin
  461. Update(TEncoding.UTF8.GetBytes(aData));
  462. end;
  463. function THashSHA1.GetBlockSize: Integer;
  464. begin
  465. Result:=64;
  466. end;
  467. function THashSHA1.GetHashSize: Integer;
  468. begin
  469. Result:=20;
  470. end;
  471. function THashSHA1.HashAsBytes: TBytes;
  472. begin
  473. Result:=GetDigest;
  474. end;
  475. function THashSHA1.HashAsString: UnicodeString;
  476. begin
  477. Result:=THash.DigestAsString(GetDigest);
  478. end;
  479. class function THashSHA1.GetHashBytes(const aData: UnicodeString): TBytes;
  480. begin
  481. With THashSha1.Create do
  482. begin
  483. Update(aData);
  484. Result:=GetDigest;
  485. end;
  486. end;
  487. class function THashSHA1.GetHashString(const aData: UnicodeString): UnicodeString;
  488. begin
  489. With THashSha1.Create do
  490. begin
  491. Update(aData);
  492. Result:=HashAsString;
  493. end;
  494. end;
  495. class function THashSHA1.GetHashBytes(const aStream: TStream): TBytes;
  496. var
  497. Buf: TBytes;
  498. Len,Count: Longint;
  499. begin
  500. Buf:=Default(TBytes);
  501. Len:=HashReadBufferSize;
  502. SetLength(Buf,Len);
  503. With THashSha1.Create do
  504. begin
  505. Count:=aStream.Read(Buf,Len);
  506. While (Count>0) do
  507. begin
  508. Update(Buf,Count);
  509. Count:=aStream.Read(Buf,Len);
  510. end;
  511. Result:=GetDigest;
  512. end;
  513. end;
  514. class function THashSHA1.GetHashString(const aStream: TStream): UnicodeString;
  515. begin
  516. Result:=THash.DigestAsString(GetHashBytes(aStream));
  517. end;
  518. class function THashSHA1.GetHashBytesFromFile(const aFileName: TFileName): TBytes;
  519. var
  520. F: TFileStream;
  521. begin
  522. F:=TFileStream.Create(aFileName,fmOpenRead or fmShareDenyWrite);
  523. try
  524. Result:=GetHashBytes(F);
  525. finally
  526. F.Free;
  527. end;
  528. end;
  529. class function THashSHA1.GetHashStringFromFile(const aFileName: TFileName): UnicodeString;
  530. begin
  531. Result:=THash.DigestAsString(GetHashBytesFromFile(aFileName));
  532. end;
  533. class function THashSHA1.GetHMAC(const aData, aKey: UnicodeString): UnicodeString;
  534. begin
  535. Result:=THash.DigestAsString(GetHMACAsBytes(aData,aKey));
  536. end;
  537. class function THashSHA1.GetHMACAsBytes(const aData, aKey: UnicodeString): TBytes;
  538. begin
  539. With TEncoding.UTF8 do
  540. Result:=GetHMACAsBytes(GetBytes(aData),GetBytes(aKey));
  541. end;
  542. class function THashSHA1.GetHMACAsBytes(const aData: UnicodeString; const aKey: TBytes): TBytes;
  543. begin
  544. With TEncoding.UTF8 do
  545. Result:=GetHMACAsBytes(GetBytes(aData),aKey);
  546. end;
  547. class function THashSHA1.GetHMACAsBytes(const aData: TBytes; const aKey: UnicodeString): TBytes;
  548. begin
  549. With TEncoding.UTF8 do
  550. Result:=GetHMACAsBytes(aData,GetBytes(aKey));
  551. end;
  552. class function THashSHA1.GetHMACAsBytes(const aData, aKey: TBytes): TBytes;
  553. var
  554. I: Byte;
  555. SHA1_BLOCK_SIZE : Integer;
  556. VLength: PtrUInt;
  557. PKey, POPad, PIPad: PByte;
  558. VKey, VOPad, VIPad: TBytes;
  559. Sha1 : THashSha1;
  560. begin
  561. VKey:=Default(TBytes);
  562. VOPad:=Default(TBytes);
  563. VIPad:=Default(TBytes);
  564. Sha1:=THashSha1.Create;
  565. SHA1_BLOCK_SIZE:=Sha1.GetBlockSize;
  566. VLength:=Length(aKey);
  567. if VLength > SHA1_BLOCK_SIZE then
  568. begin
  569. SetLength(VKey,SHA1_BLOCK_SIZE);
  570. FillChar(VKey[0],SHA1_BLOCK_SIZE, #0);
  571. Sha1.Update(aKey);
  572. VKey:=Concat(Sha1.GetDigest,VKey);
  573. end
  574. else
  575. begin
  576. SetLength(VKey,SHA1_BLOCK_SIZE-VLength);
  577. FillChar(VKey[0],SHA1_BLOCK_SIZE-VLength, #0);
  578. VKey:=Concat(aKey,VKey);
  579. end;
  580. SetLength(VOPad,SHA1_BLOCK_SIZE);
  581. POPad:=PByte(VOPad);
  582. FillChar(POPad^, SHA1_BLOCK_SIZE, $5c);
  583. SetLength(VIPad, SHA1_BLOCK_SIZE);
  584. PIPad := PByte(VIPad);
  585. FillChar(PIPad^, SHA1_BLOCK_SIZE, $36);
  586. PKey := PByte(VKey);
  587. for I:=1 to VLength do
  588. begin
  589. POPad^:=(POPad^ xor PKey^);
  590. PIPad^:=(PIPad^ xor PKey^);
  591. Inc(POPad);
  592. Inc(PIPad);
  593. Inc(PKey);
  594. end;
  595. VIPad:=Concat(VIPad,aData);
  596. Sha1.Reset;
  597. Sha1.Update(VIPad);
  598. Result:=Concat(VOPad,Sha1.GetDigest);
  599. end;
  600. function THashSHA1.GetDigest: TBytes;
  601. begin
  602. Result:=[];
  603. if not _DidFinal then
  604. begin
  605. _DidFinal:=True;
  606. SHA1Final(_SHA1,_Digest);
  607. end;
  608. SetLength(Result,Length(_Digest));
  609. Move(_Digest,Result[0],Length(_Digest));
  610. end;
  611. { THashSHA2 }
  612. Procedure NotSupportedVersion(aHashVersion : THashSHA2.TSHA2Version);
  613. var
  614. S : String;
  615. begin
  616. WriteStr(S,aHashversion);
  617. Raise EHashException.CreateFmt('SHA2 - %s not yet supported',[S]);
  618. end;
  619. class function THashSHA2.Create(aHashVersion: TSHA2Version): THashSHA2;
  620. begin
  621. if aHashVersion in [SHA512_224, SHA512_256] then
  622. NotSupportedVersion(aHashVersion);
  623. Result.FHashVersion:=aHashVersion;
  624. Result.Reset;
  625. end;
  626. class function THashSHA2.GetHashBytes(const aData: UnicodeString; aHashVersion: TSHA2Version): TBytes;
  627. var
  628. H : THashSHA2;
  629. begin
  630. H:=THashSHA2.Create(aHashVersion);
  631. H.Update(AData);
  632. Result:=H.GetDigest;
  633. end;
  634. class function THashSHA2.GetHashString(const aData: UnicodeString; aHashVersion: TSHA2Version): UnicodeString;
  635. var
  636. H: THashSHA2;
  637. begin
  638. H:=THashSHA2.Create(aHashVersion);
  639. H.Update(aData);
  640. Result:=H.HashAsString;
  641. end;
  642. class function THashSHA2.GetHashBytes(const aStream: TStream; aHashVersion: TSHA2Version): TBytes;
  643. var
  644. Buf: TBytes;
  645. Len,Count: Longint;
  646. begin
  647. Buf:=Default(TBytes);
  648. Len:=HashReadBufferSize;
  649. SetLength(Buf,Len);
  650. With THashSha2.Create(aHashVersion) do
  651. begin
  652. Count:=aStream.Read(Buf,Len);
  653. While (Count>0) do
  654. begin
  655. Update(Buf,Count);
  656. Count:=aStream.Read(Buf,Len);
  657. end;
  658. Result:=GetDigest;
  659. end;
  660. end;
  661. class function THashSHA2.GetHashString(const aStream: TStream; aHashVersion: TSHA2Version): UnicodeString;
  662. begin
  663. Result:=THash.DigestAsString(GetHashBytes(aStream,aHashVersion));
  664. end;
  665. class function THashSHA2.GetHashBytesFromFile(const aFileName: TFileName; aHashVersion: TSHA2Version): TBytes;
  666. var
  667. F: TFileStream;
  668. begin
  669. F:=TFileStream.Create(aFileName,fmOpenRead or fmShareDenyWrite);
  670. try
  671. Result:=GetHashBytes(F,aHashVersion);
  672. finally
  673. F.Free;
  674. end;
  675. end;
  676. class function THashSHA2.GetHashStringFromFile(const aFileName: TFileName; aHashVersion: TSHA2Version): UnicodeString;
  677. begin
  678. Result:=THash.DigestAsString(GetHashBytesFromFile(aFileName,aHashVersion));
  679. end;
  680. class function THashSHA2.GetHMAC(const aData, aKey: UnicodeString; aHashVersion: TSHA2Version): UnicodeString;
  681. begin
  682. Result:=THash.DigestAsString(GetHMACAsBytes(aData,aKey,aHashVersion));
  683. end;
  684. class function THashSHA2.GetHMACAsBytes(const aData, aKey: UnicodeString; aHashVersion: TSHA2Version): TBytes;
  685. begin
  686. With TEncoding.UTF8 do
  687. Result:=GetHMACAsBytes(GetBytes(aData),GetBytes(aKey),aHashVersion);
  688. end;
  689. class function THashSHA2.GetHMACAsBytes(const aData: UnicodeString; const aKey: TBytes; aHashVersion: TSHA2Version): TBytes;
  690. begin
  691. With TEncoding.UTF8 do
  692. Result:=GetHMACAsBytes(GetBytes(aData),aKey,aHashVersion);
  693. end;
  694. class function THashSHA2.GetHMACAsBytes(const aData: TBytes; const aKey: UnicodeString; aHashVersion: TSHA2Version): TBytes;
  695. begin
  696. With TEncoding.UTF8 do
  697. Result:=GetHMACAsBytes(aData,GetBytes(aKey),aHashVersion);
  698. end;
  699. class function THashSHA2.GetHMACAsBytes(const aData, aKey: TBytes; aHashVersion: TSHA2Version): TBytes;
  700. var
  701. Count: UInt32;
  702. KeySize,DataSize,BufSize : Integer;
  703. aDigest,KeyBuffer, PadBuffer: TBytes;
  704. SHA2,SHA2_ : THashSHA2;
  705. begin
  706. Result:=[];
  707. KeySize:=Length(akey);
  708. DataSize:=Length(aData);
  709. if aKey = nil then
  710. Exit;
  711. if aData = nil then
  712. Exit;
  713. SHA2:=THashSHA2.Create(aHashversion);
  714. BufSize:=SHA2.GetBlockSize;
  715. SetLength(KeyBuffer,BufSize);
  716. SetLength(PadBuffer,BufSize);
  717. if KeySize>BufSize then
  718. begin
  719. SHA2.Update(aKey);
  720. aDigest:=SHA2.GetDigest;
  721. System.Move(aDigest[0],KeyBuffer[0],SHA2.GetHashSize);
  722. end else
  723. System.Move(aKey[0], KeyBuffer[0], KeySize);
  724. // XOR the key buffer with the iPad value
  725. for Count := 0 to BufSize do
  726. PadBuffer[Count] := KeyBuffer[Count] xor $36;
  727. SHA2.Reset;
  728. SHA2.Update(PadBuffer);
  729. SHA2.Update(aData);
  730. aDigest:=SHA2.GetDigest;
  731. // XOR the key buffer with the oPad value
  732. for Count := 0 to 63 do
  733. PadBuffer[Count] := KeyBuffer[Count] xor $5C;
  734. // SHA256 the key buffer and the result of the inner SHA256 (Outer)
  735. SHA2.Reset;
  736. SHA2.Update(PadBuffer);
  737. SHA2.Update(aDigest);
  738. Result:=SHA2_.GetDigest;
  739. end;
  740. procedure THashSHA2.Reset;
  741. begin
  742. case FHashVersion of
  743. Sha224 : _S224.Init;
  744. Sha256 : _S256.Init;
  745. Sha384 : _S384.Init;
  746. Sha512 : _S512.Init;
  747. end;
  748. FDidFinal:=False;
  749. end;
  750. procedure THashSHA2.Update(var aData; aLength: Cardinal);
  751. begin
  752. Update(PByte(@aData),aLength);
  753. end;
  754. procedure THashSHA2.Update(const aData: PByte; aLength: Cardinal);
  755. begin
  756. case FHashVersion of
  757. Sha224 : _S224.Update(aData,aLength);
  758. Sha256 : _S256.Update(aData,aLength);
  759. Sha384 : _S384.Update(aData,aLength);
  760. Sha512 : _S512.Update(aData,aLength);
  761. end;
  762. end;
  763. procedure THashSHA2.Update(const aData: TBytes; aLength: Cardinal);
  764. begin
  765. if aLength=0 then
  766. aLength:=Length(aData);
  767. Update(PByte(aData),aLength);
  768. end;
  769. procedure THashSHA2.Update(const aData: UnicodeString);
  770. begin
  771. Update(TEncoding.UTF8.GetBytes(aData));
  772. end;
  773. procedure THashSHA2.Update(const aData: RawByteString);
  774. begin
  775. Update(PByte(aData),Length(aData)*SizeOf(AnsiChar));
  776. end;
  777. procedure THashSHA2.DoFinal;
  778. begin
  779. case FHashVersion of
  780. Sha224 : _S224.Final;
  781. Sha256 : _S256.Final;
  782. Sha384 : _S384.Final;
  783. Sha512 : _S512.Final;
  784. end;
  785. FDidFinal:=True;
  786. end;
  787. function THashSHA2.GetDigest: TBytes;
  788. Var
  789. P : PByte;
  790. L : Integer;
  791. begin
  792. if Not FDidFinal then
  793. DoFinal;
  794. // These should normally all be the same...
  795. case FHashVersion of
  796. Sha224 : P:=@_S224.Digest;
  797. Sha256 : P:=@_S256.Digest;
  798. Sha384 : P:=@_S384.Digest;
  799. Sha512 : P:=@_S512.Digest;
  800. end;
  801. L:=GetHashSize;
  802. SetLength(Result,L);
  803. Move(P^,Result[0],L);
  804. end;
  805. function THashSHA2.GetBlockSize: Integer;
  806. Const
  807. Sizes : Array[TSHA2Version] of integer
  808. = (64,64,128,128,128,128);
  809. begin
  810. Result:=Sizes[FHashVersion];
  811. end;
  812. function THashSHA2.GetHashSize: Integer;
  813. Const
  814. Sizes : Array[TSHA2Version] of integer
  815. = (28,32,48,64,28,32);
  816. begin
  817. Result:=Sizes[FHashVersion];
  818. end;
  819. function THashSHA2.HashAsBytes: TBytes;
  820. begin
  821. Result:=GetDigest;
  822. end;
  823. function THashSHA2.HashAsString: UnicodeString;
  824. begin
  825. Result:=THash.DigestAsString(GetDigest);
  826. end;
  827. { THashBobJenkins }
  828. class function THashBobJenkins.Create: THashBobJenkins;
  829. begin
  830. Result.Reset;
  831. end;
  832. class function THashBobJenkins.GetHashBytes(const aData: UnicodeString): TBytes;
  833. begin
  834. Result:=Default(TBytes);
  835. SetLength(Result,SizeOf(Cardinal));
  836. PCardinal(Result)^:=GetHashValue(aData)
  837. end;
  838. class function THashBobJenkins.GetHashString(const aData: UnicodeString): UnicodeString;
  839. begin
  840. Result:=HexStr(GetHashValue(aData),8);
  841. end;
  842. class function THashBobJenkins.GetHashString(const aData: RawByteString): UnicodeString;
  843. begin
  844. Result:=HexStr(GetHashValue(aData),8);
  845. end;
  846. class function THashBobJenkins.GetHashValue(var aData; aLength: Integer; aInitialValue: Integer): Integer;
  847. begin
  848. Result:=Integer(DelphiHashLittle(PByte(@AData),aLength,aInitialValue));
  849. end;
  850. class function THashBobJenkins.GetHashValue(const aData: PByte; aLength: Integer; aInitialValue: Integer): Integer;
  851. begin
  852. Result:=DelphiHashLittle(AData,aLength,aInitialValue);
  853. end;
  854. class function THashBobJenkins.GetHashValue(const aData: UnicodeString): Integer;
  855. begin
  856. Result:=GetHashValue(PByte(aData),Length(aData)*SizeOf(UnicodeChar),0);
  857. end;
  858. class function THashBobJenkins.GetHashValue(const aData: RawByteString): Integer;
  859. begin
  860. Result:=GetHashValue(PByte(aData),Length(aData)*SizeOf(AnsiChar),0);
  861. end;
  862. procedure THashBobJenkins.Reset(aInitialValue: Integer);
  863. begin
  864. FCurrent:=aInitialValue;
  865. end;
  866. procedure THashBobJenkins.Update(aData: PByte; aLength: Cardinal);
  867. begin
  868. FCurrent:=DelphiHashLittle(AData,aLength,FCurrent);
  869. end;
  870. procedure THashBobJenkins.Update(var aData; aLength: Cardinal);
  871. begin
  872. Update(PByte(@AData),aLength);
  873. end;
  874. procedure THashBobJenkins.Update(const aData: TBytes; aLength: Cardinal);
  875. begin
  876. if aLength=0 then
  877. aLength:=Length(aData);
  878. Update(PByte(aData),aLength);
  879. end;
  880. procedure THashBobJenkins.Update(const aData: UnicodeString);
  881. begin
  882. Update(PByte(aData),Length(aData)*SizeOf(UnicodeChar));
  883. end;
  884. procedure THashBobJenkins.Update(const aData: RawByteString);
  885. begin
  886. Update(PByte(aData),Length(aData)*SizeOf(AnsiChar));
  887. end;
  888. function THashBobJenkins.HashAsBytes: TBytes;
  889. begin
  890. Result:=[];
  891. SetLength(Result,Sizeof(Cardinal));
  892. PCardinal(Result)^:=FCurrent;
  893. end;
  894. function THashBobJenkins.HashAsInteger: Integer;
  895. begin
  896. Result:=FCurrent;
  897. end;
  898. function THashBobJenkins.HashAsString: UnicodeString;
  899. begin
  900. Result:=HexStr(HashAsInteger,8);
  901. end;
  902. { THashFNV1a32 }
  903. class function THashFNV1a32.Create: THashFNV1a32;
  904. begin
  905. Result.Reset;
  906. end;
  907. class function THashFNV1a32.GetHashBytes(const aData: UnicodeString): TBytes;
  908. var
  909. C : Cardinal;
  910. begin
  911. Result:=Default(TBytes);
  912. SetLength(Result,SizeOf(Fnv32_t));
  913. C:=Cardinal(GetHashValue(aData));
  914. PFnv32_t(@Result[0])^:=C;
  915. end;
  916. class function THashFNV1a32.GetHashString(const aData: UnicodeString): UnicodeString;
  917. begin
  918. Result:=HexStr(FNV1_32a(Pointer(aData)^,Length(aData)*SizeOf(UnicodeChar),FNV_SEED),8);
  919. end;
  920. class function THashFNV1a32.GetHashString(const aData: RawByteString): UnicodeString;
  921. begin
  922. Result:=HexStr(FNV1_32a(Pointer(aData)^,Length(aData),FNV_SEED),8);
  923. end;
  924. class function THashFNV1a32.GetHashValue(const aData: UnicodeString): Integer;
  925. var
  926. C : Cardinal;
  927. begin
  928. C:=FNV1_32a(PByte(aData),Length(aData)*SizeOf(UnicodeChar),FNV_SEED);
  929. Result:=Integer(C);
  930. end;
  931. class function THashFNV1a32.GetHashValue(const aData: RawByteString): Integer;
  932. begin
  933. Result:=Integer(FNV1_32a(Pointer(aData)^,Length(aData), FNV_SEED));
  934. end;
  935. class function THashFNV1a32.GetHashValue(const aData; aLength: Cardinal; aInitialValue: Cardinal): Integer;
  936. begin
  937. Result:=Integer(FNV1_32a(aData,aLength,aInitialValue));
  938. end;
  939. procedure THashFNV1a32.Reset(aInitialValue: Cardinal);
  940. begin
  941. FCurrent:=aInitialValue;
  942. end;
  943. procedure THashFNV1a32.Update(const aData; aLength: Cardinal);
  944. begin
  945. FCurrent:=FNV1_32a(aData,aLength,FCurrent);
  946. end;
  947. procedure THashFNV1a32.Update(const aData: TBytes; aLength: Cardinal);
  948. begin
  949. if aLength=0 then
  950. aLength:=Length(aData);
  951. Update(aData[0],aLength);
  952. end;
  953. procedure THashFNV1a32.Update(const aData: UnicodeString);
  954. begin
  955. FCurrent:=FNV1_32a(PByte(aData),Length(aData)*SizeOf(UnicodeChar),FCurrent);
  956. end;
  957. procedure THashFNV1a32.Update(const aData: RawByteString);
  958. begin
  959. FCurrent:=FNV1_32a(PByte(aData),Length(aData)*SizeOf(AnsiChar),FCurrent);
  960. end;
  961. function THashFNV1a32.GetDigest: TBytes;
  962. begin
  963. Result:=Default(TBytes);
  964. SetLength(Result,SizeOf(Fnv32_t));
  965. PFnv32_t(@Result[0])^:=FCurrent;
  966. end;
  967. function THashFNV1a32.HashAsBytes: TBytes;
  968. begin
  969. Result:=GetDigest;
  970. end;
  971. function THashFNV1a32.HashAsInteger: Integer;
  972. begin
  973. Result:=Integer(FCurrent);
  974. end;
  975. function THashFNV1a32.HashAsString: UnicodeString;
  976. begin
  977. Result:=HexStr(FCurrent,8);
  978. end;
  979. end.