@@ -137,11 +137,13 @@ test(SUITE, 'argon2Sync: deterministic with same inputs', () => {
137137 ) ;
138138} ) ;
139139
140- // --- Numeric parameter validation (Phase 1.1: validateUInt) ---
140+ // --- Numeric parameter validation (Phase 1.1: validateUInt + Phase 3.2 RFC 9106 ) ---
141141//
142142// `static_cast<uint32_t>(NaN | +/-Infinity | -1)` is undefined behavior in
143- // C++. The C++ layer used to do these casts naked; the validateUInt helper
144- // now rejects them with a descriptive error before the cast.
143+ // C++. The C++ layer's validateUInt helper used to be the first line of
144+ // defense; Phase 3.2 added a TS-side RFC 9106 §3.1 check that fires
145+ // earlier and produces a clearer message. The regex below matches the
146+ // new RFC 9106 wording.
145147
146148const baseParams = {
147149 message : Buffer . from ( 'password' ) ,
@@ -173,20 +175,20 @@ test(SUITE, 'argon2Sync: rejects -Infinity passes', () => {
173175test ( SUITE , 'argon2Sync: rejects negative tagLength' , ( ) => {
174176 assert . throws ( ( ) => {
175177 argon2Sync ( 'argon2id' , { ...baseParams , tagLength : - 1 } ) ;
176- } , / t a g L e n g t h . * n o n - n e g a t i v e / i ) ;
178+ } , / I n v a l i d A r g o n 2 t a g L e n g t h : - 1 / ) ;
177179} ) ;
178180
179181test ( SUITE , 'argon2Sync: rejects fractional passes' , ( ) => {
180182 assert . throws ( ( ) => {
181183 argon2Sync ( 'argon2id' , { ...baseParams , passes : 3.5 } ) ;
182- } , / p a s s e s . * i n t e g e r / i ) ;
184+ } , / I n v a l i d A r g o n 2 p a s s e s : 3 \. 5 / ) ;
183185} ) ;
184186
185187test ( SUITE , 'argon2Sync: rejects out-of-range memory' , ( ) => {
186188 // memory is uint32_t — anything beyond UINT32_MAX must be rejected.
187189 assert . throws ( ( ) => {
188190 argon2Sync ( 'argon2id' , { ...baseParams , memory : 2 ** 32 } ) ;
189- } , / m e m o r y . * o u t o f r a n g e / i ) ;
191+ } , / I n v a l i d A r g o n 2 m e m o r y : 4 2 9 4 9 6 7 2 9 6 / ) ;
190192} ) ;
191193
192194test ( SUITE , 'argon2: async path also rejects NaN parallelism' , ( ) => {
@@ -202,3 +204,49 @@ test(SUITE, 'argon2: async path also rejects NaN parallelism', () => {
202204 } ) ;
203205 } ) ;
204206} ) ;
207+
208+ // --- RFC 9106 §3.1 minimum-bound validation (Phase 3.2) ---
209+
210+ test ( SUITE , 'argon2Sync: rejects parallelism = 0 (RFC 9106 mins)' , ( ) => {
211+ assert . throws ( ( ) => {
212+ argon2Sync ( 'argon2id' , { ...baseParams , parallelism : 0 } ) ;
213+ } , / p a r a l l e l i s m : 0 / ) ;
214+ } ) ;
215+
216+ test ( SUITE , 'argon2Sync: rejects tagLength < 4 (RFC 9106 mins)' , ( ) => {
217+ assert . throws ( ( ) => {
218+ argon2Sync ( 'argon2id' , { ...baseParams , tagLength : 3 } ) ;
219+ } , / t a g L e n g t h : 3 / ) ;
220+ } ) ;
221+
222+ test ( SUITE , 'argon2Sync: rejects passes = 0 (RFC 9106 mins)' , ( ) => {
223+ assert . throws ( ( ) => {
224+ argon2Sync ( 'argon2id' , { ...baseParams , passes : 0 } ) ;
225+ } , / p a s s e s : 0 / ) ;
226+ } ) ;
227+
228+ test ( SUITE , 'argon2Sync: rejects memory < 8 * parallelism (RFC 9106)' , ( ) => {
229+ // p=4 ⇒ memory must be ≥ 32 KiB; 16 KiB must be rejected.
230+ assert . throws ( ( ) => {
231+ argon2Sync ( 'argon2id' , {
232+ ...baseParams ,
233+ parallelism : 4 ,
234+ memory : 16 ,
235+ } ) ;
236+ } , / m e m o r y : 1 6 / ) ;
237+ } ) ;
238+
239+ test ( SUITE , 'argon2Sync: rejects nonce shorter than 8 bytes (RFC 9106)' , ( ) => {
240+ assert . throws ( ( ) => {
241+ argon2Sync ( 'argon2id' , {
242+ ...baseParams ,
243+ nonce : Buffer . from ( '1234567' ) , // 7 bytes
244+ } ) ;
245+ } , / n o n c e l e n g t h : 7 / ) ;
246+ } ) ;
247+
248+ test ( SUITE , 'argon2Sync: rejects unsupported version' , ( ) => {
249+ assert . throws ( ( ) => {
250+ argon2Sync ( 'argon2id' , { ...baseParams , version : 0x42 } ) ;
251+ } , / I n v a l i d A r g o n 2 v e r s i o n / ) ;
252+ } ) ;
0 commit comments