Skip to content

Commit 2bcf319

Browse files
authored
Merge pull request #2416 from greateggsgreg/additional_argon2_variants
Add support for argon2d and argon2i variants
2 parents 43d030c + 44ae878 commit 2bcf319

File tree

1 file changed

+105
-5
lines changed

1 file changed

+105
-5
lines changed

openssl/src/kdf.rs

Lines changed: 105 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ cfg_if::cfg_if! {
2626
if #[cfg(all(ossl320, not(osslconf = "OPENSSL_NO_ARGON2")))] {
2727
use std::cmp;
2828
use std::ffi::c_void;
29+
use std::ffi::CStr;
2930
use std::mem::MaybeUninit;
3031
use std::ptr;
3132
use foreign_types::ForeignTypeRef;
@@ -34,15 +35,60 @@ cfg_if::cfg_if! {
3435
use crate::lib_ctx::LibCtxRef;
3536
use crate::error::ErrorStack;
3637

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.
3884
///
3985
/// To use multiple cores to process the lanes in parallel you must
4086
/// set a global max thread count using `OSSL_set_max_threads`. On
4187
/// builds with no threads all lanes will be processed sequentially.
4288
///
4389
/// 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,
4692
ctx: Option<&LibCtxRef>,
4793
pass: &[u8],
4894
salt: &[u8],
@@ -61,7 +107,7 @@ cfg_if::cfg_if! {
61107
let mut threads = 1;
62108
// If max_threads is 0, then this isn't a threaded build.
63109
// 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.
65111
if max_threads > 0 {
66112
threads = cmp::min(lanes, cmp::min(max_threads, u32::MAX as u64) as u32);
67113
}
@@ -116,7 +162,7 @@ cfg_if::cfg_if! {
116162

117163
let argon2 = EvpKdf(cvt_p(ffi::EVP_KDF_fetch(
118164
libctx,
119-
b"ARGON2ID\0".as_ptr() as *const c_char,
165+
kdf_identifier.as_ptr() as *const c_char,
120166
ptr::null(),
121167
))?);
122168
let ctx = EvpKdfCtx(cvt_p(ffi::EVP_KDF_CTX_new(argon2.0))?);
@@ -161,6 +207,60 @@ mod tests {
161207
assert_eq!(hex::encode(&actual[..]), expected);
162208
}
163209

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+
164264
#[test]
165265
#[cfg(all(ossl320, not(osslconf = "OPENSSL_NO_ARGON2")))]
166266
fn argon2id_no_ad_secret() {

0 commit comments

Comments
 (0)