fpsha512.pp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876
  1. {
  2. This file is part of the Free Component Library.
  3. Copyright (c) 2021 by the Free Pascal team.
  4. SHA512/SHA384 and HMACSha512/HMACSha384 routines.
  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 fpsha512;
  12. {$mode ObjFPC}{$H+}
  13. {$modeswitch advancedrecords}
  14. { $define debugsha}
  15. interface
  16. uses
  17. Classes, SysUtils, fphashutils;
  18. Type
  19. THashBuffer = array[0..127] of Byte;
  20. { TSHA512 }
  21. TSHA512Base = record
  22. Context: array[0..7] of QWord;
  23. Buffer : THashBuffer;
  24. Index: UInt32;
  25. TotalLength: Int64;
  26. procedure Compress;
  27. procedure Final;
  28. procedure Init(Use384 : Boolean = False);
  29. procedure Update(PBuf: PByte; Size: UInt32); overload;
  30. procedure Update(const Value: TBytes); overload;
  31. {$IFDEF DEBUGSHA}
  32. private
  33. procedure DumpBuffer;
  34. procedure DumpHash;
  35. {$ENDIF DEBUGSHA}
  36. end;
  37. PSHA512Base = ^TSHA512Base;
  38. TSHA512Digest = packed array[0..63] of Byte;
  39. PSHA512Digest = ^TSHA512Digest;
  40. PSHA512 = ^TSHA512;
  41. TSHA512 = record
  42. Base : TSHA512Base;
  43. Digest: TSHA512Digest;
  44. function IsEqual(const ADigest: TSHA512Digest): Boolean;
  45. procedure OutputHexa(out Result: AnsiString);
  46. procedure Compress;
  47. procedure Final;
  48. procedure Init;
  49. procedure Update(PBuf: PByte; Size: UInt32); overload;
  50. procedure Update(const Value: TBytes); overload;
  51. // Calculate SHA512, return digest as bytes.
  52. class procedure DigestBytes(const Value: TBytes; out Result: TBytes) ; static;
  53. // Calculate SHA512, return digest as base64(url) string
  54. class procedure DigestBase64(const Value: TBytes; const IsURL: Boolean; out Result: AnsiString); static;
  55. // Calculate SHA512, return digest as HEX encoded string
  56. class procedure DigestHexa(const Value: TBytes; out Result: AnsiString); static;
  57. // HMAC using SHA512 as hash
  58. Class function HMAC(Key: PByte; KeySize: UInt32; Data: PByte; DataSize: UInt32; var aDigest: TSHA512Digest): Boolean; overload; static;
  59. class function HMAC(Key: PByte; KeySize: UInt32; Data: PByte; DataSize: UInt32; Data2: PByte; DataSize2: UInt32; Data3: PByte; DataSize3: UInt32; var aDigest: TSHA512Digest): Boolean; overload; static;
  60. // Calculate HMacSHA512, return digest as hex string.
  61. class function HMACHexa(const Key, Data: TBytes; out SignatureHexa: AnsiString): Boolean; overload; static;
  62. // Calculate SHA512 from a stream, return digest.
  63. class procedure Stream(aStream: TStream; out aDigest: TSHA512Digest); static; overload;
  64. class function Stream(aStream: TStream): TSHA512Digest; static; overload;
  65. // Digest Stream, result as HexaDecimal string.
  66. class procedure StreamHexa(aStream: TStream; out Result: AnsiString); static; overload;
  67. class Function StreamHexa(aStream: TStream): AnsiString; static overload;
  68. // Digest Stream, result as Base64-encoded string
  69. class procedure StreamBase64(aStream: TStream; isURL : Boolean; out Result: AnsiString); static; overload;
  70. class Function StreamBase64(aStream: TStream; isURL : Boolean): AnsiString; static; overload;
  71. // HKDF : Derive key of desired length from a salt,input key and info (RF5869, using HMACSHA512) .
  72. class function HKDF(const Salt, IKM, Info: TBytes; var Output: TBytes; const DesiredLen: Integer): Boolean; static;
  73. end;
  74. TSHA384Digest = packed array[0..47] of Byte;
  75. PSHA384Digest = ^TSHA384Digest;
  76. PSHA384 = ^TSHA384;
  77. TSHA384 = record
  78. Base : TSHA512Base;
  79. Digest: TSHA384Digest;
  80. function IsEqual(const ADigest: TSHA384Digest): Boolean;
  81. procedure OutputHexa(out Result: AnsiString);
  82. procedure Compress;
  83. procedure Final;
  84. procedure Init;
  85. procedure Update(PBuf: PByte; Size: UInt32); overload;
  86. procedure Update(const Value: TBytes); overload;
  87. // Calculate SHA384, return digest as bytes.
  88. class procedure DigestBytes(const Value: TBytes; out Result: TBytes) ; static;
  89. // Calculate SHA384, return digest as base64(url) string
  90. class procedure DigestBase64(const Value: TBytes; const IsURL: Boolean; out Result: AnsiString); static;
  91. // Calculate SHA384, return digest as HEX encoded string
  92. class procedure DigestHexa(const Value: TBytes; out Result: AnsiString); static;
  93. // HMAC using SHA384 as hash
  94. Class function HMAC(Key: PByte; KeySize: UInt32; Data: PByte; DataSize: UInt32; var aDigest: TSHA384Digest): Boolean; overload; static;
  95. class function HMAC(Key: PByte; KeySize: UInt32; Data: PByte; DataSize: UInt32; Data2: PByte; DataSize2: UInt32; Data3: PByte; DataSize3: UInt32; var aDigest: TSHA384Digest): Boolean; overload; static;
  96. // Calculate HMacSHA384, return digest as hex string.
  97. class function HMACHexa(const Key, Data: TBytes; out SignatureHexa: AnsiString): Boolean; overload; static;
  98. // Calculate SHA384 from a stream, return digest.
  99. class procedure Stream(aStream: TStream; out aDigest: TSHA384Digest); static; overload;
  100. class function Stream(aStream: TStream): TSHA384Digest; static; overload;
  101. // Digest Stream, result as HexaDecimal string.
  102. class procedure StreamHexa(aStream: TStream; out Result: AnsiString); static; overload;
  103. class Function StreamHexa(aStream: TStream): AnsiString; static overload;
  104. // Digest Stream, result as Base64-encoded string
  105. class procedure StreamBase64(aStream: TStream; isURL : Boolean; out Result: AnsiString); static; overload;
  106. class Function StreamBase64(aStream: TStream; isURL : Boolean): AnsiString; static; overload;
  107. // HKDF : Derive key of desired length from a salt,input key and info (RF5869, using HMACSHA384) .
  108. class function HKDF(const Salt, IKM, Info: TBytes; var Output: TBytes; const DesiredLen: Integer): Boolean; static;
  109. end;
  110. Const
  111. SHA512_DIGEST_SIZE = SizeOf(TSHA512Digest); // 64
  112. SHA384_DIGEST_SIZE = SizeOf(TSHA384Digest); // 48
  113. implementation
  114. Const
  115. Seed512Hash : Array[0..7] of QWord
  116. = (QWord($6A09E667F3BCC908),
  117. QWord($BB67AE8584CAA73B),
  118. QWord($3C6EF372FE94F82B),
  119. QWord($A54FF53A5F1D36F1),
  120. QWord($510E527FADE682D1),
  121. QWord($9B05688C2B3E6C1F),
  122. QWord($1F83D9ABFB41BD6B),
  123. QWord($5BE0CD19137E2179)
  124. );
  125. Seed384Hash : Array[0..7] of QWord
  126. = (QWord($cbbb9d5dc1059ed8),
  127. QWord($629a292a367cd507),
  128. QWord($9159015a3070dd17),
  129. QWord($152fecd8f70e5939),
  130. QWord($67332667ffc00b31),
  131. QWord($8eb44a8768581511),
  132. QWord($db0c2e0d64f98fa7),
  133. QWord($47b5481dbefa4fa4)
  134. );
  135. { ----------------------------------------------------------------------
  136. TSHA512Base
  137. ----------------------------------------------------------------------}
  138. procedure TSHA512Base.Init(Use384 : Boolean = False);
  139. Var
  140. I : Integer ;
  141. begin
  142. Self.Index := 0;
  143. Self.TotalLength := 0;
  144. FillChar(Buffer, Sizeof(Buffer), 0);
  145. if Not Use384 then
  146. begin
  147. For I:=0 to 7 do
  148. Context[i]:=Seed512Hash[i];
  149. end
  150. else
  151. begin
  152. For I:=0 to 7 do
  153. Context[i]:=Seed384Hash[i];
  154. end;
  155. end;
  156. {$IFDEF DEBUGSHA}
  157. procedure Tsha512Base.DumpBuffer;
  158. Var
  159. i : Integer;
  160. begin
  161. For I:=0 to SizeOf(Buffer)-1 do
  162. Write(IntToStr(Buffer[i]),',');
  163. Writeln;
  164. end;
  165. procedure TSHA512Base.DumpHash;
  166. Var
  167. i : Integer;
  168. begin
  169. For I:=0 to 7 do
  170. Write(IntToStr(Context[i]),' ');
  171. Writeln;
  172. end;
  173. {$ENDIF}
  174. procedure TSHA512Base.Update(const Value: TBytes);
  175. begin
  176. Update(PByte(Value), System.Length(Value));
  177. end;
  178. procedure TSHA512Base.Update(PBuf: PByte; Size: UInt32);
  179. var
  180. Len: UInt32;
  181. begin
  182. Inc(TotalLength, Int64(UInt32(Size)) * 8);
  183. while Size > 0 do
  184. begin
  185. Len:=Sizeof(Buffer)-Index;
  186. if Len <= UInt32(Size) then
  187. begin
  188. Move(PBuf^, Buffer[Index], Len);
  189. Dec(Size, Len);
  190. Inc(PBuf, Len);
  191. Compress;
  192. Self.Index := 0;
  193. end else
  194. begin
  195. Move(PBuf^, Buffer[Index], Size);
  196. Inc(Self.Index, Size);
  197. Size := 0;
  198. end;
  199. end;
  200. end;
  201. procedure TSHA512Base.Final;
  202. Var
  203. I : Integer;
  204. begin
  205. Buffer[Index] := $80;
  206. FillChar(Buffer[Index+1], SizeOf(Buffer)-Index-1, 0);
  207. if Index >= 112 then
  208. Compress;
  209. PQWord(@Buffer[112])^ := 0;
  210. PQWord(@Buffer[120])^ := SwapEndian(TotalLength);
  211. Compress;
  212. For I:=0 to 7 do
  213. Context[i] := NtoBE(Context[i]);
  214. end;
  215. procedure TSHA512Base.Compress;
  216. const
  217. K: array[0..79] of QWord = (
  218. QWord($428A2F98D728AE22),QWord($7137449123EF65CD),QWord($B5C0FBCFEC4D3B2F),QWord($E9B5DBA58189DBBC),
  219. QWord($3956C25BF348B538),QWord($59F111F1B605D019),QWord($923F82A4AF194F9B),QWord($AB1C5ED5DA6D8118),
  220. QWord($D807AA98A3030242),QWord($12835B0145706FBE),QWord($243185BE4EE4B28C),QWord($550C7DC3D5FFB4E2),
  221. QWord($72BE5D74F27B896F),QWord($80DEB1FE3B1696B1),QWord($9BDC06A725C71235),QWord($C19BF174CF692694),
  222. QWord($E49B69C19EF14AD2),QWord($EFBE4786384F25E3),QWord($0FC19DC68B8CD5B5),QWord($240CA1CC77AC9C65),
  223. QWord($2DE92C6F592B0275),QWord($4A7484AA6EA6E483),QWord($5CB0A9DCBD41FBD4),QWord($76F988DA831153B5),
  224. QWord($983E5152EE66DFAB),QWord($A831C66D2DB43210),QWord($B00327C898FB213F),QWord($BF597FC7BEEF0EE4),
  225. QWord($C6E00BF33DA88FC2),QWord($D5A79147930AA725),QWord($06CA6351E003826F),QWord($142929670A0E6E70),
  226. QWord($27B70A8546D22FFC),QWord($2E1B21385C26C926),QWord($4D2C6DFC5AC42AED),QWord($53380D139D95B3DF),
  227. QWord($650A73548BAF63DE),QWord($766A0ABB3C77B2A8),QWord($81C2C92E47EDAEE6),QWord($92722C851482353B),
  228. QWord($A2BFE8A14CF10364),QWord($A81A664BBC423001),QWord($C24B8B70D0F89791),QWord($C76C51A30654BE30),
  229. QWord($D192E819D6EF5218),QWord($D69906245565A910),QWord($F40E35855771202A),QWord($106AA07032BBD1B8),
  230. QWord($19A4C116B8D2D0C8),QWord($1E376C085141AB53),QWord($2748774CDF8EEB99),QWord($34B0BCB5E19B48A8),
  231. QWord($391C0CB3C5C95A63),QWord($4ED8AA4AE3418ACB),QWord($5B9CCA4F7763E373),QWord($682E6FF3D6B2B8A3),
  232. QWord($748F82EE5DEFB2FC),QWord($78A5636F43172F60),QWord($84C87814A1F0AB72),QWord($8CC702081A6439EC),
  233. QWord($90BEFFFA23631E28),QWord($A4506CEBDE82BDE9),QWord($BEF9A3F7B2C67915),QWord($C67178F2E372532B),
  234. QWord($CA273ECEEA26619C),QWord($D186B8C721C0C207),QWord($EADA7DD6CDE0EB1E),QWord($F57D4F7FEE6ED178),
  235. QWord($06F067AA72176FBA),QWord($0A637DC5A2C898A6),QWord($113F9804BEF90DAE),QWord($1B710B35131C471B),
  236. QWord($28DB77F523047D84),QWord($32CAAB7B40C72493),QWord($3C9EBE0A15C9BEBC),QWord($431D67C49C100D4C),
  237. QWord($4CC5D4BECB3E42B6),QWord($597F299CFC657E2A),QWord($5FCB6FAB3AD6FAEC),QWord($6C44198C4A475817)
  238. );
  239. type
  240. TQWordArray = Array[0..79] of QWord;
  241. var
  242. A, B, C, D, E, F, G, H: QWord;
  243. I: UInt32;
  244. t1, t2: QWord;
  245. W : TQWordArray;
  246. begin
  247. {$IFDEF DEBUGSHA} DumpHash; DumpBuffer; {$ENDIF}
  248. W:=Default(TQWordArray);
  249. a:= Context[0];
  250. b:= Context[1];
  251. c:= Context[2];
  252. d:= Context[3];
  253. e:= Context[4];
  254. f:= Context[5];
  255. g:= Context[6];
  256. h:= Context[7];
  257. // Fill first 16 QWords, swap endianness.
  258. Move(Buffer,W,SizeOf(THashBuffer));
  259. for i:= 0 to 15 do
  260. W[i]:= BeTON(W[i]);
  261. for i:= 0 to 79 do
  262. begin
  263. if I>=16 then
  264. W[i]:= W[i-16]
  265. // SIGMA4(x) = (ROR64(x, 19) ^ ROR64(x, 61) ^ SHR64(x, 6))
  266. + (((W[i-2] shr 19) or (W[i-2] shl 45))
  267. xor ((W[i-2] shr 61) or (W[i-2] shl 3))
  268. xor (W[i-2] shr 6))
  269. + W[i-7]
  270. // Sigma3 (x) = (ROR64(x, 1) ^ ROR64(x, 8) ^ SHR64(x, 7));
  271. + (((W[i-15] shr 1) or (W[i-15] shl 63))
  272. xor ((W[i-15] shr 8) or (W[i-15] shl 56))
  273. xor (W[i-15] shr 7));
  274. t1:= h
  275. // Sigma2(x) = (ROR64(x, 14) ^ ROR64(x, 18) ^ ROR64(x, 41))
  276. + (((e shr 14) or (e shl 50)) xor ((e shr 18) or (e shl 46)) xor ((e shr 41) or (e shl 23)))
  277. // CH(x, y, z) = (((x) & (y)) | (~(x) & (z)))
  278. + ((e and f) or (not e and g))
  279. + K[i] + W[i];
  280. t2:= // SIGMA1(x) = (ROR64(x, 28) ^ ROR64(x, 34) ^ ROR64(x, 39))
  281. (((a shr 28) or (a shl 36)) xor ((a shr 34) or (a shl 30)) xor ((a shr 39) or (a shl 25))) +
  282. // MAJ(x,y,z) = (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
  283. ((a and b) or (a and c) or (b and c));
  284. h:= g;
  285. g:= f;
  286. f:= e;
  287. e:= d + t1;
  288. d:= c;
  289. c:= b;
  290. b:= a;
  291. a:= t1 + t2;
  292. end;
  293. Inc(Context[0], A);
  294. Inc(Context[1], B);
  295. Inc(Context[2], C);
  296. Inc(Context[3], D);
  297. Inc(Context[4], E);
  298. Inc(Context[5], F);
  299. Inc(Context[6], G);
  300. Inc(Context[7], H);
  301. FillChar(Buffer,Sizeof(Buffer),0);
  302. {$IFDEF DEBUGSHA} DumpHash;{$ENDIF}
  303. end;
  304. { ----------------------------------------------------------------------
  305. TSHA512
  306. ----------------------------------------------------------------------}
  307. procedure TSHA512.Init;
  308. begin
  309. Base.Init(False);
  310. end;
  311. procedure TSHA512.Compress;
  312. begin
  313. Base.Compress;
  314. end;
  315. procedure TSHA512.Final;
  316. begin
  317. Base.Final;
  318. Move(Base.Context, Digest, Sizeof(Digest));
  319. end;
  320. function TSHA512.IsEqual(const ADigest: TSHA512Digest): Boolean;
  321. var
  322. Left, Right: TBytes;
  323. begin
  324. Left:=BytesFromVar(@ADigest, SizeOf(ADigest));
  325. Right:=BytesFromVar(@Self.Digest, SizeOf(Self.Digest));
  326. Result:=CompareMem(Pointer(Left), Pointer(Right),System.Length(Left));
  327. end;
  328. procedure TSHA512.Update(PBuf: PByte; Size: UInt32);
  329. begin
  330. Base.Update(PBuf,Size);
  331. end;
  332. procedure TSHA512.Update(const Value: TBytes);
  333. begin
  334. Base.Update(Value);
  335. end;
  336. class procedure TSHA512.DigestBytes(const Value: TBytes; out Result: TBytes);
  337. var
  338. lSHA512: TSHA512;
  339. begin
  340. lSHA512.Init;
  341. lSHA512.Update(Value);
  342. lSHA512.Final;
  343. BytesFromVar(Result, @lSHA512.Digest[0], SizeOf(lSHA512.Digest));
  344. end;
  345. class procedure TSHA512.DigestBase64(const Value: TBytes; const IsURL: Boolean; out Result: AnsiString);
  346. var
  347. S : TBytes;
  348. lSHA512: TSHA512;
  349. begin
  350. lSHA512.Init;
  351. lSHA512.Update(Value);
  352. lSHA512.Final;
  353. BytesFromVar(S, @lSHA512.Digest[0], SizeOf(lSHA512.Digest));
  354. BytesEncodeBase64(S, Result, IsURL, False, False);
  355. end;
  356. class procedure TSHA512.DigestHexa(const Value: TBytes; out Result: AnsiString);
  357. var
  358. SHA512: TSHA512;
  359. begin
  360. SHA512.Init;
  361. SHA512.Update(Value);
  362. SHA512.Final;
  363. SHA512.OutputHexa(Result);
  364. end;
  365. procedure TSHA512.OutputHexa(out Result: AnsiString);
  366. begin
  367. BytesToHexStr(Result,PByte(@Self.Digest),SizeOf(Self.Digest));
  368. end;
  369. class function TSHA512.HMAC(Key: PByte; KeySize: UInt32; Data: PByte; DataSize: UInt32; var aDigest: TSHA512Digest): Boolean;
  370. begin
  371. Result := HMAC(Key, KeySize, Data, DataSize, nil, 0, nil, 0, aDigest);
  372. end;
  373. {Generate a SHA512 HMAC (Hashed Message Authentication Code) using the Key and Data
  374. The SHA512 HMAC algorithm is:
  375. SHA512(Key xor oPad, SHA512(Key xor iPad, Data))
  376. Where iPad is the byte $36 repeated 128 times
  377. oPad is the byte $5c repeated 128 times
  378. If Key is more than 128 bytes it will be hashed to Key = SHA512(Key) instead
  379. If Key is less than 128 bytes it will be padded with zeros }
  380. class function TSHA512.HMAC(Key: PByte; KeySize: UInt32; Data: PByte; DataSize: UInt32; Data2: PByte; DataSize2: UInt32; Data3: PByte; DataSize3: UInt32; var aDigest: TSHA512Digest): Boolean;
  381. Type
  382. TBuf128 = array[0..127] of Byte;
  383. var
  384. Count: UInt32;
  385. KeyBuffer, PadBuffer: TBuf128;
  386. SHA512, SHA512_: TSHA512;
  387. begin
  388. Result:=False;
  389. if Key = nil then
  390. Exit;
  391. if Data = nil then
  392. Exit;
  393. KeyBuffer:=Default(TBuf128);
  394. SHA512.Init;
  395. if KeySize > 128 then
  396. begin
  397. SHA512.Update(Key, KeySize);
  398. SHA512.Final;
  399. System.Move(SHA512.Digest[0], KeyBuffer[0], SizeOf(SHA512.Digest));
  400. end else
  401. System.Move(Key^, KeyBuffer[0], KeySize);
  402. // XOR the key buffer with the iPad value
  403. for Count := 0 to 127 do
  404. PadBuffer[Count] := KeyBuffer[Count] xor $36;
  405. SHA512.Init;
  406. SHA512.Update(@PadBuffer, SizeOf(PadBuffer));
  407. SHA512.Update(Data, DataSize);
  408. if Data2 <> nil then
  409. SHA512.Update(Data2, DataSize2);
  410. if Data3 <> nil then
  411. SHA512.Update(Data3, DataSize3);
  412. SHA512.Final;
  413. // XOR the key buffer with the oPad value
  414. for Count := 0 to 127 do
  415. PadBuffer[Count] := KeyBuffer[Count] xor $5C;
  416. // SHA512 the key buffer and the result of the inner SHA512 (Outer)
  417. SHA512_.Init;
  418. SHA512_.Update(@PadBuffer, SizeOf(PadBuffer));
  419. SHA512_.Update(@SHA512.Digest, SizeOf(SHA512.Digest));
  420. SHA512_.Final;
  421. System.Move(SHA512_.Digest, aDigest, SizeOf(aDigest));
  422. // FillChar(KeyDigest, SizeOf(TSHA1Digest),0);
  423. // FillChar(KeyBuffer, SizeOf(TSHA1ByteBuffer),0);
  424. // FillChar(PadBuffer, SizeOf(TSHA1ByteBuffer),0);
  425. Result:=True;
  426. end;
  427. // @Result[64]
  428. class function TSHA512.HMACHexa(const Key, Data: TBytes; out SignatureHexa: AnsiString): Boolean; overload;
  429. var
  430. aDigest: TSHA512Digest;
  431. S: TBytes;
  432. begin
  433. aDigest:=Default(TSHA512Digest);
  434. Result := HMAC(PByte(Key),System.Length(Key), PByte(Data), System.Length(Data), aDigest);
  435. BytesFromVar(S, @aDigest[0], SizeOf(aDigest));
  436. BytesToHexStr(SignatureHexa,S);
  437. end;
  438. class procedure TSHA512.Stream(aStream: TStream; out aDigest: TSHA512Digest);
  439. const
  440. BUFFER_SIZE = 64*1024;
  441. var
  442. aLen : LongInt;
  443. lBuffer: TBytes;
  444. SHA512: TSHA512;
  445. begin
  446. lBuffer:=Nil;
  447. SHA512.Init;
  448. SetLength(lBuffer,BUFFER_SIZE);
  449. repeat
  450. aLen:=aStream.Read(lBuffer, BUFFER_SIZE);
  451. if aLen = 0 then
  452. Break;
  453. SHA512.Update(PByte(lBuffer),aLen);
  454. until aLen=0;
  455. SHA512.Final;
  456. aDigest:=SHA512.Digest;
  457. end;
  458. class function TSHA512.Stream(aStream: TStream): TSHA512Digest;
  459. begin
  460. Stream(aStream,Result);
  461. end;
  462. class procedure TSHA512.StreamHexa(aStream: TStream; out Result: AnsiString);
  463. Var
  464. B : TBytes;
  465. aDigest : TSHA512Digest;
  466. begin
  467. Stream(aStream,aDigest);
  468. BytesFromVar(B,@aDigest,SizeOf(TSHA512Digest));
  469. BytesToHexStr(Result,B);
  470. end;
  471. class function TSHA512.StreamHexa(aStream: TStream): AnsiString;
  472. begin
  473. Result:='';
  474. StreamHexa(aStream,Result);
  475. end;
  476. class procedure TSHA512.StreamBase64(aStream: TStream; isURL : Boolean; out Result: AnsiString);
  477. Var
  478. B : TBytes;
  479. aDigest : TSHA512Digest;
  480. begin
  481. Stream(aStream,aDigest);
  482. BytesFromVar(B,@aDigest,SizeOf(TSHA512Digest));
  483. BytesEncodeBase64(B,Result,isUrl,False,False);
  484. end;
  485. Class Function TSHA512.StreamBase64(aStream: TStream; isURL : Boolean): AnsiString;
  486. begin
  487. Result:='';
  488. StreamBase64(aStream,isURL,Result);
  489. end;
  490. class function TSHA512.HKDF(const Salt, IKM, Info: TBytes; var Output: TBytes; const DesiredLen: Integer): Boolean;
  491. var
  492. PRK, T: TSHA512Digest;
  493. Round: Byte;
  494. begin
  495. PRK:=Default(TSHA512Digest);
  496. T:=Default(TSHA512Digest);
  497. Result := HMAC(PByte(Salt), System.Length(Salt), PByte(IKM), Length(IKM), PRK);
  498. if not Result then
  499. Exit;
  500. Round := 1;
  501. while System.Length(Output) < DesiredLen do
  502. begin
  503. if System.Length(Output) = 0 then
  504. Result := HMAC(@PRK, SizeOf(PRK), PByte(Info), System.Length(Info), @Round, SizeOf(Round), nil, 0, T)
  505. else
  506. Result := HMAC(@PRK, SizeOf(PRK), @T, SizeOf(T), PByte(Info), System.Length(Info), @Round, SizeOf(Round), T);
  507. if not Result then
  508. Exit;
  509. Inc(Round);
  510. Output:=Concat(OutPut,BytesFromVar(@T,SizeOf(T)));
  511. if Length(Output) >= DesiredLen then
  512. Break;
  513. end;
  514. SetLength(Output,DesiredLen);
  515. end;
  516. { ----------------------------------------------------------------------
  517. TSHA384
  518. ----------------------------------------------------------------------}
  519. procedure TSHA384.Init;
  520. begin
  521. Base.Init(True);
  522. end;
  523. procedure TSHA384.Compress;
  524. begin
  525. Base.Compress;
  526. end;
  527. procedure TSHA384.Final;
  528. begin
  529. Base.Final;
  530. Move(Base.Context, Digest, Sizeof(Digest));
  531. end;
  532. function TSHA384.IsEqual(const ADigest: TSHA384Digest): Boolean;
  533. var
  534. Left, Right: TBytes;
  535. begin
  536. Left:=BytesFromVar(@ADigest, SizeOf(ADigest));
  537. Right:=BytesFromVar(@Self.Digest, SizeOf(Self.Digest));
  538. Result:=CompareMem(Pointer(Left), Pointer(Right),System.Length(Left));
  539. end;
  540. procedure TSHA384.Update(PBuf: PByte; Size: UInt32);
  541. begin
  542. Base.Update(PBuf,Size);
  543. end;
  544. procedure TSHA384.Update(const Value: TBytes);
  545. begin
  546. Base.Update(Value);
  547. end;
  548. class procedure TSHA384.DigestBytes(const Value: TBytes; out Result: TBytes);
  549. var
  550. lSHA384: TSHA384;
  551. begin
  552. lSHA384.Init;
  553. lSHA384.Update(Value);
  554. lSHA384.Final;
  555. BytesFromVar(Result, @lSHA384.Digest[0], SizeOf(lSHA384.Digest));
  556. end;
  557. class procedure TSHA384.DigestBase64(const Value: TBytes; const IsURL: Boolean; out Result: AnsiString);
  558. var
  559. S : TBytes;
  560. lSHA384: TSHA384;
  561. begin
  562. lSHA384.Init;
  563. lSHA384.Update(Value);
  564. lSHA384.Final;
  565. BytesFromVar(S, @lSHA384.Digest[0], SizeOf(lSHA384.Digest));
  566. BytesEncodeBase64(S, Result, IsURL, False, False);
  567. end;
  568. class procedure TSHA384.DigestHexa(const Value: TBytes; out Result: AnsiString);
  569. var
  570. SHA384: TSHA384;
  571. begin
  572. SHA384.Init;
  573. SHA384.Update(Value);
  574. SHA384.Final;
  575. SHA384.OutputHexa(Result);
  576. end;
  577. procedure TSHA384.OutputHexa(out Result: AnsiString);
  578. begin
  579. BytesToHexStr(Result,PByte(@Self.Digest),SizeOf(Self.Digest));
  580. end;
  581. class function TSHA384.HMAC(Key: PByte; KeySize: UInt32; Data: PByte; DataSize: UInt32; var aDigest: TSHA384Digest): Boolean;
  582. begin
  583. Result := HMAC(Key, KeySize, Data, DataSize, nil, 0, nil, 0, aDigest);
  584. end;
  585. {Generate a SHA384 HMAC (Hashed Message Authentication Code) using the Key and Data
  586. The SHA384 HMAC algorithm is:
  587. SHA384(Key xor oPad, SHA384(Key xor iPad, Data))
  588. Where iPad is the byte $36 repeated 128 times
  589. oPad is the byte $5c repeated 128 times
  590. If Key is more than 128 bytes it will be hashed to Key = SHA384(Key) instead
  591. If Key is less than 128 bytes it will be padded with zeros }
  592. class function TSHA384.HMAC(Key: PByte; KeySize: UInt32; Data: PByte; DataSize: UInt32; Data2: PByte; DataSize2: UInt32; Data3: PByte; DataSize3: UInt32; var aDigest: TSHA384Digest): Boolean;
  593. Type
  594. TBuf128 = array[0..127] of Byte;
  595. var
  596. Count: UInt32;
  597. KeyBuffer, PadBuffer: TBuf128;
  598. SHA384, SHA384_: TSHA384;
  599. begin
  600. Result:=False;
  601. if Key = nil then
  602. Exit;
  603. if Data = nil then
  604. Exit;
  605. KeyBuffer:=Default(TBuf128);
  606. SHA384.Init;
  607. if KeySize > 128 then
  608. begin
  609. SHA384.Update(Key, KeySize);
  610. SHA384.Final;
  611. System.Move(SHA384.Digest[0], KeyBuffer[0], SizeOf(SHA384.Digest));
  612. end else
  613. System.Move(Key^, KeyBuffer[0], KeySize);
  614. // XOR the key buffer with the iPad value
  615. for Count := 0 to 127 do
  616. PadBuffer[Count] := KeyBuffer[Count] xor $36;
  617. SHA384.Init;
  618. SHA384.Update(@PadBuffer, SizeOf(PadBuffer));
  619. SHA384.Update(Data, DataSize);
  620. if Data2 <> nil then
  621. SHA384.Update(Data2, DataSize2);
  622. if Data3 <> nil then
  623. SHA384.Update(Data3, DataSize3);
  624. SHA384.Final;
  625. // XOR the key buffer with the oPad value
  626. for Count := 0 to 127 do
  627. PadBuffer[Count] := KeyBuffer[Count] xor $5C;
  628. // SHA384 the key buffer and the result of the inner SHA384 (Outer)
  629. SHA384_.Init;
  630. SHA384_.Update(@PadBuffer, SizeOf(PadBuffer));
  631. SHA384_.Update(@SHA384.Digest, SizeOf(SHA384.Digest));
  632. SHA384_.Final;
  633. System.Move(SHA384_.Digest, aDigest, SizeOf(aDigest));
  634. // FillChar(KeyDigest, SizeOf(TSHA1Digest),0);
  635. // FillChar(KeyBuffer, SizeOf(TSHA1ByteBuffer),0);
  636. // FillChar(PadBuffer, SizeOf(TSHA1ByteBuffer),0);
  637. Result:=True;
  638. end;
  639. // @Result[64]
  640. class function TSHA384.HMACHexa(const Key, Data: TBytes; out SignatureHexa: AnsiString): Boolean; overload;
  641. var
  642. aDigest: TSHA384Digest;
  643. S: TBytes;
  644. begin
  645. aDigest:=Default(TSHA384Digest);
  646. Result := HMAC(PByte(Key),System.Length(Key), PByte(Data), System.Length(Data), aDigest);
  647. BytesFromVar(S, @aDigest[0], SizeOf(aDigest));
  648. BytesToHexStr(SignatureHexa,S);
  649. end;
  650. class procedure TSHA384.Stream(aStream: TStream; out aDigest: TSHA384Digest);
  651. const
  652. BUFFER_SIZE = 64*1024;
  653. var
  654. aLen : LongInt;
  655. lBuffer: TBytes;
  656. SHA384: TSHA384;
  657. begin
  658. lBuffer:=Nil;
  659. SHA384.Init;
  660. SetLength(lBuffer,BUFFER_SIZE);
  661. repeat
  662. aLen:=aStream.Read(lBuffer, BUFFER_SIZE);
  663. if aLen = 0 then
  664. Break;
  665. SHA384.Update(PByte(lBuffer),aLen);
  666. until aLen=0;
  667. SHA384.Final;
  668. aDigest:=SHA384.Digest;
  669. end;
  670. class function TSHA384.Stream(aStream: TStream): TSHA384Digest;
  671. begin
  672. Stream(aStream,Result);
  673. end;
  674. class procedure TSHA384.StreamHexa(aStream: TStream; out Result: AnsiString);
  675. Var
  676. B : TBytes;
  677. aDigest : TSHA384Digest;
  678. begin
  679. Stream(aStream,aDigest);
  680. BytesFromVar(B,@aDigest,SizeOf(TSHA384Digest));
  681. BytesToHexStr(Result,B);
  682. end;
  683. class function TSHA384.StreamHexa(aStream: TStream): AnsiString;
  684. begin
  685. Result:='';
  686. StreamHexa(aStream,Result);
  687. end;
  688. class procedure TSHA384.StreamBase64(aStream: TStream; isURL : Boolean; out Result: AnsiString);
  689. Var
  690. B : TBytes;
  691. aDigest : TSHA384Digest;
  692. begin
  693. Stream(aStream,aDigest);
  694. BytesFromVar(B,@aDigest,SizeOf(TSHA384Digest));
  695. BytesEncodeBase64(B,Result,isUrl,False,False);
  696. end;
  697. Class Function TSHA384.StreamBase64(aStream: TStream; isURL : Boolean): AnsiString;
  698. begin
  699. Result:='';
  700. StreamBase64(aStream,isURL,Result);
  701. end;
  702. class function TSHA384.HKDF(const Salt, IKM, Info: TBytes; var Output: TBytes; const DesiredLen: Integer): Boolean;
  703. var
  704. PRK, T: TSHA384Digest;
  705. Round: Byte;
  706. begin
  707. PRK:=Default(TSHA384Digest);
  708. T:=Default(TSHA384Digest);
  709. Result := HMAC(PByte(Salt), System.Length(Salt), PByte(IKM), Length(IKM), PRK);
  710. if not Result then
  711. Exit;
  712. Round := 1;
  713. while System.Length(Output) < DesiredLen do
  714. begin
  715. if System.Length(Output) = 0 then
  716. Result := HMAC(@PRK, SizeOf(PRK), PByte(Info), System.Length(Info), @Round, SizeOf(Round), nil, 0, T)
  717. else
  718. Result := HMAC(@PRK, SizeOf(PRK), @T, SizeOf(T), PByte(Info), System.Length(Info), @Round, SizeOf(Round), T);
  719. if not Result then
  720. Exit;
  721. Inc(Round);
  722. Output:=Concat(OutPut,BytesFromVar(@T,SizeOf(T)));
  723. if Length(Output) >= DesiredLen then
  724. Break;
  725. end;
  726. SetLength(Output,DesiredLen);
  727. end;
  728. end.