Commit 5ff8594e authored by Paul Kehrer's avatar Paul Kehrer
Browse files

rename to kdf, remove thread arg

parent 826f2a0a
Loading
Loading
Loading
Loading

openssl/src/argon2.rs

deleted100644 → 0
+0 −165
Original line number Diff line number Diff line
use std::ffi::{c_char, c_void};
use std::mem::MaybeUninit;
use std::ptr;

use crate::error::ErrorStack;
use crate::{cvt, cvt_p};

struct EvpKdf(*mut ffi::EVP_KDF);

impl Drop for EvpKdf {
    fn drop(&mut self) {
        unsafe {
            ffi::EVP_KDF_free(self.0);
        }
    }
}

struct EvpKdfCtx(*mut ffi::EVP_KDF_CTX);

impl Drop for EvpKdfCtx {
    fn drop(&mut self) {
        unsafe {
            ffi::EVP_KDF_CTX_free(self.0);
        }
    }
}

/// Derives a key using the argon2id algorithm.
///
/// Requires OpenSSL 3.2.0 or newer.
#[allow(clippy::too_many_arguments)]
pub fn argon2id(
    pass: &[u8],
    salt: &[u8],
    ad: Option<&[u8]>,
    secret: Option<&[u8]>,
    mut iter: u32,
    mut threads: u32,
    mut lanes: u32,
    mut memcost: u32,
    out: &mut [u8],
) -> Result<(), ErrorStack> {
    // We only support single-threaded operation for now since rust-openssl doesn't
    // bind OSSL_set_max_threads
    assert!(threads == 1);
    unsafe {
        ffi::init();
        let mut params: [ffi::OSSL_PARAM; 10] =
            core::array::from_fn(|_| MaybeUninit::<ffi::OSSL_PARAM>::zeroed().assume_init());
        let mut idx = 0;
        params[idx] = ffi::OSSL_PARAM_construct_octet_string(
            b"pass\0".as_ptr() as *const c_char,
            pass.as_ptr() as *mut c_void,
            pass.len(),
        );
        idx += 1;
        params[idx] = ffi::OSSL_PARAM_construct_octet_string(
            b"salt\0".as_ptr() as *const c_char,
            salt.as_ptr() as *mut c_void,
            salt.len(),
        );
        idx += 1;
        params[idx] =
            ffi::OSSL_PARAM_construct_uint(b"threads\0".as_ptr() as *const c_char, &mut threads);
        idx += 1;
        params[idx] =
            ffi::OSSL_PARAM_construct_uint(b"lanes\0".as_ptr() as *const c_char, &mut lanes);
        idx += 1;
        params[idx] =
            ffi::OSSL_PARAM_construct_uint(b"memcost\0".as_ptr() as *const c_char, &mut memcost);
        idx += 1;
        params[idx] =
            ffi::OSSL_PARAM_construct_uint(b"iter\0".as_ptr() as *const c_char, &mut iter);
        idx += 1;
        let mut size = out.len() as u32;
        params[idx] =
            ffi::OSSL_PARAM_construct_uint(b"size\0".as_ptr() as *const c_char, &mut size);
        idx += 1;
        if let Some(ad) = ad {
            params[idx] = ffi::OSSL_PARAM_construct_octet_string(
                b"ad\0".as_ptr() as *const c_char,
                ad.as_ptr() as *mut c_void,
                ad.len(),
            );
            idx += 1;
        }
        if let Some(secret) = secret {
            params[idx] = ffi::OSSL_PARAM_construct_octet_string(
                b"secret\0".as_ptr() as *const c_char,
                secret.as_ptr() as *mut c_void,
                secret.len(),
            );
            idx += 1;
        }
        params[idx] = ffi::OSSL_PARAM_construct_end();

        let argon2_p = cvt_p(ffi::EVP_KDF_fetch(
            ptr::null_mut(),
            b"ARGON2ID\0".as_ptr() as *const c_char,
            ptr::null(),
        ))?;
        let argon2 = EvpKdf(argon2_p);
        let ctx_p = cvt_p(ffi::EVP_KDF_CTX_new(argon2.0))?;
        let ctx = EvpKdfCtx(ctx_p);
        cvt(ffi::EVP_KDF_derive(
            ctx.0,
            out.as_mut_ptr(),
            out.len(),
            params.as_ptr(),
        ))
        .map(|_| ())
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn argon2id() {
        // RFC 9106 test vector for argon2id
        let pass = hex::decode("0101010101010101010101010101010101010101010101010101010101010101")
            .unwrap();
        let salt = hex::decode("02020202020202020202020202020202").unwrap();
        let secret = hex::decode("0303030303030303").unwrap();
        let ad = hex::decode("040404040404040404040404").unwrap();
        let expected = "0d640df58d78766c08c037a34a8b53c9d01ef0452d75b65eb52520e96b01e659";

        let mut actual = [0 as u8; 32];
        super::argon2id(
            &pass,
            &salt,
            Some(&ad),
            Some(&secret),
            3,
            1,
            4,
            32,
            &mut actual,
        )
        .unwrap();
        assert_eq!(hex::encode(&actual[..]), expected);
    }

    #[test]
    fn argon2id_no_ad_secret() {
        // Test vector from OpenSSL
        let pass = "";
        let salt = hex::decode("02020202020202020202020202020202").unwrap();
        let expected = "0a34f1abde67086c82e785eaf17c68382259a264f4e61b91cd2763cb75ac189a";

        let mut actual = [0 as u8; 32];
        super::argon2id(
            &pass.as_bytes(),
            &salt,
            None,
            None,
            3,
            1,
            4,
            32,
            &mut actual,
        )
        .unwrap();
        assert_eq!(hex::encode(&actual[..]), expected);
    }
}

openssl/src/kdf.rs

0 → 100644
+162 −0
Original line number Diff line number Diff line
#[cfg(ossl300)]
struct EvpKdf(*mut ffi::EVP_KDF);

#[cfg(ossl300)]
impl Drop for EvpKdf {
    fn drop(&mut self) {
        unsafe {
            ffi::EVP_KDF_free(self.0);
        }
    }
}

#[cfg(ossl300)]
struct EvpKdfCtx(*mut ffi::EVP_KDF_CTX);

#[cfg(ossl300)]
impl Drop for EvpKdfCtx {
    fn drop(&mut self) {
        unsafe {
            ffi::EVP_KDF_CTX_free(self.0);
        }
    }
}

cfg_if::cfg_if! {
    if #[cfg(all(ossl320, not(osslconf = "OPENSSL_NO_ARGON2")))] {
        use std::ffi::{c_char, c_void};
        use std::mem::MaybeUninit;
        use std::ptr;
        use crate::{cvt, cvt_p};
        use crate::error::ErrorStack;

        /// Derives a key using the argon2id algorithm.
        ///
        /// This function currently does not support multi-threaded operation, so
        /// lanes greater than 1 will be processed sequentially.
        ///
        /// Requires OpenSSL 3.2.0 or newer.
        #[allow(clippy::too_many_arguments)]
        pub fn argon2id(
            pass: &[u8],
            salt: &[u8],
            ad: Option<&[u8]>,
            secret: Option<&[u8]>,
            mut iter: u32,
            mut lanes: u32,
            mut memcost: u32,
            out: &mut [u8],
        ) -> Result<(), ErrorStack> {
            unsafe {
                ffi::init();
                let mut threads = 1;
                let mut params: [ffi::OSSL_PARAM; 10] =
                    core::array::from_fn(|_| MaybeUninit::<ffi::OSSL_PARAM>::zeroed().assume_init());
                let mut idx = 0;
                params[idx] = ffi::OSSL_PARAM_construct_octet_string(
                    b"pass\0".as_ptr() as *const c_char,
                    pass.as_ptr() as *mut c_void,
                    pass.len(),
                );
                idx += 1;
                params[idx] = ffi::OSSL_PARAM_construct_octet_string(
                    b"salt\0".as_ptr() as *const c_char,
                    salt.as_ptr() as *mut c_void,
                    salt.len(),
                );
                idx += 1;
                params[idx] =
                    ffi::OSSL_PARAM_construct_uint(b"threads\0".as_ptr() as *const c_char, &mut threads);
                idx += 1;
                params[idx] =
                    ffi::OSSL_PARAM_construct_uint(b"lanes\0".as_ptr() as *const c_char, &mut lanes);
                idx += 1;
                params[idx] =
                    ffi::OSSL_PARAM_construct_uint(b"memcost\0".as_ptr() as *const c_char, &mut memcost);
                idx += 1;
                params[idx] =
                    ffi::OSSL_PARAM_construct_uint(b"iter\0".as_ptr() as *const c_char, &mut iter);
                idx += 1;
                let mut size = out.len() as u32;
                params[idx] =
                    ffi::OSSL_PARAM_construct_uint(b"size\0".as_ptr() as *const c_char, &mut size);
                idx += 1;
                if let Some(ad) = ad {
                    params[idx] = ffi::OSSL_PARAM_construct_octet_string(
                        b"ad\0".as_ptr() as *const c_char,
                        ad.as_ptr() as *mut c_void,
                        ad.len(),
                    );
                    idx += 1;
                }
                if let Some(secret) = secret {
                    params[idx] = ffi::OSSL_PARAM_construct_octet_string(
                        b"secret\0".as_ptr() as *const c_char,
                        secret.as_ptr() as *mut c_void,
                        secret.len(),
                    );
                    idx += 1;
                }
                params[idx] = ffi::OSSL_PARAM_construct_end();

                let argon2_p = cvt_p(ffi::EVP_KDF_fetch(
                    ptr::null_mut(),
                    b"ARGON2ID\0".as_ptr() as *const c_char,
                    ptr::null(),
                ))?;
                let argon2 = EvpKdf(argon2_p);
                let ctx_p = cvt_p(ffi::EVP_KDF_CTX_new(argon2.0))?;
                let ctx = EvpKdfCtx(ctx_p);
                cvt(ffi::EVP_KDF_derive(
                    ctx.0,
                    out.as_mut_ptr(),
                    out.len(),
                    params.as_ptr(),
                ))
                .map(|_| ())
            }
        }
    }
}

#[cfg(test)]
mod tests {
    #[test]
    #[cfg(all(ossl320, not(osslconf = "OPENSSL_NO_ARGON2")))]
    fn argon2id() {
        // RFC 9106 test vector for argon2id
        let pass = hex::decode("0101010101010101010101010101010101010101010101010101010101010101")
            .unwrap();
        let salt = hex::decode("02020202020202020202020202020202").unwrap();
        let secret = hex::decode("0303030303030303").unwrap();
        let ad = hex::decode("040404040404040404040404").unwrap();
        let expected = "0d640df58d78766c08c037a34a8b53c9d01ef0452d75b65eb52520e96b01e659";

        let mut actual = [0 as u8; 32];
        super::argon2id(
            &pass,
            &salt,
            Some(&ad),
            Some(&secret),
            3,
            4,
            32,
            &mut actual,
        )
        .unwrap();
        assert_eq!(hex::encode(&actual[..]), expected);
    }

    #[test]
    #[cfg(all(ossl320, not(osslconf = "OPENSSL_NO_ARGON2")))]
    fn argon2id_no_ad_secret() {
        // Test vector from OpenSSL
        let pass = "";
        let salt = hex::decode("02020202020202020202020202020202").unwrap();
        let expected = "0a34f1abde67086c82e785eaf17c68382259a264f4e61b91cd2763cb75ac189a";

        let mut actual = [0 as u8; 32];
        super::argon2id(&pass.as_bytes(), &salt, None, None, 3, 4, 32, &mut actual).unwrap();
        assert_eq!(hex::encode(&actual[..]), expected);
    }
}
+1 −2
Original line number Diff line number Diff line
@@ -148,8 +148,6 @@ mod bio;
mod util;
pub mod aes;
#[cfg(ossl320)]
#[cfg(all(ossl320, not(osslconf = "OPENSSL_NO_ARGON2")))]
pub mod argon2;
pub mod asn1;
pub mod base64;
pub mod bn;
@@ -171,6 +169,7 @@ pub mod ex_data;
#[cfg(not(any(libressl, ossl300)))]
pub mod fips;
pub mod hash;
pub mod kdf;
#[cfg(ossl300)]
pub mod lib_ctx;
pub mod md;