2222unit Argon2;
2323
2424{ $mode objfpc}{ $H+}
25- { $define USE_MTPROCS}
2625{ .$define GENKAT}
2726
2827interface
@@ -44,6 +43,7 @@ interface
4443 ARGON2_OK = 0 ;
4544 ARGON2_MEMORY_ALLOCATION_ERROR = -22 ;
4645 ARGON2_INCORRECT_PARAMETER = -25 ;
46+ ARGON2_THREAD_FAIL = -33 ;
4747
4848
4949type
@@ -76,8 +76,8 @@ Targon2_context = record
7676
7777 // * Argon2 primitive type */
7878 Targon2_type = (
79- Argon2_d = 0 ,
80- Argon2_i = 1 ,
79+ Argon2_i = 0 ,
80+ Argon2_d = 1 ,
8181 Argon2_id = 2
8282 );
8383
@@ -88,11 +88,22 @@ Targon2_context = record
8888 ARGON2_VERSION_NUMBER = ARGON2_VERSION_13
8989 );
9090
91+ function argon2d_kdf (const t_cost, m_cost, parallelism: cuint32;
92+ const pwd: pansichar; const pwdlen: csize_t;
93+ const salt: pansichar; const saltlen: csize_t;
94+ hash: Pointer; const hashlen: csize_t): cint;
95+
9196function argon2id_kdf (const t_cost, m_cost, parallelism: cuint32;
9297 const pwd: pansichar; const pwdlen: csize_t;
9398 const salt: pansichar; const saltlen: csize_t;
9499 hash: Pointer; const hashlen: csize_t): cint;
95100
101+ function argon2_kdf (const t_cost, m_cost, parallelism: cuint32;
102+ const pwd: pansichar; const pwdlen: csize_t;
103+ const salt: pansichar; const saltlen: csize_t;
104+ hash: Pointer; const hashlen: csize_t;
105+ type_: Targon2_type): cint;
106+
96107function argon2_hash (const t_cost, m_cost, parallelism: cuint32;
97108 const pwd: pansichar; const pwdlen: csize_t;
98109 const salt: pansichar; const saltlen: csize_t;
@@ -108,11 +119,7 @@ implementation
108119{ $R-}{ $Q-}
109120
110121uses
111- Math, Hash, SysUtils, StrUtils
112- { $IF DEFINED(USE_MTPROCS)}
113- , MTProcs
114- { $ENDIF}
115- ;
122+ Math, Hash, SysUtils, StrUtils;
116123
117124// **********************Argon2 internal constants*******************************/
118125
@@ -170,6 +177,7 @@ Targon2_instance_t = record
170177 Pargon2_position_t = ^Targon2_position_t;
171178 Targon2_position_t = record
172179 pass: cuint32;
180+ lane: cuint32;
173181 slice: cuint8;
174182 index: cuint32;
175183 instance_ptr: Pargon2_instance_t;
@@ -613,7 +621,7 @@ function index_alpha(const instance: Pargon2_instance_t;
613621 Result:= absolute_position;
614622end ;
615623
616- procedure fill_segment (position_lane: PtrInt; Data: Pointer; { %H- } Item: TObject) ;
624+ function fill_segment (Data: Pointer): PtrInt ;
617625var
618626 ref_block: Pblock = nil ;
619627 curr_block: Pblock = nil ;
@@ -626,6 +634,7 @@ procedure fill_segment(position_lane: PtrInt; Data: Pointer; {%H-}Item: TObject)
626634 position: Targon2_position_t;
627635 instance: Pargon2_instance_t absolute position.instance_ptr;
628636begin
637+ Result:= 0 ;
629638 if (Data = nil ) then Exit;
630639
631640 position := Pargon2_position_t(Data)^;
@@ -641,7 +650,7 @@ procedure fill_segment(position_lane: PtrInt; Data: Pointer; {%H-}Item: TObject)
641650 init_block_value(@input_block, 0 );
642651
643652 input_block.v[0 ] := position.pass;
644- input_block.v[1 ] := position_lane ;
653+ input_block.v[1 ] := position.lane ;
645654 input_block.v[2 ] := position.slice;
646655 input_block.v[3 ] := instance^.memory_blocks;
647656 input_block.v[4 ] := instance^.passes;
@@ -662,7 +671,7 @@ procedure fill_segment(position_lane: PtrInt; Data: Pointer; {%H-}Item: TObject)
662671 end ;
663672
664673 // * Offset of the current block */
665- curr_offset := position_lane * instance^.lane_length +
674+ curr_offset := position.lane * instance^.lane_length +
666675 position.slice * instance^.segment_length + starting_index;
667676
668677 if (0 = curr_offset mod instance^.lane_length) then
@@ -701,13 +710,13 @@ procedure fill_segment(position_lane: PtrInt; Data: Pointer; {%H-}Item: TObject)
701710
702711 if ((position.pass = 0 ) and (position.slice = 0 )) then begin
703712 // * Can not reference other lanes yet */
704- ref_lane := position_lane ;
713+ ref_lane := position.lane ;
705714 end ;
706715
707716 // * 1.2.3 Computing the number of possible reference block within the lane. */
708717 position.index := i;
709718 ref_index := index_alpha(instance, @position, pseudo_rand and $FFFFFFFF,
710- ref_lane = position_lane );
719+ ref_lane = position.lane );
711720
712721 // * 2 Creating a new block */
713722 ref_block :=
@@ -770,35 +779,91 @@ procedure finalize(const context: Pargon2_context; instance: Pargon2_instance_t)
770779 end ;
771780end ;
772781
773- function fill_memory_blocks (instance: Pargon2_instance_t): cint;
782+ // * Single-threaded version for p=1 case */
783+ function fill_memory_blocks_st (instance: Pargon2_instance_t): cint;
774784var
775785 r, s, l: cuint32;
776786 position: Targon2_position_t;
777787begin
778- if (instance = nil ) or (instance^.lanes = 0 ) then begin
779- Exit(ARGON2_INCORRECT_PARAMETER);
780- end ;
781788 position.instance_ptr:= instance;
782789 for r := 0 to instance^.passes - 1 do
783790 begin
784791 position.pass:= r;
785792 for s := 0 to ARGON2_SYNC_POINTS - 1 do
786793 begin
787794 position.slice:= s;
788- { $IF DEFINED(USE_MTPROCS)}
789- if instance^.lanes > 1 then
790- ProcThreadPool.DoParallel(TMTProcedure(@fill_segment), 0 , instance^.lanes - 1 , @position)
791- else
795+ for l:= 0 to instance^.lanes - 1 do
796+ begin
797+ position.lane:= l;
798+ fill_segment(@position);
799+ end ;
800+ end ;
801+ { $IFDEF GENKAT}
802+ internal_kat(instance, r); // * Print all memory blocks */
792803{ $ENDIF}
793- for l := 0 to instance^.lanes - 1 do fill_segment(l, @position, nil );
804+ end ;
805+ Result:= ARGON2_OK;
806+ end ;
807+
808+ // * Multi-threaded version for p > 1 case */
809+ function fill_memory_blocks_mt (instance: Pargon2_instance_t): cint;
810+ var
811+ r, s, l, ll: cuint32;
812+ threads: array of TThreadID;
813+ positions: array of Targon2_position_t;
814+ begin
815+ // 1. Allocating space for threads
816+ SetLength(threads, instance^.lanes);
817+ SetLength(positions, instance^.lanes);
818+ for r := 0 to instance^.passes - 1 do
819+ begin
820+ for s := 0 to ARGON2_SYNC_POINTS - 1 do
821+ begin
822+ // 2. Calling threads
823+ for l:= 0 to instance^.lanes - 1 do
824+ begin
825+ positions[l].pass:= r;
826+ positions[l].lane:= l;
827+ positions[l].slice:= s;
828+ positions[l].instance_ptr:= instance;
829+ threads[l]:= BeginThread(@fill_segment, @positions[l]);
830+ if (threads[l] = TThreadID(0 )) then
831+ begin
832+ // Wait for already running threads
833+ for ll:= 0 to l - 1 do
834+ begin
835+ WaitForThreadTerminate(threads[ll], -1 );
836+ CloseThread(threads[ll]);
837+ end ;
838+ Exit(ARGON2_THREAD_FAIL);
839+ end ;
840+ end ;
841+ // 3. Joining remaining threads
842+ for l := instance^.lanes - instance^.threads to instance^.lanes - 1 do
843+ begin
844+ WaitForThreadTerminate(threads[l], -1 );
845+ CloseThread(threads[l]);
846+ end ;
794847 end ;
795848{ $IFDEF GENKAT}
796- internal_kat(instance, r); // / * Print all memory blocks */
849+ internal_kat(instance, r); // * Print all memory blocks */
797850{ $ENDIF}
798851 end ;
799852 Result:= ARGON2_OK;
800853end ;
801854
855+ function fill_memory_blocks (instance: Pargon2_instance_t): cint;
856+ begin
857+ if (instance = nil ) or (instance^.lanes = 0 ) then begin
858+ Exit(ARGON2_INCORRECT_PARAMETER);
859+ end ;
860+ if (instance^.threads > 1 ) then
861+ Result:= fill_memory_blocks_mt(instance)
862+ else begin
863+ Result:= fill_memory_blocks_st(instance);
864+ end ;
865+ end ;
866+
802867procedure fill_first_blocks (blockhash: pcuint8; const instance: pargon2_instance_t);
803868var
804869 l: cuint32;
@@ -1056,47 +1121,67 @@ function argon2_hash(const t_cost, m_cost, parallelism: cuint32;
10561121 FreeMem(context.out_);
10571122end ;
10581123
1124+ function argon2d_kdf (const t_cost, m_cost, parallelism: cuint32;
1125+ const pwd: pansichar; const pwdlen: csize_t;
1126+ const salt: pansichar; const saltlen: csize_t;
1127+ hash: Pointer; const hashlen: csize_t): cint; inline;
1128+ begin
1129+ Result:= argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, nil , 0 ,
1130+ nil , 0 , hash, hashlen, Argon2_d, ARGON2_VERSION_NUMBER);
1131+ end ;
1132+
10591133function argon2id_kdf (const t_cost, m_cost, parallelism: cuint32;
10601134 const pwd: pansichar; const pwdlen: csize_t;
10611135 const salt: pansichar; const saltlen: csize_t;
1062- hash: Pointer; const hashlen: csize_t): cint;
1136+ hash: Pointer; const hashlen: csize_t): cint; inline;
10631137begin
10641138 Result:= argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, nil , 0 ,
10651139 nil , 0 , hash, hashlen, Argon2_id, ARGON2_VERSION_NUMBER);
10661140end ;
10671141
1142+ function argon2_kdf (const t_cost, m_cost, parallelism: cuint32;
1143+ const pwd: pansichar; const pwdlen: csize_t;
1144+ const salt: pansichar; const saltlen: csize_t;
1145+ hash: Pointer; const hashlen: csize_t;
1146+ type_: Targon2_type): cint; inline;
1147+ begin
1148+ Result:= argon2_hash(t_cost, m_cost, parallelism, pwd, pwdlen, salt, saltlen, nil , 0 ,
1149+ nil , 0 , hash, hashlen, type_, ARGON2_VERSION_NUMBER);
1150+ end ;
1151+
10681152function argon2_selftest : Boolean;
10691153
10701154 function hash_test (version: Targon2_version; type_: Targon2_type; t, m, p: cuint32; pwd, salt, hex: String): Boolean;
1155+ const
1156+ AName: array [Targon2_type] of String = (' Argon2i' , ' Argon2d' , ' Argon2id' );
10711157 var
10721158 Q: QWord;
10731159 out_: String;
10741160 out_hex: String;
10751161 out_len: Integer;
10761162 begin
1077- out_len:= Length(hex) div 2 ;
1078- WriteLn(Format(' Hash test: $v=%d t=%d, m=%d, p=%d, pass=%s, salt=%s, result=%d' ,
1079- [version, t, m, p, pwd, salt, out_len]));
1080-
1081- SetLength(out_, out_len);
1082- Q:= GetTickCount64;
1083- argon2_hash(t, 1 shl m, p, Pointer(pwd), Length(pwd), Pointer(salt), Length(salt),
1084- nil , 0 , nil , 0 , Pointer(out_), OUT_LEN, type_, version);
1085- WriteLn(' Time: ' , GetTickCount64 - Q);
1086- SetLength(out_hex, OUT_LEN * 2 );
1087- BinToHex(PAnsiChar(out_), PAnsiChar(out_hex), OUT_LEN);
1088- Result:= SameText(hex, out_hex);
1089- WriteLn(' Must: ' , hex);
1090- WriteLn(' Have: ' , out_hex);
1091- WriteLn(' Result: ' , Result);
1092- WriteLn(' ------------------------------------------------------------' );
1163+ WriteLn(AName[type_]);
1164+ out_len:= Length(hex) div 2 ;
1165+ WriteLn(Format(' Hash test: $v=%d t=%d, m=%d, p=%d, pass=%s, salt=%s, result=%d' ,
1166+ [version, t, m, p, pwd, salt, out_len]));
1167+
1168+ SetLength(out_, out_len);
1169+ Q:= GetTickCount64;
1170+ argon2_hash(t, 1 shl m, p, Pointer(pwd), Length(pwd), Pointer(salt), Length(salt),
1171+ nil , 0 , nil , 0 , Pointer(out_), OUT_LEN, type_, version);
1172+ WriteLn(' Time: ' , GetTickCount64 - Q);
1173+ SetLength(out_hex, OUT_LEN * 2 );
1174+ BinToHex(PAnsiChar(out_), PAnsiChar(out_hex), OUT_LEN);
1175+ Result:= SameText(hex, out_hex);
1176+ WriteLn(' Must: ' , hex);
1177+ WriteLn(' Have: ' , out_hex);
1178+ WriteLn(' Result: ' , Result);
1179+ WriteLn(' ------------------------------------------------------------' );
10931180 end ;
10941181
10951182begin
10961183 Result:= True;
10971184 // Test Argon2i
1098- Result:= Result and hash_test(ARGON2_VERSION_10, Argon2_i, 2 , 16 , 1 , ' password' , ' somesalt' ,
1099- ' f6c4db4a54e2a370627aff3db6176b94a2a209a62c8e36152711802f7b30c694' );
11001185 Result:= Result and hash_test(ARGON2_VERSION_NUMBER, Argon2_i, 2 , 16 , 1 , ' password' , ' somesalt' ,
11011186 ' c1628832147d9720c5bd1cfd61367078729f6dfb6f8fea9ff98158e0d7816ed0' );
11021187 Result:= Result and hash_test(ARGON2_VERSION_NUMBER, Argon2_i, 2 , 16 , 1 , ' differentpassword' , ' somesalt' ,
@@ -1106,6 +1191,20 @@ function argon2_selftest: Boolean;
11061191 // Test Argon2d
11071192 Result:= Result and hash_test(ARGON2_VERSION_NUMBER, Argon2_d, 2 , 16 , 1 , ' password' , ' somesalt' ,
11081193 ' 955e5d5b163a1b60bba35fc36d0496474fba4f6b59ad53628666f07fb2f93eaf' );
1194+ Result:= Result and hash_test(ARGON2_VERSION_NUMBER, Argon2_d, 4 , 17 , 4 ,
1195+ ' The quick brown fox jumps over the lazy dog' ,
1196+ ' 49d91010f3cadfca4964a1305132537e28a195cf7b0823763fa34d190f9b2559' ,
1197+ ' 595193668d0ae6169235017f58d2a197d9cc485af5cb8f26357d95ee7eb991c4' );
1198+
1199+ Result:= Result and hash_test(ARGON2_VERSION_NUMBER, Argon2_d, 10 , 16 , 4 ,
1200+ ' The quick brown fox jumps over the lazy dog' ,
1201+ ' 49d91010f3cadfca4964a1305132537e28a195cf7b0823763fa34d190f9b2559' ,
1202+ ' 49101d42bd15dc1559bfd978753ac957c239b2f6184b8de2042e03fdd4b6676c' );
1203+
1204+ Result:= Result and hash_test(ARGON2_VERSION_NUMBER, Argon2_d, 6 , 17 , 4 ,
1205+ ' The quick brown fox jumps over the lazy dog' ,
1206+ ' 49d91010f3cadfca4964a1305132537e28a195cf7b0823763fa34d190f9b2559' ,
1207+ ' 13ea5db0e564b8719f7f3fc55559b8ca224dd063256f53051dd5bb682b48b5ac' );
11091208 // Test Argon2id
11101209 Result:= Result and hash_test(ARGON2_VERSION_NUMBER, Argon2_id, 2 , 16 , 1 , ' password' , ' somesalt' ,
11111210 ' 09316115d5cf24ed5a15a31a3ba326e5cf32edc24702987c02b6566f61913cf7' );
0 commit comments