@@ -26,6 +26,7 @@ cfg_if::cfg_if! {
26
26
if #[ cfg( all( ossl320, not( osslconf = "OPENSSL_NO_ARGON2" ) ) ) ] {
27
27
use std:: cmp;
28
28
use std:: ffi:: c_void;
29
+ use std:: ffi:: CStr ;
29
30
use std:: mem:: MaybeUninit ;
30
31
use std:: ptr;
31
32
use foreign_types:: ForeignTypeRef ;
@@ -34,15 +35,60 @@ cfg_if::cfg_if! {
34
35
use crate :: lib_ctx:: LibCtxRef ;
35
36
use crate :: error:: ErrorStack ;
36
37
37
- /// Derives a key using the argon2id algorithm.
38
+ #[ allow( clippy:: too_many_arguments) ]
39
+ pub fn argon2d(
40
+ ctx: Option <& LibCtxRef >,
41
+ pass: & [ u8 ] ,
42
+ salt: & [ u8 ] ,
43
+ ad: Option <& [ u8 ] >,
44
+ secret: Option <& [ u8 ] >,
45
+ iter: u32 ,
46
+ lanes: u32 ,
47
+ memcost: u32 ,
48
+ out: & mut [ u8 ] ,
49
+ ) -> Result <( ) , ErrorStack > {
50
+ return argon2_helper( CStr :: from_bytes_with_nul( b"ARGON2D\0 " ) . unwrap( ) , ctx, pass, salt, ad, secret, iter, lanes, memcost, out) ;
51
+ }
52
+
53
+ #[ allow( clippy:: too_many_arguments) ]
54
+ pub fn argon2i(
55
+ ctx: Option <& LibCtxRef >,
56
+ pass: & [ u8 ] ,
57
+ salt: & [ u8 ] ,
58
+ ad: Option <& [ u8 ] >,
59
+ secret: Option <& [ u8 ] >,
60
+ iter: u32 ,
61
+ lanes: u32 ,
62
+ memcost: u32 ,
63
+ out: & mut [ u8 ] ,
64
+ ) -> Result <( ) , ErrorStack > {
65
+ return argon2_helper( CStr :: from_bytes_with_nul( b"ARGON2I\0 " ) . unwrap( ) , ctx, pass, salt, ad, secret, iter, lanes, memcost, out) ;
66
+ }
67
+
68
+ #[ allow( clippy:: too_many_arguments) ]
69
+ pub fn argon2id(
70
+ ctx: Option <& LibCtxRef >,
71
+ pass: & [ u8 ] ,
72
+ salt: & [ u8 ] ,
73
+ ad: Option <& [ u8 ] >,
74
+ secret: Option <& [ u8 ] >,
75
+ iter: u32 ,
76
+ lanes: u32 ,
77
+ memcost: u32 ,
78
+ out: & mut [ u8 ] ,
79
+ ) -> Result <( ) , ErrorStack > {
80
+ return argon2_helper( CStr :: from_bytes_with_nul( b"ARGON2ID\0 " ) . unwrap( ) , ctx, pass, salt, ad, secret, iter, lanes, memcost, out) ;
81
+ }
82
+
83
+ /// Derives a key using the argon2* algorithms.
38
84
///
39
85
/// To use multiple cores to process the lanes in parallel you must
40
86
/// set a global max thread count using `OSSL_set_max_threads`. On
41
87
/// builds with no threads all lanes will be processed sequentially.
42
88
///
43
89
/// Requires OpenSSL 3.2.0 or newer.
44
- # [ allow ( clippy :: too_many_arguments ) ]
45
- pub fn argon2id (
90
+ fn argon2_helper (
91
+ kdf_identifier : & CStr ,
46
92
ctx: Option <& LibCtxRef >,
47
93
pass: & [ u8 ] ,
48
94
salt: & [ u8 ] ,
@@ -61,7 +107,7 @@ cfg_if::cfg_if! {
61
107
let mut threads = 1 ;
62
108
// If max_threads is 0, then this isn't a threaded build.
63
109
// If max_threads is > u32::MAX we need to clamp since
64
- // argon2id 's threads parameter is a u32.
110
+ // argon2 's threads parameter is a u32.
65
111
if max_threads > 0 {
66
112
threads = cmp:: min( lanes, cmp:: min( max_threads, u32 :: MAX as u64 ) as u32 ) ;
67
113
}
@@ -116,7 +162,7 @@ cfg_if::cfg_if! {
116
162
117
163
let argon2 = EvpKdf ( cvt_p( ffi:: EVP_KDF_fetch (
118
164
libctx,
119
- b"ARGON2ID \0 " . as_ptr( ) as * const c_char,
165
+ kdf_identifier . as_ptr( ) as * const c_char,
120
166
ptr:: null( ) ,
121
167
) ) ?) ;
122
168
let ctx = EvpKdfCtx ( cvt_p( ffi:: EVP_KDF_CTX_new ( argon2. 0 ) ) ?) ;
@@ -161,6 +207,60 @@ mod tests {
161
207
assert_eq ! ( hex:: encode( & actual[ ..] ) , expected) ;
162
208
}
163
209
210
+ #[ test]
211
+ #[ cfg( all( ossl320, not( osslconf = "OPENSSL_NO_ARGON2" ) ) ) ]
212
+ fn argon2d ( ) {
213
+ // RFC 9106 test vector for argon2d
214
+ let pass = hex:: decode ( "0101010101010101010101010101010101010101010101010101010101010101" )
215
+ . unwrap ( ) ;
216
+ let salt = hex:: decode ( "02020202020202020202020202020202" ) . unwrap ( ) ;
217
+ let secret = hex:: decode ( "0303030303030303" ) . unwrap ( ) ;
218
+ let ad = hex:: decode ( "040404040404040404040404" ) . unwrap ( ) ;
219
+ let expected = "512b391b6f1162975371d30919734294f868e3be3984f3c1a13a4db9fabe4acb" ;
220
+
221
+ let mut actual = [ 0u8 ; 32 ] ;
222
+ super :: argon2d (
223
+ None ,
224
+ & pass,
225
+ & salt,
226
+ Some ( & ad) ,
227
+ Some ( & secret) ,
228
+ 3 ,
229
+ 4 ,
230
+ 32 ,
231
+ & mut actual,
232
+ )
233
+ . unwrap ( ) ;
234
+ assert_eq ! ( hex:: encode( & actual[ ..] ) , expected) ;
235
+ }
236
+
237
+ #[ test]
238
+ #[ cfg( all( ossl320, not( osslconf = "OPENSSL_NO_ARGON2" ) ) ) ]
239
+ fn argon2i ( ) {
240
+ // RFC 9106 test vector for argon2i
241
+ let pass = hex:: decode ( "0101010101010101010101010101010101010101010101010101010101010101" )
242
+ . unwrap ( ) ;
243
+ let salt = hex:: decode ( "02020202020202020202020202020202" ) . unwrap ( ) ;
244
+ let secret = hex:: decode ( "0303030303030303" ) . unwrap ( ) ;
245
+ let ad = hex:: decode ( "040404040404040404040404" ) . unwrap ( ) ;
246
+ let expected = "c814d9d1dc7f37aa13f0d77f2494bda1c8de6b016dd388d29952a4c4672b6ce8" ;
247
+
248
+ let mut actual = [ 0u8 ; 32 ] ;
249
+ super :: argon2i (
250
+ None ,
251
+ & pass,
252
+ & salt,
253
+ Some ( & ad) ,
254
+ Some ( & secret) ,
255
+ 3 ,
256
+ 4 ,
257
+ 32 ,
258
+ & mut actual,
259
+ )
260
+ . unwrap ( ) ;
261
+ assert_eq ! ( hex:: encode( & actual[ ..] ) , expected) ;
262
+ }
263
+
164
264
#[ test]
165
265
#[ cfg( all( ossl320, not( osslconf = "OPENSSL_NO_ARGON2" ) ) ) ]
166
266
fn argon2id_no_ad_secret ( ) {
0 commit comments