argon2.pas 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226
  1. {
  2. /*
  3. * Argon2 reference source code package - reference C implementations
  4. *
  5. * Copyright 2015
  6. * Daniel Dinu, Dmitry Khovratovich, Jean-Philippe Aumasson, and Samuel Neves
  7. *
  8. * Pascal tranlastion in 2018 by Alexander Koblov ([email protected])
  9. *
  10. * You may use this work under the terms of a Creative Commons CC0 1.0
  11. * License/Waiver or the Apache Public License 2.0, at your option. The terms of
  12. * these licenses can be found at:
  13. *
  14. * - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
  15. * - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
  16. *
  17. * You should have received a copy of both of these licenses along with this
  18. * software. If not, they may be obtained at the above URLs.
  19. */
  20. }
  21. unit Argon2;
  22. {$mode objfpc}{$H+}
  23. {.$define GENKAT}
  24. interface
  25. uses
  26. CTypes, DCblake2;
  27. const
  28. //* Number of synchronization points between lanes per pass */
  29. ARGON2_SYNC_POINTS = cuint32(4);
  30. //* Flags to determine which fields are securely wiped (default = no wipe). */
  31. ARGON2_DEFAULT_FLAGS = cuint32(0);
  32. ARGON2_FLAG_CLEAR_PASSWORD = (cuint32(1) shl 0);
  33. ARGON2_FLAG_CLEAR_SECRET = (cuint32(1) shl 1);
  34. const
  35. //* Error codes */
  36. ARGON2_OK = 0;
  37. ARGON2_MEMORY_ALLOCATION_ERROR = -22;
  38. ARGON2_INCORRECT_PARAMETER = -25;
  39. ARGON2_THREAD_FAIL = -33;
  40. type
  41. Pargon2_context = ^Targon2_context;
  42. Targon2_context = record
  43. out_: pcuint8; //* output array */
  44. outlen: cuint32; //* digest length */
  45. pwd: pcuint8; //* password array */
  46. pwdlen: cuint32; //* password length */
  47. salt: pcuint8; //* salt array */
  48. saltlen: cuint32; //* salt length */
  49. secret: pcuint8; //* key array */
  50. secretlen: cuint32; //* key length */
  51. ad: pcuint8; //* associated data array */
  52. adlen: cuint32; //* associated data length */
  53. t_cost: cuint32; //* number of passes */
  54. m_cost: cuint32; //* amount of memory requested (KB) */
  55. lanes: cuint32; //* number of lanes */
  56. threads: cuint32; //* maximum number of threads */
  57. version: cuint32; //* version number */
  58. flags: cuint32; //* array of bool options */
  59. end;
  60. //* Argon2 primitive type */
  61. Targon2_type = (
  62. Argon2_d = 0,
  63. Argon2_i = 1,
  64. Argon2_id = 2
  65. );
  66. //* Version of the algorithm */
  67. Targon2_version = (
  68. ARGON2_VERSION_10 = $10,
  69. ARGON2_VERSION_13 = $13,
  70. ARGON2_VERSION_NUMBER = ARGON2_VERSION_13
  71. );
  72. function argon2d_kdf(const t_cost, m_cost, parallelism: cuint32;
  73. const pwd: pansichar; const pwdlen: csize_t;
  74. const salt: pansichar; const saltlen: csize_t;
  75. hash: Pointer; const hashlen: csize_t): cint;
  76. function argon2id_kdf(const t_cost, m_cost, parallelism: cuint32;
  77. const pwd: pansichar; const pwdlen: csize_t;
  78. const salt: pansichar; const saltlen: csize_t;
  79. hash: Pointer; const hashlen: csize_t): cint;
  80. function argon2_kdf(const t_cost, m_cost, parallelism: cuint32;
  81. const pwd: pansichar; const pwdlen: csize_t;
  82. const salt: pansichar; const saltlen: csize_t;
  83. hash: Pointer; const hashlen: csize_t;
  84. type_: Targon2_type): cint;
  85. function argon2_hash(const t_cost, m_cost, parallelism: cuint32;
  86. const pwd: pansichar; const pwdlen: csize_t;
  87. const salt: pansichar; const saltlen: csize_t;
  88. const secret: pansichar; const secretlen: csize_t;
  89. const ad: pansichar; const adlen: csize_t;
  90. hash: Pointer; const hashlen: csize_t;
  91. type_: Targon2_type; version: Targon2_version): cint;
  92. function argon2_selftest: Boolean;
  93. implementation
  94. {$R-}{$Q-}
  95. uses
  96. Math, Hash, SysUtils, StrUtils;
  97. //**********************Argon2 internal constants*******************************/
  98. const
  99. //* Memory block size in bytes */
  100. ARGON2_BLOCK_SIZE = 1024;
  101. ARGON2_QWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE div 8;
  102. (* Number of pseudo-random values generated by one call to Blake in Argon2i
  103. to
  104. generate reference block positions *)
  105. ARGON2_ADDRESSES_IN_BLOCK = 128;
  106. //* Pre-hashing digest length and its extension*/
  107. ARGON2_PREHASH_DIGEST_LENGTH = 64;
  108. ARGON2_PREHASH_SEED_LENGTH = 72;
  109. //*************************Argon2 internal data types***********************/
  110. type
  111. (*
  112. * Structure for the (1KB) memory block implemented as 128 64-bit words.
  113. * Memory blocks can be copied, XORed. Internal words can be accessed by [] (no
  114. * bounds checking).
  115. *)
  116. Pblock = ^Tblock;
  117. Tblock = packed record
  118. v: packed array [0..ARGON2_QWORDS_IN_BLOCK-1] of cuint64;
  119. end;
  120. (*
  121. * Argon2 instance: memory pointer, number of passes, amount of memory, type,
  122. * and derived values.
  123. * Used to evaluate the number and location of blocks to construct in each
  124. * thread
  125. *)
  126. Pargon2_instance_t = ^Targon2_instance_t;
  127. Targon2_instance_t = record
  128. memory: Pblock; //* Memory pointer */
  129. version: Targon2_version;
  130. passes: cuint32; //* Number of passes */
  131. memory_blocks: cuint32; //* Number of blocks in memory */
  132. segment_length: cuint32;
  133. lane_length: cuint32;
  134. lanes: cuint32;
  135. threads: cuint32;
  136. type_: Targon2_type;
  137. print_internals: cint; //* whether to print the memory blocks */
  138. context_ptr: Pargon2_context; //* points back to original context */
  139. end;
  140. (*
  141. * Argon2 position: where we construct the block right now. Used to distribute
  142. * work between threads.
  143. *)
  144. Pargon2_position_t = ^Targon2_position_t;
  145. Targon2_position_t = record
  146. pass: cuint32;
  147. lane: cuint32;
  148. slice: cuint8;
  149. index: cuint32;
  150. instance_ptr: Pargon2_instance_t;
  151. end;
  152. {$IFDEF GENKAT}
  153. procedure initial_kat(const blockhash: pcuint8; const context: Pargon2_context;
  154. type_: Targon2_type);
  155. var
  156. i: cuint32;
  157. begin
  158. if (blockhash <> nil) and (context <> nil) then
  159. begin
  160. WriteLn('=======================================');
  161. WriteLn(Format('%d version number %d', [type_, context^.version]));
  162. WriteLn('=======================================');
  163. WriteLn(Format('Memory: %u KiB, Iterations: %u, Parallelism: %u lanes, Tag length: %u bytes',
  164. [context^.m_cost, context^.t_cost, context^.lanes, context^.outlen]));
  165. Write(Format('Password[%u]: ', [context^.pwdlen]));
  166. if (context^.flags and ARGON2_FLAG_CLEAR_PASSWORD <> 0) then
  167. begin
  168. WriteLn('CLEARED');
  169. end
  170. else begin
  171. for i := 0 to context^.pwdlen - 1 do
  172. Write(Format('%2.2x ', [context^.pwd[i]]));
  173. WriteLn;
  174. end;
  175. Write(Format('Salt[%u]: ', [context^.saltlen]));
  176. for i := 0 to context^.saltlen - 1 do begin
  177. Write(Format('%2.2x ', [context^.salt[i]]));
  178. end;
  179. WriteLn;
  180. (*
  181. printf("Secret[%u]: ", context->secretlen);
  182. if (context->flags & ARGON2_FLAG_CLEAR_SECRET) {
  183. printf("CLEARED\n");
  184. } else {
  185. for (i = 0; i < context->secretlen; ++i) {
  186. printf("%2.2x ", ((unsigned char )context->secret)[i]);
  187. }
  188. printf("\n");
  189. }
  190. printf("Associated data[%u]: ", context->adlen);
  191. for (i = 0; i < context->adlen; ++i) {
  192. printf("%2.2x ", ((unsigned char )context->ad)[i]);
  193. }
  194. printf("\n");
  195. printf("Pre-hashing digest: ");
  196. for (i = 0; i < ARGON2_PREHASH_DIGEST_LENGTH; ++i) {
  197. printf("%2.2x ", ((unsigned char )blockhash)[i]);
  198. }
  199. printf("\n"); *)
  200. end;
  201. end;
  202. procedure print_tag(const out_: pcuint8; outlen: cuint32);
  203. var
  204. i: cuint32;
  205. begin
  206. if (out_ <> nil) then
  207. begin
  208. Write('Tag: ');
  209. for i := 0 to outlen - 1 do begin
  210. Write(Format('%2.2x ', [out_[i]]));
  211. end;
  212. WriteLn;
  213. end;
  214. end;
  215. procedure internal_kat(const instance: Pargon2_instance_t; pass: cuint32);
  216. var
  217. i, j: cuint32;
  218. how_many_words: cuint32;
  219. begin
  220. if (instance <> nil) then
  221. begin
  222. WriteLn(Format('After pass %u:', [pass]));
  223. for i := 0 to instance^.memory_blocks - 1 do
  224. begin
  225. how_many_words :=
  226. IfThen(instance^.memory_blocks > ARGON2_QWORDS_IN_BLOCK,
  227. 1,
  228. ARGON2_QWORDS_IN_BLOCK);
  229. for j := 0 to how_many_words - 1 do
  230. WriteLn(Format('Block %.4u [%3u]: %s', [i, j,
  231. HexStr(instance^.memory[i].v[j], 16)]));
  232. end;
  233. end;
  234. end;
  235. {$ENDIF}
  236. function load32( const src: Pointer ): cuint32; inline;
  237. begin
  238. Result := NtoLE(pcuint32(src)^);
  239. end;
  240. function load64( const src: pointer ): cuint64; inline;
  241. begin
  242. Result := NtoLE(pcuint64(src)^);
  243. end;
  244. procedure store32( dst: pointer; w: cuint32 ); inline;
  245. begin
  246. pcuint32(dst)^ := LEtoN(w);
  247. end;
  248. procedure store64( dst: pointer; w: cuint64 ); inline;
  249. begin
  250. pcuint64(dst)^ := LEtoN(w);
  251. end;
  252. //* designed by the Lyra PHC team */
  253. function fBlaMka(x, y: cuint64): cuint64; inline;
  254. const
  255. m = cuint64($FFFFFFFF);
  256. begin
  257. Result:= x + y + 2 * ((x and m) * (y and m));
  258. end;
  259. procedure G(var a, b, c, d: cuint64); inline;
  260. begin
  261. a := fBlaMka(a, b);
  262. d := RorQWord(d xor a, 32);
  263. c := fBlaMka(c, d);
  264. b := RorQWord(b xor c, 24);
  265. a := fBlaMka(a, b);
  266. d := RorQWord(d xor a, 16);
  267. c := fBlaMka(c, d);
  268. b := RorQWord(b xor c, 63);
  269. end;
  270. procedure BLAKE2_ROUND_NOMSG(var v0, v1, v2, v3, v4, v5, v6, v7,
  271. v8, v9, v10, v11, v12, v13, v14, v15: cuint64); inline;
  272. begin
  273. G(v0, v4, v8, v12);
  274. G(v1, v5, v9, v13);
  275. G(v2, v6, v10, v14);
  276. G(v3, v7, v11, v15);
  277. G(v0, v5, v10, v15);
  278. G(v1, v6, v11, v12);
  279. G(v2, v7, v8, v13);
  280. G(v3, v4, v9, v14);
  281. end;
  282. //***************Instance and Position constructors**********/
  283. procedure init_block_value(b: Pblock; in_: cuint8); inline;
  284. begin
  285. FillChar(b^, SizeOf(Tblock), in_);
  286. end;
  287. procedure copy_block(dst: Pblock; const src: Pblock); inline;
  288. begin
  289. Move(src^, dst^, SizeOf(Tblock));
  290. end;
  291. procedure xor_block(dst: Pblock; const src: Pblock);
  292. var
  293. i: cint;
  294. begin
  295. for i := 0 to ARGON2_QWORDS_IN_BLOCK - 1 do
  296. dst^.v[i] := dst^.v[i] xor src^.v[i];
  297. end;
  298. procedure load_block(dst: Pblock; const input: PByte); inline;
  299. begin
  300. Move(input^, dst^, SizeOf(Tblock));
  301. end;
  302. procedure store_block(output: PByte; const src: Pblock); inline;
  303. begin
  304. Move(src^, output^, SizeOf(Tblock));
  305. end;
  306. //***************Memory functions*****************/
  307. procedure secure_wipe_memory(v: Pointer; n: csize_t);
  308. {$OPTIMIZATION OFF}
  309. begin
  310. FillChar(v^, n, 0);
  311. end;
  312. {$OPTIMIZATION DEFAULT}
  313. procedure clear_internal_memory(v: Pointer; n: csize_t);
  314. begin
  315. if (v <> nil) then secure_wipe_memory(v, n);
  316. end;
  317. function allocate_memory(memory: PPByte; num, size: csize_t): cint;
  318. var
  319. memory_size: csize_t;
  320. begin
  321. memory_size := num * size;
  322. if (memory = nil) then begin
  323. Exit(ARGON2_MEMORY_ALLOCATION_ERROR);
  324. end;
  325. //* Check for multiplication overflow */
  326. if (size <> 0) and (memory_size div size <> num) then begin
  327. Exit(ARGON2_MEMORY_ALLOCATION_ERROR);
  328. end;
  329. memory^ := GetMem(memory_size);
  330. if (memory^ = nil) then begin
  331. Exit(ARGON2_MEMORY_ALLOCATION_ERROR);
  332. end;
  333. Result:= ARGON2_OK;
  334. end;
  335. procedure free_memory(memory: pcuint8; num, size: csize_t);
  336. var
  337. memory_size: csize_t;
  338. begin
  339. memory_size := num * size;
  340. clear_internal_memory(memory, memory_size);
  341. FreeMem(memory);
  342. end;
  343. (*
  344. * Function fills a new memory block and optionally XORs the old block over the new one.
  345. * @next_block must be initialized.
  346. * @param prev_block Pointer to the previous block
  347. * @param ref_block Pointer to the reference block
  348. * @param next_block Pointer to the block to be constructed
  349. * @param with_xor Whether to XOR into the new block (1) or just overwrite (0)
  350. * @pre all block pointers must be valid
  351. *)
  352. procedure fill_block(const prev_block: Pblock; const ref_block: Pblock;
  353. next_block: Pblock; with_xor: boolean);
  354. var
  355. i: cuint32;
  356. blockR, block_tmp: Tblock;
  357. begin
  358. copy_block(@blockR, ref_block);
  359. xor_block(@blockR, prev_block);
  360. copy_block(@block_tmp, @blockR);
  361. //* Now blockR = ref_block + prev_block and block_tmp = ref_block + prev_block */
  362. if (with_xor) then
  363. begin
  364. //* Saving the next block contents for XOR over: */
  365. xor_block(@block_tmp, next_block);
  366. (* Now blockR = ref_block + prev_block and
  367. block_tmp = ref_block + prev_block + next_block *)
  368. end;
  369. (* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then
  370. (16,17,..31)... finally (112,113,...127) *)
  371. for i := 0 to 7 do
  372. begin
  373. BLAKE2_ROUND_NOMSG(
  374. blockR.v[16 * i], blockR.v[16 * i + 1], blockR.v[16 * i + 2],
  375. blockR.v[16 * i + 3], blockR.v[16 * i + 4], blockR.v[16 * i + 5],
  376. blockR.v[16 * i + 6], blockR.v[16 * i + 7], blockR.v[16 * i + 8],
  377. blockR.v[16 * i + 9], blockR.v[16 * i + 10], blockR.v[16 * i + 11],
  378. blockR.v[16 * i + 12], blockR.v[16 * i + 13], blockR.v[16 * i + 14],
  379. blockR.v[16 * i + 15]);
  380. end;
  381. (* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then
  382. (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) *)
  383. for i := 0 to 7 do
  384. begin
  385. BLAKE2_ROUND_NOMSG(
  386. blockR.v[2 * i], blockR.v[2 * i + 1], blockR.v[2 * i + 16],
  387. blockR.v[2 * i + 17], blockR.v[2 * i + 32], blockR.v[2 * i + 33],
  388. blockR.v[2 * i + 48], blockR.v[2 * i + 49], blockR.v[2 * i + 64],
  389. blockR.v[2 * i + 65], blockR.v[2 * i + 80], blockR.v[2 * i + 81],
  390. blockR.v[2 * i + 96], blockR.v[2 * i + 97], blockR.v[2 * i + 112],
  391. blockR.v[2 * i + 113]);
  392. end;
  393. copy_block(next_block, @block_tmp);
  394. xor_block(next_block, @blockR);
  395. end;
  396. function blake2b(out_: pcuint8; outlen: csize_t; const in_: pcuint8; inlen: csize_t): cint;
  397. var
  398. S: blake2b_state;
  399. begin
  400. if (blake2b_init(@S, outlen) = 0) then
  401. begin
  402. blake2b_update(@S, in_, inlen);
  403. blake2b_final(@S, out_, outlen);
  404. Exit(0);
  405. end;
  406. Result:= -1;
  407. end;
  408. procedure blake2b_long(pout: pointer; outlen: csize_t; const in_: pointer; inlen: csize_t);
  409. var
  410. out_: pcuint8;
  411. toproduce: cuint32;
  412. blake_state: blake2b_state;
  413. outlen_bytes: array [0..sizeof(cuint32)-1] of cuint8;
  414. in_buffer: array[0..Pred(BLAKE2B_OUTBYTES)] of cuint8;
  415. out_buffer: array[0..Pred(BLAKE2B_OUTBYTES)] of cuint8;
  416. begin
  417. out_:= pout;
  418. //* Ensure little-endian byte order! */
  419. store32(@outlen_bytes[0], cuint32(outlen));
  420. if (outlen <= BLAKE2B_OUTBYTES) then
  421. begin
  422. blake2b_init(@blake_state, outlen);
  423. blake2b_update(@blake_state, outlen_bytes, sizeof(outlen_bytes));
  424. blake2b_update(@blake_state, in_, inlen);
  425. blake2b_final(@blake_state, out_, outlen);
  426. end
  427. else begin
  428. blake2b_init(@blake_state, BLAKE2B_OUTBYTES);
  429. blake2b_update(@blake_state, outlen_bytes, sizeof(outlen_bytes));
  430. blake2b_update(@blake_state, in_, inlen);
  431. blake2b_final(@blake_state, out_buffer, BLAKE2B_OUTBYTES);
  432. Move(out_buffer[0], out_^, BLAKE2B_OUTBYTES div 2);
  433. out_ += BLAKE2B_OUTBYTES div 2;
  434. toproduce := cuint32(outlen) - BLAKE2B_OUTBYTES div 2;
  435. while (toproduce > BLAKE2B_OUTBYTES) do
  436. begin
  437. Move(out_buffer[0], in_buffer[0], BLAKE2B_OUTBYTES);
  438. blake2b(out_buffer, BLAKE2B_OUTBYTES, in_buffer, BLAKE2B_OUTBYTES);
  439. Move(out_buffer[0], out_^, BLAKE2B_OUTBYTES div 2);
  440. out_ += BLAKE2B_OUTBYTES div 2;
  441. toproduce -= BLAKE2B_OUTBYTES div 2;
  442. end;
  443. Move(out_buffer[0], in_buffer[0], BLAKE2B_OUTBYTES);
  444. blake2b(out_buffer, toproduce, in_buffer, BLAKE2B_OUTBYTES);
  445. Move(out_buffer[0], out_^, toproduce);
  446. end;
  447. clear_internal_memory(@blake_state, sizeof(blake_state));
  448. end;
  449. procedure next_addresses(address_block, input_block: Pblock;
  450. const zero_block: Pblock);
  451. begin
  452. Inc(input_block^.v[6]);
  453. fill_block(zero_block, input_block, address_block, false);
  454. fill_block(zero_block, address_block, address_block, false);
  455. end;
  456. function index_alpha(const instance: Pargon2_instance_t;
  457. const position: Pargon2_position_t; pseudo_rand: cuint32;
  458. same_lane: boolean): cuint32;
  459. var
  460. reference_area_size: cuint32;
  461. relative_position: cuint64;
  462. start_position, absolute_position: cuint32;
  463. begin
  464. (*
  465. * Pass 0:
  466. * This lane : all already finished segments plus already constructed
  467. * blocks in this segment
  468. * Other lanes : all already finished segments
  469. * Pass 1+:
  470. * This lane : (SYNC_POINTS - 1) last segments plus already constructed
  471. * blocks in this segment
  472. * Other lanes : (SYNC_POINTS - 1) last segments
  473. *)
  474. if (0 = position^.pass) then
  475. begin
  476. //* First pass */
  477. if (0 = position^.slice) then
  478. begin
  479. //* First slice */
  480. reference_area_size :=
  481. position^.index - 1; //* all but the previous */
  482. end
  483. else begin
  484. if (same_lane) then
  485. begin
  486. //* The same lane => add current segment */
  487. reference_area_size :=
  488. position^.slice * instance^.segment_length +
  489. position^.index - 1;
  490. end
  491. else begin
  492. reference_area_size :=
  493. position^.slice * instance^.segment_length +
  494. IfThen((position^.index = 0), (-1), 0);
  495. end;
  496. end
  497. end
  498. else begin
  499. //* Second pass */
  500. if (same_lane) then
  501. begin
  502. reference_area_size := instance^.lane_length -
  503. instance^.segment_length + position^.index - 1;
  504. end
  505. else begin
  506. reference_area_size := instance^.lane_length -
  507. instance^.segment_length +
  508. IfThen((position^.index = 0), (-1), 0);
  509. end;
  510. end;
  511. (* 1.2.4. Mapping pseudo_rand to 0..<reference_area_size-1> and produce
  512. * relative position *)
  513. relative_position := pseudo_rand;
  514. relative_position := relative_position * relative_position shr 32;
  515. relative_position := reference_area_size - 1 -
  516. (reference_area_size * relative_position shr 32);
  517. //* 1.2.5 Computing starting position */
  518. start_position := 0;
  519. if (0 <> position^.pass) then
  520. begin
  521. start_position := IfThen(position^.slice = ARGON2_SYNC_POINTS - 1,
  522. 0,
  523. (position^.slice + 1) * instance^.segment_length);
  524. end;
  525. //* 1.2.6. Computing absolute position */
  526. absolute_position := (start_position + relative_position) mod
  527. instance^.lane_length; //* absolute position */
  528. Result:= absolute_position;
  529. end;
  530. function fill_segment(Data: Pointer): PtrInt;
  531. var
  532. ref_block: Pblock = nil;
  533. curr_block: Pblock = nil;
  534. address_block, input_block, zero_block: Tblock;
  535. pseudo_rand, ref_index, ref_lane: cuint64;
  536. prev_offset, curr_offset: cuint32;
  537. starting_index: cuint32;
  538. i: cuint32;
  539. data_independent_addressing: boolean;
  540. position: Targon2_position_t;
  541. instance: Pargon2_instance_t absolute position.instance_ptr;
  542. begin
  543. Result:= 0;
  544. if (Data = nil) then Exit;
  545. position := Pargon2_position_t(Data)^;
  546. data_independent_addressing :=
  547. (instance^.type_ = Argon2_i) or
  548. ((instance^.type_ = Argon2_id) and (position.pass = 0) and
  549. (position.slice < ARGON2_SYNC_POINTS div 2));
  550. if (data_independent_addressing) then
  551. begin
  552. init_block_value(@zero_block, 0);
  553. init_block_value(@input_block, 0);
  554. input_block.v[0] := position.pass;
  555. input_block.v[1] := position.lane;
  556. input_block.v[2] := position.slice;
  557. input_block.v[3] := instance^.memory_blocks;
  558. input_block.v[4] := instance^.passes;
  559. input_block.v[5] := cuint64(instance^.type_);
  560. end;
  561. position.index := 0;
  562. starting_index := 0;
  563. if ((0 = position.pass) and (0 = position.slice)) then
  564. begin
  565. starting_index := 2; //* we have already generated the first two blocks */
  566. //* Don't forget to generate the first block of addresses: */
  567. if (data_independent_addressing) then begin
  568. next_addresses(@address_block, @input_block, @zero_block);
  569. end;
  570. end;
  571. //* Offset of the current block */
  572. curr_offset := position.lane * instance^.lane_length +
  573. position.slice * instance^.segment_length + starting_index;
  574. if (0 = curr_offset mod instance^.lane_length) then
  575. begin
  576. //* Last block in this lane */
  577. prev_offset := curr_offset + instance^.lane_length - 1;
  578. end
  579. else begin
  580. //* Previous block */
  581. prev_offset := curr_offset - 1;
  582. end;
  583. for i := starting_index to instance^.segment_length - 1 do
  584. begin
  585. //*1.1 Rotating prev_offset if needed */
  586. if (curr_offset mod instance^.lane_length = 1) then begin
  587. prev_offset := curr_offset - 1;
  588. end;
  589. //* 1.2 Computing the index of the reference block */
  590. //* 1.2.1 Taking pseudo-random value from the previous block */
  591. if (data_independent_addressing) then
  592. begin
  593. if (i mod ARGON2_ADDRESSES_IN_BLOCK = 0) then begin
  594. next_addresses(@address_block, @input_block, @zero_block);
  595. end;
  596. pseudo_rand := address_block.v[i mod ARGON2_ADDRESSES_IN_BLOCK];
  597. end
  598. else begin
  599. pseudo_rand := instance^.memory[prev_offset].v[0];
  600. end;
  601. //* 1.2.2 Computing the lane of the reference block */
  602. ref_lane := ((pseudo_rand shr 32)) mod instance^.lanes;
  603. if ((position.pass = 0) and (position.slice = 0)) then begin
  604. //* Can not reference other lanes yet */
  605. ref_lane := position.lane;
  606. end;
  607. //* 1.2.3 Computing the number of possible reference block within the lane. */
  608. position.index := i;
  609. ref_index := index_alpha(instance, @position, pseudo_rand and $FFFFFFFF,
  610. ref_lane = position.lane);
  611. //* 2 Creating a new block */
  612. ref_block :=
  613. instance^.memory + instance^.lane_length * ref_lane + ref_index;
  614. curr_block := instance^.memory + curr_offset;
  615. if (ARGON2_VERSION_10 = instance^.version) then begin
  616. //* version 1.2.1 and earlier: overwrite, not XOR */
  617. fill_block(instance^.memory + prev_offset, ref_block, curr_block, false);
  618. end
  619. else begin
  620. if (0 = position.pass) then begin
  621. fill_block(instance^.memory + prev_offset, ref_block,
  622. curr_block, false);
  623. end
  624. else begin
  625. fill_block(instance^.memory + prev_offset, ref_block,
  626. curr_block, true);
  627. end;
  628. end;
  629. Inc(curr_offset);
  630. Inc(prev_offset);
  631. end;
  632. end;
  633. procedure finalize(const context: Pargon2_context; instance: Pargon2_instance_t);
  634. var
  635. l: cuint32;
  636. blockhash: Tblock;
  637. last_block_in_lane: cuint32;
  638. blockhash_bytes: array [0..ARGON2_BLOCK_SIZE-1] of cuint8;
  639. begin
  640. if (context <> nil) and (instance <> nil) then
  641. begin
  642. copy_block(@blockhash, instance^.memory + instance^.lane_length - 1);
  643. //* XOR the last blocks */
  644. for l := 1 to instance^.lanes - 1 do
  645. begin
  646. last_block_in_lane := l * instance^.lane_length + (instance^.lane_length - 1);
  647. xor_block(@blockhash, instance^.memory + last_block_in_lane);
  648. end;
  649. //* Hash the result */
  650. begin
  651. store_block(@blockhash_bytes[0], @blockhash);
  652. blake2b_long(context^.out_, context^.outlen, @blockhash_bytes[0],
  653. ARGON2_BLOCK_SIZE);
  654. //* clear blockhash and blockhash_bytes */
  655. clear_internal_memory(@blockhash.v[0], ARGON2_BLOCK_SIZE);
  656. clear_internal_memory(@blockhash_bytes[0], ARGON2_BLOCK_SIZE);
  657. end;
  658. {$IFDEF GENKAT}
  659. print_tag(context^.out_, context^.outlen);
  660. {$ENDIF}
  661. free_memory(pcuint8(instance^.memory),
  662. instance^.memory_blocks, sizeof(Tblock));
  663. end;
  664. end;
  665. //* Single-threaded version for p=1 case */
  666. function fill_memory_blocks_st(instance: Pargon2_instance_t): cint;
  667. var
  668. r, s, l: cuint32;
  669. position: Targon2_position_t;
  670. begin
  671. position.instance_ptr:= instance;
  672. for r := 0 to instance^.passes - 1 do
  673. begin
  674. position.pass:= r;
  675. for s := 0 to ARGON2_SYNC_POINTS - 1 do
  676. begin
  677. position.slice:= s;
  678. for l:= 0 to instance^.lanes - 1 do
  679. begin
  680. position.lane:= l;
  681. fill_segment(@position);
  682. end;
  683. end;
  684. {$IFDEF GENKAT}
  685. internal_kat(instance, r); //* Print all memory blocks */
  686. {$ENDIF}
  687. end;
  688. Result:= ARGON2_OK;
  689. end;
  690. //* Multi-threaded version for p > 1 case */
  691. function fill_memory_blocks_mt(instance: Pargon2_instance_t): cint;
  692. var
  693. r, s, l, ll: cuint32;
  694. threads: array of TThreadID;
  695. positions: array of Targon2_position_t;
  696. begin
  697. // 1. Allocating space for threads
  698. SetLength(threads, instance^.lanes);
  699. SetLength(positions, instance^.lanes);
  700. for r := 0 to instance^.passes - 1 do
  701. begin
  702. for s := 0 to ARGON2_SYNC_POINTS - 1 do
  703. begin
  704. // 2. Calling threads
  705. for l:= 0 to instance^.lanes - 1 do
  706. begin
  707. positions[l].pass:= r;
  708. positions[l].lane:= l;
  709. positions[l].slice:= s;
  710. positions[l].instance_ptr:= instance;
  711. threads[l]:= BeginThread(@fill_segment, @positions[l]);
  712. if (threads[l] = TThreadID(0)) then
  713. begin
  714. // Wait for already running threads
  715. for ll:= 0 to l - 1 do
  716. begin
  717. WaitForThreadTerminate(threads[ll], -1);
  718. CloseThread(threads[ll]);
  719. end;
  720. Exit(ARGON2_THREAD_FAIL);
  721. end;
  722. end;
  723. // 3. Joining remaining threads
  724. for l := instance^.lanes - instance^.threads to instance^.lanes - 1 do
  725. begin
  726. WaitForThreadTerminate(threads[l], -1);
  727. CloseThread(threads[l]);
  728. end;
  729. end;
  730. {$IFDEF GENKAT}
  731. internal_kat(instance, r); //* Print all memory blocks */
  732. {$ENDIF}
  733. end;
  734. Result:= ARGON2_OK;
  735. end;
  736. function fill_memory_blocks(instance: Pargon2_instance_t): cint;
  737. begin
  738. if (instance = nil) or (instance^.lanes = 0) then begin
  739. Exit(ARGON2_INCORRECT_PARAMETER);
  740. end;
  741. if (instance^.threads > 1) then
  742. Result:= fill_memory_blocks_mt(instance)
  743. else begin
  744. Result:= fill_memory_blocks_st(instance);
  745. end;
  746. end;
  747. procedure fill_first_blocks(blockhash: pcuint8; const instance: pargon2_instance_t);
  748. var
  749. l: cuint32;
  750. blockhash_bytes: array[0..ARGON2_BLOCK_SIZE-1] of cuint8;
  751. begin
  752. //* Make the first and second block in each lane as G(H0||0||i) or G(H0||1||i) */
  753. for l := 0 to instance^.lanes - 1 do
  754. begin
  755. store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 0);
  756. store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH + 4, l);
  757. blake2b_long(@blockhash_bytes[0], ARGON2_BLOCK_SIZE, blockhash,
  758. ARGON2_PREHASH_SEED_LENGTH);
  759. load_block(@instance^.memory[l * instance^.lane_length + 0],
  760. blockhash_bytes);
  761. store32(blockhash + ARGON2_PREHASH_DIGEST_LENGTH, 1);
  762. blake2b_long(@blockhash_bytes[0], ARGON2_BLOCK_SIZE, blockhash,
  763. ARGON2_PREHASH_SEED_LENGTH);
  764. load_block(@instance^.memory[l * instance^.lane_length + 1],
  765. blockhash_bytes);
  766. end;
  767. clear_internal_memory(@blockhash_bytes[0], ARGON2_BLOCK_SIZE);
  768. end;
  769. procedure initial_hash(blockhash: pcuint8; context: Pargon2_context;
  770. type_: Targon2_type);
  771. var
  772. BlakeHash: blake2b_state;
  773. value: array[0..sizeof(cuint32)-1] of cuint8;
  774. begin
  775. if (nil = context) or (nil = blockhash) then Exit;
  776. blake2b_init(@BlakeHash, ARGON2_PREHASH_DIGEST_LENGTH);
  777. store32(@value[0], context^.lanes);
  778. blake2b_update(@BlakeHash, @value[0], sizeof(value));
  779. store32(@value[0], context^.outlen);
  780. blake2b_update(@BlakeHash, @value[0], sizeof(value));
  781. store32(@value[0], context^.m_cost);
  782. blake2b_update(@BlakeHash, @value[0], sizeof(value));
  783. store32(@value[0], context^.t_cost);
  784. blake2b_update(@BlakeHash, @value[0], sizeof(value));
  785. store32(@value[0], context^.version);
  786. blake2b_update(@BlakeHash, @value[0], sizeof(value));
  787. store32(@value[0], cuint32(type_));
  788. blake2b_update(@BlakeHash, @value[0], sizeof(value));
  789. store32(@value[0], context^.pwdlen);
  790. blake2b_update(@BlakeHash, @value[0], sizeof(value));
  791. if (context^.pwd <> nil) then
  792. begin
  793. blake2b_update(@BlakeHash, context^.pwd,
  794. context^.pwdlen);
  795. if (context^.flags and ARGON2_FLAG_CLEAR_PASSWORD <> 0) then
  796. begin
  797. secure_wipe_memory(context^.pwd, context^.pwdlen);
  798. context^.pwdlen := 0;
  799. end;
  800. end;
  801. store32(@value[0], context^.saltlen);
  802. blake2b_update(@BlakeHash, @value[0], sizeof(value));
  803. if (context^.salt <> nil) then
  804. begin
  805. blake2b_update(@BlakeHash, context^.salt,
  806. context^.saltlen);
  807. end;
  808. store32(@value[0], context^.secretlen);
  809. blake2b_update(@BlakeHash, @value[0], sizeof(value));
  810. if (context^.secret <> nil) then
  811. begin
  812. blake2b_update(@BlakeHash, context^.secret,
  813. context^.secretlen);
  814. if (context^.flags and ARGON2_FLAG_CLEAR_SECRET <> 0) then
  815. begin
  816. secure_wipe_memory(context^.secret, context^.secretlen);
  817. context^.secretlen := 0;
  818. end;
  819. end;
  820. store32(@value[0], context^.adlen);
  821. blake2b_update(@BlakeHash, @value[0], sizeof(value));
  822. if (context^.ad <> nil) then
  823. begin
  824. blake2b_update(@BlakeHash, context^.ad,
  825. context^.adlen);
  826. end;
  827. blake2b_final(@BlakeHash, blockhash, ARGON2_PREHASH_DIGEST_LENGTH);
  828. end;
  829. function initialize(instance: Pargon2_instance_t; context: Pargon2_context): cint;
  830. var
  831. blockhash: array[0..ARGON2_PREHASH_SEED_LENGTH-1] of cuint8;
  832. begin
  833. instance^.context_ptr := context;
  834. //* 1. Memory allocation */
  835. result := allocate_memory(@(instance^.memory),
  836. instance^.memory_blocks, sizeof(Tblock));
  837. if (result <> ARGON2_OK) then Exit;
  838. (* 2. Initial hashing */
  839. /* H_0 + 8 extra bytes to produce the first blocks */
  840. /* uint8_t blockhash[ARGON2_PREHASH_SEED_LENGTH]; */
  841. /* Hashing all inputs *)
  842. initial_hash(blockhash, context, instance^.type_);
  843. //* Zeroing 8 extra bytes */
  844. clear_internal_memory(@blockhash[ARGON2_PREHASH_DIGEST_LENGTH],
  845. ARGON2_PREHASH_SEED_LENGTH -
  846. ARGON2_PREHASH_DIGEST_LENGTH);
  847. {$IFDEF GENKAT}
  848. initial_kat(blockhash, context, instance^.type_);
  849. {$ENDIF}
  850. //* 3. Creating first blocks, we always have at least two blocks in a slice */
  851. fill_first_blocks(blockhash, instance);
  852. //* Clearing the hash */
  853. clear_internal_memory(@blockhash[0], ARGON2_PREHASH_SEED_LENGTH);
  854. Result:= ARGON2_OK;
  855. end;
  856. function argon2_ctx(context: Pargon2_context; type_: Targon2_type): cint;
  857. var
  858. memory_blocks, segment_length: cuint32;
  859. instance: Targon2_instance_t;
  860. begin
  861. (*
  862. //* 1. Validate all inputs */
  863. int result = validate_inputs(context);
  864. if (ARGON2_OK != result) {
  865. return result;
  866. }
  867. if (Argon2_d != type && Argon2_i != type && Argon2_id != type) {
  868. return ARGON2_INCORRECT_TYPE;
  869. }
  870. *)
  871. //* 2. Align memory size */
  872. //* Minimum memory_blocks = 8L blocks, where L is the number of lanes */
  873. memory_blocks := context^.m_cost;
  874. if (memory_blocks < 2 * ARGON2_SYNC_POINTS * context^.lanes) then begin
  875. memory_blocks := 2 * ARGON2_SYNC_POINTS * context^.lanes;
  876. end;
  877. segment_length := memory_blocks div (context^.lanes * ARGON2_SYNC_POINTS);
  878. //* Ensure that all segments have equal length */
  879. memory_blocks := segment_length * (context^.lanes * ARGON2_SYNC_POINTS);
  880. instance.version := Targon2_version(context^.version);
  881. instance.memory := nil;
  882. instance.passes := context^.t_cost;
  883. instance.memory_blocks := memory_blocks;
  884. instance.segment_length := segment_length;
  885. instance.lane_length := segment_length * ARGON2_SYNC_POINTS;
  886. instance.lanes := context^.lanes;
  887. instance.threads := context^.threads;
  888. instance.type_ := type_;
  889. if (instance.threads > instance.lanes) then begin
  890. instance.threads := instance.lanes;
  891. end;
  892. //* 3. Initialization: Hashing inputs, allocating memory, filling first blocks */
  893. result := initialize(@instance, context);
  894. if (ARGON2_OK <> result) then Exit;
  895. //* 4. Filling memory */
  896. result := fill_memory_blocks(@instance);
  897. if (ARGON2_OK <> result) then Exit;
  898. //* 5. Finalization */
  899. finalize(context, @instance);
  900. Result:= ARGON2_OK;
  901. end;
  902. function argon2_hash(const t_cost, m_cost, parallelism: cuint32;
  903. const pwd: pansichar; const pwdlen: csize_t;
  904. const salt: pansichar; const saltlen: csize_t;
  905. const secret: pansichar; const secretlen: csize_t;
  906. const ad: pansichar; const adlen: csize_t;
  907. hash: Pointer; const hashlen: csize_t;
  908. type_: Targon2_type; version: Targon2_version): cint;
  909. var
  910. context: Targon2_context;
  911. begin
  912. (*
  913. if (pwdlen > ARGON2_MAX_PWD_LENGTH) {
  914. return ARGON2_PWD_TOO_LONG;
  915. }
  916. if (saltlen > ARGON2_MAX_SALT_LENGTH) {
  917. return ARGON2_SALT_TOO_LONG;
  918. }
  919. if (hashlen > ARGON2_MAX_OUTLEN) {
  920. return ARGON2_OUTPUT_TOO_LONG;
  921. }
  922. if (hashlen < ARGON2_MIN_OUTLEN) {
  923. return ARGON2_OUTPUT_TOO_SHORT;
  924. }
  925. *)
  926. context.out_ := GetMem(hashlen);
  927. if (context.out_ = nil) then begin
  928. Exit(ARGON2_MEMORY_ALLOCATION_ERROR);
  929. end;
  930. context.outlen := cuint32(hashlen);
  931. context.pwd := pcuint8(pwd);
  932. context.pwdlen := cuint32(pwdlen);
  933. context.salt := pcuint8(salt);
  934. context.saltlen := cuint32(saltlen);
  935. context.secret := pcuint8(secret);
  936. context.secretlen := secretlen;
  937. context.ad := pcuint8(ad);
  938. context.adlen := adlen;
  939. context.t_cost := t_cost;
  940. context.m_cost := m_cost;
  941. context.lanes := parallelism;
  942. context.threads := parallelism;
  943. context.flags := ARGON2_DEFAULT_FLAGS;
  944. context.version := cuint32(version);
  945. result := argon2_ctx(@context, type_);
  946. //* if raw hash requested, write it */
  947. if (result = ARGON2_OK) and (hash <> nil) then
  948. begin
  949. Move(context.out_^, hash^, hashlen);
  950. end;
  951. clear_internal_memory(context.out_, hashlen);
  952. FreeMem(context.out_);
  953. end;
  954. function argon2d_kdf(const t_cost, m_cost, parallelism: cuint32;
  955. const pwd: pansichar; const pwdlen: csize_t;
  956. const salt: pansichar; const saltlen: csize_t;
  957. hash: Pointer; const hashlen: csize_t): cint; inline;
  958. begin
  959. Result:= argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, nil, 0,
  960. nil, 0, hash, hashlen, Argon2_d, ARGON2_VERSION_NUMBER);
  961. end;
  962. function argon2id_kdf(const t_cost, m_cost, parallelism: cuint32;
  963. const pwd: pansichar; const pwdlen: csize_t;
  964. const salt: pansichar; const saltlen: csize_t;
  965. hash: Pointer; const hashlen: csize_t): cint; inline;
  966. begin
  967. Result:= argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, nil, 0,
  968. nil, 0, hash, hashlen, Argon2_id, ARGON2_VERSION_NUMBER);
  969. end;
  970. function argon2_kdf(const t_cost, m_cost, parallelism: cuint32;
  971. const pwd: pansichar; const pwdlen: csize_t;
  972. const salt: pansichar; const saltlen: csize_t;
  973. hash: Pointer; const hashlen: csize_t;
  974. type_: Targon2_type): cint; inline;
  975. begin
  976. Result:= argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, nil, 0,
  977. nil, 0, hash, hashlen, type_, ARGON2_VERSION_NUMBER);
  978. end;
  979. function argon2_selftest: Boolean;
  980. function hash_test(version: Targon2_version; type_: Targon2_type; t, m, p: cuint32; pwd, salt, hex: String): Boolean;
  981. const
  982. AName: array[Targon2_type] of String = ('Argon2d', 'Argon2i', 'Argon2id');
  983. var
  984. Q: QWord;
  985. ret: Integer;
  986. out_: String;
  987. out_hex: String;
  988. out_len: Integer;
  989. begin
  990. WriteLn(AName[type_]);
  991. out_len:= Length(hex) div 2;
  992. WriteLn(Format('Hash test: $v=%d t=%d, m=%d, p=%d, pass=%s, salt=%s, result=%d',
  993. [version, t, m, p, pwd, salt, out_len]));
  994. SetLength(out_, out_len);
  995. Q:= GetTickCount64;
  996. ret:= argon2_hash(t, 1 shl m, p, Pointer(pwd), Length(pwd), Pointer(salt), Length(salt),
  997. nil, 0, nil, 0, Pointer(out_), OUT_LEN, type_, version);
  998. if (ret <> ARGON2_OK) then
  999. begin
  1000. WriteLn('Error: ', ret);
  1001. Exit(False);
  1002. end;
  1003. WriteLn('Time: ', GetTickCount64 - Q);
  1004. SetLength(out_hex, OUT_LEN * 2);
  1005. BinToHex(PAnsiChar(out_), PAnsiChar(out_hex), OUT_LEN);
  1006. Result:= SameText(hex, out_hex);
  1007. WriteLn('Must: ', hex);
  1008. WriteLn('Have: ', out_hex);
  1009. WriteLn('Result: ', Result);
  1010. WriteLn('------------------------------------------------------------');
  1011. end;
  1012. begin
  1013. Result:= True;
  1014. // Test Argon2i
  1015. Result:= Result and hash_test(ARGON2_VERSION_NUMBER, Argon2_i, 2, 16, 1, 'password', 'somesalt',
  1016. 'c1628832147d9720c5bd1cfd61367078729f6dfb6f8fea9ff98158e0d7816ed0');
  1017. Result:= Result and hash_test(ARGON2_VERSION_NUMBER, Argon2_i, 2, 16, 1, 'password', 'diffsalt',
  1018. 'b0357cccfbef91f3860b0dba447b2348cbefecadaf990abfe9cc40726c521271');
  1019. Result:= Result and hash_test(ARGON2_VERSION_NUMBER, Argon2_i, 2, 16, 2,
  1020. 'The quick brown fox jumps over the lazy dog',
  1021. '09316115d5cf24ed5a15a31a3ba326e5cf32edc24702987c02b6566f61913cf7',
  1022. '81f1ba863be362444e3a22feca1d65e4d0ff53609ef9db5961d715552d38ac0d');
  1023. // Test Argon2d
  1024. Result:= Result and hash_test(ARGON2_VERSION_NUMBER, Argon2_d, 2, 16, 1, 'password', 'somesalt',
  1025. '955e5d5b163a1b60bba35fc36d0496474fba4f6b59ad53628666f07fb2f93eaf');
  1026. Result:= Result and hash_test(ARGON2_VERSION_NUMBER, Argon2_d, 4, 17, 4,
  1027. 'The quick brown fox jumps over the lazy dog',
  1028. '49d91010f3cadfca4964a1305132537e28a195cf7b0823763fa34d190f9b2559',
  1029. '595193668d0ae6169235017f58d2a197d9cc485af5cb8f26357d95ee7eb991c4');
  1030. Result:= Result and hash_test(ARGON2_VERSION_NUMBER, Argon2_d, 10, 16, 4,
  1031. 'The quick brown fox jumps over the lazy dog',
  1032. '49d91010f3cadfca4964a1305132537e28a195cf7b0823763fa34d190f9b2559',
  1033. '49101d42bd15dc1559bfd978753ac957c239b2f6184b8de2042e03fdd4b6676c');
  1034. Result:= Result and hash_test(ARGON2_VERSION_NUMBER, Argon2_d, 6, 17, 4,
  1035. 'The quick brown fox jumps over the lazy dog',
  1036. '49d91010f3cadfca4964a1305132537e28a195cf7b0823763fa34d190f9b2559',
  1037. '13ea5db0e564b8719f7f3fc55559b8ca224dd063256f53051dd5bb682b48b5ac');
  1038. // Test Argon2id
  1039. Result:= Result and hash_test(ARGON2_VERSION_NUMBER, Argon2_id, 2, 16, 1, 'password', 'somesalt',
  1040. '09316115d5cf24ed5a15a31a3ba326e5cf32edc24702987c02b6566f61913cf7');
  1041. Result:= Result and hash_test(ARGON2_VERSION_NUMBER, Argon2_id, 2, 16, 1, 'password', 'diffsalt',
  1042. 'bdf32b05ccc42eb15d58fd19b1f856b113da1e9a5874fdcc544308565aa8141c');
  1043. Result:= Result and hash_test(ARGON2_VERSION_NUMBER, Argon2_id, 2, 16, 2, 'password', 'somesalt',
  1044. '6f681ac1c3384a90119d2763a683f9ac79532d999abfab5644aa8aafd3d0d234');
  1045. // Print result
  1046. WriteLn('Result: ', Result);
  1047. end;
  1048. end.