From a2d649204d91dcd0a67a63f30f092ebc843552c6 Mon Sep 17 00:00:00 2001 From: lonerapier Date: Fri, 12 Dec 2025 17:54:19 +0530 Subject: [PATCH] add prelude --- mfkdf2/README.md | 65 ++++------ mfkdf2/src/definitions/factor.rs | 10 +- mfkdf2/src/derive/factors/password.rs | 13 +- mfkdf2/src/lib.rs | 1 + mfkdf2/src/prelude.rs | 35 +++++ mfkdf2/src/setup/factors/password.rs | 12 +- mfkdf2/tests/common/mod.rs | 176 ++++++++++---------------- mfkdf2/tests/entropy.rs | 116 ++++++----------- mfkdf2/tests/integration.rs | 100 +++++++-------- mfkdf2/tests/integrity.rs | 37 ++---- mfkdf2/tests/security.rs | 17 +-- mfkdf2/tests/stack.rs | 107 ++++++---------- 12 files changed, 279 insertions(+), 410 deletions(-) create mode 100644 mfkdf2/src/prelude.rs diff --git a/mfkdf2/README.md b/mfkdf2/README.md index e422c65a..7340a24d 100644 --- a/mfkdf2/README.md +++ b/mfkdf2/README.md @@ -59,21 +59,19 @@ over time. It consists of two algorithms: Initializes the factor with a secret and produces a public state with initial key material. ```rust -# use mfkdf2::setup::factors::{password, password::PasswordOptions}; -# use mfkdf2::setup::factors::{totp, totp::TOTPOptions}; -# use mfkdf2::error::MFKDF2Error; +use mfkdf2::prelude::*; # let TOTP_SECRET = vec![0u8; 20]; # // setup a password factor with id "pwd" -let password_factor = password("password", PasswordOptions { id: Some("pwd".to_string()) })?; +let password_factor = setup_password("password", PasswordOptions { id: Some("pwd".to_string()) })?; // setup a TOTP factor with id "totp" -let totp_factor = totp(TOTPOptions { +let totp_factor = setup_totp(TOTPOptions { id: Some("totp".to_string()), secret: Some(TOTP_SECRET), ..Default::default() })?; -# Ok::<(), mfkdf2::error::MFKDF2Error>(()) +# MFKDF2Result::Ok(()) ``` ## Derive @@ -83,13 +81,14 @@ Takes the factor's witness and produces key material from the factor and the upd ```rust # use mfkdf2::derive::factors::{password, totp}; # use mfkdf2::error::MFKDF2Error; +# use mfkdf2::error::MFKDF2Result; # // derive the password factor let password_factor = password("password")?; // derive the TOTP factor with code `123456` let totp_factor = totp(123456, None)?; -# Ok::<(), mfkdf2::error::MFKDF2Error>(()) +# MFKDF2Result::Ok(()) ``` # KDF construction @@ -104,25 +103,20 @@ how a key is derived and ensures the key is the same every time (as long as the correct). ```rust -# use mfkdf2::setup::factors::{password, password::PasswordOptions}; -# use mfkdf2::setup::factors::{hmacsha1, hmacsha1::HmacSha1Options}; -# use mfkdf2::setup::factors::{hotp, hotp::HOTPOptions}; -# use mfkdf2::setup; -# use mfkdf2::definitions::MFKDF2Options; -# use mfkdf2::error::MFKDF2Error; +use mfkdf2::prelude::*; # let HOTP_SECRET = vec![0u8; 20]; # // perform setup key let setup_derived_key = setup::key( &[ - password("password123", PasswordOptions::default()).expect("Failed to setup password factor"), - hmacsha1(HmacSha1Options::default())?, - hotp(HOTPOptions { secret: Some(HOTP_SECRET), ..Default::default() })?, + setup_password("password123", PasswordOptions::default()).expect("Failed to setup password factor"), + setup_hmacsha1(HmacSha1Options::default())?, + setup_hotp(HOTPOptions { secret: Some(HOTP_SECRET), ..Default::default() })?, // add more factors here ], MFKDF2Options::default(), )?; -# Ok::<(), mfkdf2::error::MFKDF2Error>(()) +# MFKDF2Result::Ok(()) ``` ## Derive Key @@ -149,17 +143,7 @@ Derive a composite key with password, hmacsha1 and hotp factors. Derive returns ```rust # use std::collections::HashMap; -# use mfkdf2::setup::factors::{password as setup_password, password::PasswordOptions}; -# use mfkdf2::setup::factors::{hmacsha1 as setup_hmacsha1, hmacsha1::HmacSha1Options}; -# use mfkdf2::setup::factors::{hotp as setup_hotp, hotp::HOTPOptions}; -# use mfkdf2::setup; -# use mfkdf2::derive::factors::password as derive_password; -# use mfkdf2::derive::factors::hmacsha1 as derive_hmacsha1; -# use mfkdf2::derive::factors::hotp as derive_hotp; -# use mfkdf2::otpauth::generate_otp_token; -# use mfkdf2::derive; -# use mfkdf2::definitions::MFKDF2Options; -# use mfkdf2::error::MFKDF2Error; +use mfkdf2::prelude::*; # use hmac::{Mac, Hmac}; # use sha1::Sha1; # let HOTP_SECRET = vec![0u8; 20]; @@ -188,7 +172,7 @@ let derive_password_factor = derive_password("password123")?; # .iter() # .find(|f| f.id == "hmacsha1").unwrap(); # let challenge = match &policy_hmac_factor.params { -# mfkdf2::definitions::factor::FactorParams::HmacSha1(p) => hex::decode(&p.challenge).unwrap(), +# FactorParams::HmacSha1(p) => hex::decode(&p.challenge).unwrap(), # _ => unreachable!(), # }; # let response: [u8; 20] = as Mac>::new_from_slice(&HMACSHA1_SECRET) @@ -205,7 +189,7 @@ let derive_hmac_factor = derive_hmacsha1(response)?; # .iter() # .find(|f| f.id == "hotp").unwrap(); # let (counter, digits, hash) = match &policy_hotp_factor.params { -# mfkdf2::definitions::factor::FactorParams::HOTP(p) => (p.counter, p.digits, p.hash.clone()), +# FactorParams::HOTP(p) => (p.counter, p.digits, p.hash.clone()), # _ => unreachable!(), # }; # let correct_code = generate_otp_token(&HOTP_SECRET, counter, &hash, digits); @@ -224,20 +208,19 @@ let derived_key = derive::key( // derived_key.key -> 34d2…5771 # assert_eq!(derived_key.key, setup_derived_key.key); -# Ok::<(), mfkdf2::error::MFKDF2Error>(()) +# MFKDF2Result::Ok(()) ``` ### Password + TOTP ```rust # use std::collections::HashMap; -use mfkdf2::setup::factors::{totp::TOTPOptions, password::PasswordOptions}; -use mfkdf2::definitions::MFKDF2Options; +use mfkdf2::prelude::*; -let setup = mfkdf2::setup::key( +let setup = setup::key( &[ - mfkdf2::setup::factors::password("password1", PasswordOptions::default())?, - mfkdf2::setup::factors::totp(TOTPOptions { + setup_password("password1", PasswordOptions::default())?, + setup_totp(TOTPOptions { secret: Some(b"abcdefghijklmnopqrst".to_vec()), time: Some(1), ..Default::default() @@ -246,15 +229,15 @@ let setup = mfkdf2::setup::key( MFKDF2Options::default(), )?; -let derived_key = mfkdf2::derive::key( +let derived_key = derive::key( &setup.policy, HashMap::from([ - ("password".to_string(), mfkdf2::derive::factors::password("password1")?), + ("password".to_string(), derive_password("password1")?), ( "totp".to_string(), - mfkdf2::derive::factors::totp( + derive_totp( 241063, - Some(mfkdf2::derive::factors::totp::TOTPDeriveOptions { + Some(TOTPDeriveOptions { time: Some(30001), ..Default::default() }), @@ -268,7 +251,7 @@ let derived_key = mfkdf2::derive::key( println!("Derived Key: {:?}", derived_key); # assert_eq!(setup.key, derived_key.key); -# Ok::<(), mfkdf2::error::MFKDF2Error>(()) +# MFKDF2Result::Ok(()) ``` # Threshold Recovery diff --git a/mfkdf2/src/definitions/factor.rs b/mfkdf2/src/definitions/factor.rs index b03c7a52..04240fd0 100644 --- a/mfkdf2/src/definitions/factor.rs +++ b/mfkdf2/src/definitions/factor.rs @@ -28,14 +28,10 @@ use crate::{ /// # Example /// /// ```rust -/// use mfkdf2::{ -/// definitions::FactorType, -/// derive::factors::password as derive_password, -/// setup::factors::password::{PasswordOptions, password}, -/// }; +/// use mfkdf2::prelude::*; /// /// // setup a password factor with id "pwd" -/// let setup = password("password123", PasswordOptions { id: Some("pwd".to_string()) })?; +/// let setup = setup_password("password123", PasswordOptions { id: Some("pwd".to_string()) })?; /// /// let p = match &setup.factor_type { /// FactorType::Password(p) => p, @@ -51,7 +47,7 @@ use crate::{ /// }; /// assert_eq!(p.password, "password123"); /// assert_eq!(derive.data(), "password123".as_bytes()); -/// # Ok::<(), mfkdf2::error::MFKDF2Error>(()) +/// # MFKDF2Result::Ok(()) /// ``` #[derive(Clone, Serialize, Deserialize)] #[cfg_attr(feature = "bindings", derive(uniffi::Record))] diff --git a/mfkdf2/src/derive/factors/password.rs b/mfkdf2/src/derive/factors/password.rs index deb51700..7a220964 100644 --- a/mfkdf2/src/derive/factors/password.rs +++ b/mfkdf2/src/derive/factors/password.rs @@ -38,16 +38,7 @@ impl FactorDerive for Password { /// /// ```rust /// # use std::collections::HashMap; -/// # use mfkdf2::{ -/// # error::MFKDF2Result, -/// # setup::{ -/// # self, -/// # factors::password::{PasswordOptions, password as setup_password}, -/// # }, -/// # definitions::MFKDF2Options, -/// # derive, -/// # derive::factors::password as derive_password, -/// # }; +/// use mfkdf2::prelude::*; /// let setup_factor = setup_password("correct horse battery staple", PasswordOptions::default())?; /// let setup_key = setup::key(&[setup_factor], MFKDF2Options::default())?; /// @@ -60,7 +51,7 @@ impl FactorDerive for Password { /// )?; /// /// assert_eq!(derived_key.key, setup_key.key); -/// # Ok::<(), mfkdf2::error::MFKDF2Error>(()) +/// # MFKDF2Result::Ok(()) /// ``` pub fn password(password: impl Into) -> MFKDF2Result { let password = std::convert::Into::::into(password); diff --git a/mfkdf2/src/lib.rs b/mfkdf2/src/lib.rs index 599a92bb..22907b34 100644 --- a/mfkdf2/src/lib.rs +++ b/mfkdf2/src/lib.rs @@ -16,6 +16,7 @@ pub mod integrity; mod log; pub mod otpauth; pub mod policy; +pub mod prelude; mod rng; pub mod setup; mod traits; diff --git a/mfkdf2/src/prelude.rs b/mfkdf2/src/prelude.rs new file mode 100644 index 00000000..b0fa32db --- /dev/null +++ b/mfkdf2/src/prelude.rs @@ -0,0 +1,35 @@ +//! # MFKDF2 Prelude +//! +//! This module provides a comprehensive prelude that re-exports the most commonly used types, +//! traits, and functions from the MFKDF2 crate. This is designed to make testing, examples, +//! and development more ergonomic by reducing import boilerplate. +pub use crate::{ + constants::SECRET_SHARING_POLY, + definitions::{FactorType, MFKDF2DerivedKey, MFKDF2Factor, MFKDF2Options, factor::FactorParams}, + derive::{ + self, + factors::{ + hmacsha1 as derive_hmacsha1, hotp as derive_hotp, ooba as derive_ooba, + passkey as derive_passkey, password as derive_password, persisted as derive_persisted, + question as derive_question, stack as derive_stack, totp as derive_totp, + totp::TOTPDeriveOptions, uuid as derive_uuid, + }, + }, + error::{MFKDF2Error, MFKDF2Result}, + otpauth::{HashAlgorithm, Kind, OtpAuthUrlOptions, generate_otp_token}, + policy::{self, Policy, PolicySetupOptions}, + setup::{ + self, + factors::{ + hmacsha1::{HmacSha1Options, HmacSha1Output, hmacsha1 as setup_hmacsha1}, + hotp::{HOTPOptions, HOTPOutput, hotp as setup_hotp}, + ooba::{OobaOptions, OobaOutput, ooba as setup_ooba}, + passkey::{PasskeyOptions, PasskeyOutput, passkey as setup_passkey}, + password::{PasswordOptions, PasswordOutput, password as setup_password}, + question::{QuestionOptions, QuestionOutput, question as setup_question}, + stack::{StackOptions, StackOutput, stack as setup_stack}, + totp::{TOTPOptions, TOTPOutput, totp as setup_totp}, + uuid::{UUIDFactorOutput, UUIDOptions, uuid as setup_uuid}, + }, + }, +}; diff --git a/mfkdf2/src/setup/factors/password.rs b/mfkdf2/src/setup/factors/password.rs index 21f0bbc8..67f0821c 100644 --- a/mfkdf2/src/setup/factors/password.rs +++ b/mfkdf2/src/setup/factors/password.rs @@ -78,21 +78,21 @@ pub struct PasswordOptions { /// Basic usage with a default id: /// /// ```rust -/// # use mfkdf2::setup::factors::password::{password, PasswordOptions}; -/// let factor = password("correct horse battery staple", PasswordOptions::default())?; +/// use mfkdf2::prelude::*; +/// let factor = setup_password("correct horse battery staple", PasswordOptions::default())?; /// assert_eq!(factor.id.as_deref(), Some("password")); /// assert!(factor.entropy.unwrap() > 40.0); -/// # Ok::<(), mfkdf2::error::MFKDF2Error>(()) +/// # MFKDF2Result::Ok(()) /// ``` /// /// Using a custom id so you can distinguish multiple password factors: /// /// ```rust -/// # use mfkdf2::setup::factors::password::{password, PasswordOptions}; +/// use mfkdf2::prelude::*; /// let options = PasswordOptions { id: Some("login-password".to_string()) }; -/// let factor = password("my login secret", options)?; +/// let factor = setup_password("my login secret", options)?; /// assert_eq!(factor.id.as_deref(), Some("login-password")); -/// # Ok::<(), mfkdf2::error::MFKDF2Error>(()) +/// # MFKDF2Result::Ok(()) /// ``` pub fn password( password: impl Into, diff --git a/mfkdf2/tests/common/mod.rs b/mfkdf2/tests/common/mod.rs index 890b5cbe..c3803ddf 100644 --- a/mfkdf2/tests/common/mod.rs +++ b/mfkdf2/tests/common/mod.rs @@ -3,14 +3,16 @@ use base64::Engine; use hkdf::Hkdf; use hmac::{Hmac, Mac}; -use mfkdf2::definitions::{MFKDF2DerivedKey, MFKDF2Options, factor::FactorParams}; +use mfkdf2::prelude::*; use rsa::{ RsaPrivateKey, RsaPublicKey, pkcs1::{DecodeRsaPrivateKey, DecodeRsaPublicKey}, traits::PublicKeyParts, }; +use serde_json::Value; use sha1::Sha1; use sha2::Sha256; +use uuid::Uuid; pub const HMACSHA1_SECRET: [u8; 20] = [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, @@ -51,46 +53,34 @@ fn jwk(key: &RsaPublicKey) -> jsonwebtoken::jwk::Jwk { serde_json::from_value(jwk).unwrap() } -pub fn mock_mfkdf2_password() -> Result { - let factors = vec![mfkdf2::setup::factors::password( - "Tr0ubd4dour", - mfkdf2::setup::factors::password::PasswordOptions { id: Some("password_1".to_string()) }, - )] - .into_iter() - .collect::, _>>()?; +pub fn mock_mfkdf2_password() -> MFKDF2Result { + let factors = + vec![setup_password("Tr0ubd4dour", PasswordOptions { id: Some("password_1".to_string()) })] + .into_iter() + .collect::, _>>()?; let options = MFKDF2Options::default(); - let key = mfkdf2::setup::key(&factors, options)?; + let key = setup::key(&factors, options)?; Ok(key) } -pub fn mock_threshold_mfkdf2() -> Result { +pub fn mock_threshold_mfkdf2() -> MFKDF2Result { let factors = vec![ - mfkdf2::setup::factors::password( - "Tr0ubd4dour", - mfkdf2::setup::factors::password::PasswordOptions { id: Some("password_1".to_string()) }, - ), - mfkdf2::setup::factors::password( - "hunter2", - mfkdf2::setup::factors::password::PasswordOptions { id: Some("password_2".to_string()) }, - ), + setup_password("Tr0ubd4dour", PasswordOptions { id: Some("password_1".to_string()) }), + setup_password("hunter2", PasswordOptions { id: Some("password_2".to_string()) }), ] .into_iter() .collect::, _>>()?; let options = MFKDF2Options { threshold: Some(1), ..Default::default() }; - let key = mfkdf2::setup::key(&factors, options)?; + let key = setup::key(&factors, options)?; Ok(key) } -pub fn mock_password_question_mfkdf2() --> Result { +pub fn mock_password_question_mfkdf2() -> MFKDF2Result { let factors = vec![ - mfkdf2::setup::factors::password( - "Tr0ubd4dour", - mfkdf2::setup::factors::password::PasswordOptions { id: Some("password_1".to_string()) }, - ), - mfkdf2::setup::factors::question("Paris", mfkdf2::setup::factors::question::QuestionOptions { + setup_password("Tr0ubd4dour", PasswordOptions { id: Some("password_1".to_string()) }), + setup_question("Paris", QuestionOptions { id: Some("question_1".to_string()), question: Some("What is the capital of France?".to_string()), }), @@ -99,38 +89,35 @@ pub fn mock_password_question_mfkdf2() .collect::, _>>()?; let options = MFKDF2Options::default(); - let key = mfkdf2::setup::key(&factors, options)?; + let key = setup::key(&factors, options)?; Ok(key) } -pub fn mock_uuid_mfkdf2() -> Result { - let factors = vec![mfkdf2::setup::factors::uuid(mfkdf2::setup::factors::uuid::UUIDOptions { - id: None, - uuid: Some(uuid::Uuid::from_u128(123_456_789_012)), - })] - .into_iter() - .collect::, _>>()?; +pub fn mock_uuid_mfkdf2() -> MFKDF2Result { + let factors = + vec![setup_uuid(UUIDOptions { id: None, uuid: Some(Uuid::from_u128(123_456_789_012)) })] + .into_iter() + .collect::, _>>()?; let options = MFKDF2Options::default(); - let key = mfkdf2::setup::key(&factors, options)?; + let key = setup::key(&factors, options)?; Ok(key) } -pub fn mock_hmacsha1_mfkdf2() -> Result { - let factors = - vec![mfkdf2::setup::factors::hmacsha1(mfkdf2::setup::factors::hmacsha1::HmacSha1Options { - id: Some("hmacsha1_1".to_string()), - secret: Some(HMACSHA1_SECRET.to_vec()), - })] - .into_iter() - .collect::, _>>()?; +pub fn mock_hmacsha1_mfkdf2() -> MFKDF2Result { + let factors = vec![setup_hmacsha1(HmacSha1Options { + id: Some("hmacsha1_1".to_string()), + secret: Some(HMACSHA1_SECRET.to_vec()), + })] + .into_iter() + .collect::, _>>()?; let options = MFKDF2Options::default(); - let key = mfkdf2::setup::key(&factors, options)?; + let key = setup::key(&factors, options)?; Ok(key) } -pub fn mock_hotp_mfkdf2() -> Result { - let factors = vec![mfkdf2::setup::factors::hotp(mfkdf2::setup::factors::hotp::HOTPOptions { +pub fn mock_hotp_mfkdf2() -> MFKDF2Result { + let factors = vec![setup_hotp(HOTPOptions { id: Some("hotp_1".to_string()), secret: Some(HOTP_SECRET.to_vec()), ..Default::default() @@ -139,17 +126,14 @@ pub fn mock_hotp_mfkdf2() -> Result, _>>()?; let options = MFKDF2Options::default(); - let key = mfkdf2::setup::key(&factors, options)?; + let key = setup::key(&factors, options)?; Ok(key) } -pub fn mock_mixed_factors_mfkdf2() -> Result { +pub fn mock_mixed_factors_mfkdf2() -> MFKDF2Result { let factors = vec![ - mfkdf2::setup::factors::password( - "Tr0ubd4dour", - mfkdf2::setup::factors::password::PasswordOptions { id: Some("password_1".to_string()) }, - ), - mfkdf2::setup::factors::hotp(mfkdf2::setup::factors::hotp::HOTPOptions { + setup_password("Tr0ubd4dour", PasswordOptions { id: Some("password_1".to_string()) }), + setup_hotp(HOTPOptions { id: Some("hotp_1".to_string()), secret: Some(HOTP_SECRET.to_vec()), ..Default::default() @@ -159,75 +143,61 @@ pub fn mock_mixed_factors_mfkdf2() -> Result, _>>()?; let options = MFKDF2Options::default(); - let key = mfkdf2::setup::key(&factors, options)?; + let key = setup::key(&factors, options)?; Ok(key) } -pub fn create_setup_factor(name: &str) -> mfkdf2::definitions::MFKDF2Factor { +pub fn create_setup_factor(name: &str) -> MFKDF2Factor { match name { - "password" => mfkdf2::setup::factors::password( - "Tr0ubd4dour", - mfkdf2::setup::factors::password::PasswordOptions { id: Some("password_1".to_string()) }, - ) - .unwrap(), - "hotp" => mfkdf2::setup::factors::hotp(mfkdf2::setup::factors::hotp::HOTPOptions { + "password" => + setup_password("Tr0ubd4dour", PasswordOptions { id: Some("password_1".to_string()) }).unwrap(), + "hotp" => setup_hotp(HOTPOptions { id: Some("hotp_1".to_string()), secret: Some(HOTP_SECRET.to_vec()), ..Default::default() }) .unwrap(), - "totp" => mfkdf2::setup::factors::totp(mfkdf2::setup::factors::totp::TOTPOptions { + "totp" => setup_totp(TOTPOptions { id: Some("totp_1".to_string()), secret: Some(TOTP_SECRET.to_vec()), ..Default::default() }) .unwrap(), - "hmacsha1" => - mfkdf2::setup::factors::hmacsha1(mfkdf2::setup::factors::hmacsha1::HmacSha1Options { - id: Some("hmacsha1_1".to_string()), - secret: Some(HMACSHA1_SECRET.to_vec()), - }) - .unwrap(), - "question" => mfkdf2::setup::factors::question::question( - "my secret answer", - mfkdf2::setup::factors::question::QuestionOptions { - id: Some("question_1".to_string()), - question: Some("What is my secret?".to_string()), - }, - ) + "hmacsha1" => setup_hmacsha1(HmacSha1Options { + id: Some("hmacsha1_1".to_string()), + secret: Some(HMACSHA1_SECRET.to_vec()), + }) .unwrap(), - "uuid" => mfkdf2::setup::factors::uuid::uuid(mfkdf2::setup::factors::uuid::UUIDOptions { + "question" => setup_question("my secret answer", QuestionOptions { + id: Some("question_1".to_string()), + question: Some("What is my secret?".to_string()), + }) + .unwrap(), + "uuid" => setup_uuid(UUIDOptions { id: Some("uuid_1".to_string()), - uuid: Some(uuid::Uuid::parse_str("f9bf78b9-54e7-4696-97dc-5e750de4c592").unwrap()), + uuid: Some(Uuid::parse_str("f9bf78b9-54e7-4696-97dc-5e750de4c592").unwrap()), }) .unwrap(), "ooba" => { let rsa_public_key = RsaPublicKey::from_pkcs1_der(&hex::decode(RSA_PUBLIC_KEY).unwrap()).unwrap(); let test_jwk = jwk(&rsa_public_key); - mfkdf2::setup::factors::ooba(mfkdf2::setup::factors::ooba::OobaOptions { + setup_ooba(OobaOptions { id: Some("ooba_1".to_string()), length: Some(8), key: Some(test_jwk), - params: Some(serde_json::json!({"foo":"bar"})), + params: Some(serde_json::Value::from(serde_json::json!({"foo":"bar"}))), }) .unwrap() }, - "passkey" => mfkdf2::setup::factors::passkey::passkey( - PASSKEY_SECRET, - mfkdf2::setup::factors::passkey::PasskeyOptions { id: Some("passkey_1".to_string()) }, - ) - .unwrap(), + "passkey" => + setup_passkey(PASSKEY_SECRET, PasskeyOptions { id: Some("passkey_1".to_string()) }).unwrap(), _ => panic!("Unknown factor type for setup: {}", name), } } -pub fn create_derive_factor( - name: &str, - policy: &mfkdf2::policy::Policy, -) -> (String, mfkdf2::definitions::MFKDF2Factor) { +pub fn create_derive_factor(name: &str, policy: &Policy) -> (String, MFKDF2Factor) { match name { - "password" => - ("password_1".to_string(), mfkdf2::derive::factors::password("Tr0ubd4dour").unwrap()), + "password" => ("password_1".to_string(), derive_password("Tr0ubd4dour").unwrap()), "hotp" => { let factor_policy = policy.factors.iter().find(|f| f.id == "hotp_1").unwrap(); let (counter, digits, hash) = match &factor_policy.params { @@ -235,9 +205,8 @@ pub fn create_derive_factor( _ => panic!("Unexpected factor params for HOTP"), }; - let generated_code = - mfkdf2::otpauth::generate_otp_token(&HOTP_SECRET, counter, &hash, digits); - ("hotp_1".to_string(), mfkdf2::derive::factors::hotp(generated_code).unwrap()) + let generated_code = generate_otp_token(&HOTP_SECRET, counter, &hash, digits); + ("hotp_1".to_string(), derive_hotp(generated_code).unwrap()) }, "totp" => { let factor_policy = policy.factors.iter().find(|f| f.id == "totp_1").unwrap(); @@ -249,8 +218,8 @@ pub fn create_derive_factor( }; let counter = time as u64 / (step * 1000); - let totp_code = mfkdf2::otpauth::generate_otp_token(&TOTP_SECRET, counter, &hash, digits); - ("totp_1".to_string(), mfkdf2::derive::factors::totp(totp_code, None).unwrap()) + let totp_code = generate_otp_token(&TOTP_SECRET, counter, &hash, digits); + ("totp_1".to_string(), derive_totp(totp_code, None).unwrap()) }, "hmacsha1" => { let factor_policy = policy.factors.iter().find(|f| f.id == "hmacsha1_1").unwrap(); @@ -264,16 +233,12 @@ pub fn create_derive_factor( .finalize() .into_bytes() .into(); - ("hmacsha1_1".to_string(), mfkdf2::derive::factors::hmacsha1(response).unwrap()) + ("hmacsha1_1".to_string(), derive_hmacsha1(response).unwrap()) }, - "question" => - ("question_1".to_string(), mfkdf2::derive::factors::question("my secret answer").unwrap()), + "question" => ("question_1".to_string(), derive_question("my secret answer").unwrap()), "uuid" => ( "uuid_1".to_string(), - mfkdf2::derive::factors::uuid( - uuid::Uuid::parse_str("f9bf78b9-54e7-4696-97dc-5e750de4c592").unwrap(), - ) - .unwrap(), + derive_uuid(Uuid::parse_str("f9bf78b9-54e7-4696-97dc-5e750de4c592").unwrap()).unwrap(), ), "ooba" => { let rsa_private_key = @@ -284,16 +249,15 @@ pub fn create_derive_factor( FactorParams::OOBA(p) => hex::decode(&p.next).unwrap(), _ => panic!("Unexpected factor params for OOBA"), }; - let decrypted = serde_json::from_slice::( + let decrypted = serde_json::from_slice::( &rsa_private_key.decrypt(rsa::Oaep::new::(), &ciphertext).unwrap(), ) .unwrap(); let code = decrypted["code"].as_str().unwrap(); - ("ooba_1".to_string(), mfkdf2::derive::factors::ooba(code).unwrap()) + ("ooba_1".to_string(), derive_ooba(code).unwrap()) }, - "passkey" => - ("passkey_1".to_string(), mfkdf2::derive::factors::passkey(PASSKEY_SECRET).unwrap()), + "passkey" => ("passkey_1".to_string(), derive_passkey(PASSKEY_SECRET).unwrap()), _ => panic!("Unknown factor type for derive: {}", name), } } diff --git a/mfkdf2/tests/entropy.rs b/mfkdf2/tests/entropy.rs index 10bad0e9..1cf77f94 100644 --- a/mfkdf2/tests/entropy.rs +++ b/mfkdf2/tests/entropy.rs @@ -1,21 +1,13 @@ -use mfkdf2::{ - definitions::MFKDF2Options, policy::PolicySetupOptions, setup::factors::password::PasswordOptions, -}; +use mfkdf2::prelude::*; #[test] -fn entropy_3_of_3_passwords() -> Result<(), mfkdf2::error::MFKDF2Error> { +fn entropy_3_of_3_passwords() -> MFKDF2Result<()> { // ['12345678', 'ABCDEFGH', 'abcdefgh'] with threshold 3 - let setup = mfkdf2::setup::key( + let setup = setup::key( &[ - mfkdf2::setup::factors::password("12345678", PasswordOptions { - id: Some("password1".to_string()), - })?, - mfkdf2::setup::factors::password("ABCDEFGH", PasswordOptions { - id: Some("password2".to_string()), - })?, - mfkdf2::setup::factors::password("abcdefgh", PasswordOptions { - id: Some("password3".to_string()), - })?, + setup_password("12345678", PasswordOptions { id: Some("password1".to_string()) })?, + setup_password("ABCDEFGH", PasswordOptions { id: Some("password2".to_string()) })?, + setup_password("abcdefgh", PasswordOptions { id: Some("password3".to_string()) })?, ], MFKDF2Options { threshold: Some(3), ..Default::default() }, )?; @@ -28,18 +20,12 @@ fn entropy_3_of_3_passwords() -> Result<(), mfkdf2::error::MFKDF2Error> { } #[test] -fn entropy_2_of_3_passwords() -> Result<(), mfkdf2::error::MFKDF2Error> { - let setup = mfkdf2::setup::key( +fn entropy_2_of_3_passwords() -> MFKDF2Result<()> { + let setup = setup::key( &[ - mfkdf2::setup::factors::password("12345678", PasswordOptions { - id: Some("password1".to_string()), - })?, - mfkdf2::setup::factors::password("ABCDEFGH", PasswordOptions { - id: Some("password2".to_string()), - })?, - mfkdf2::setup::factors::password("abcdefgh", PasswordOptions { - id: Some("password3".to_string()), - })?, + setup_password("12345678", PasswordOptions { id: Some("password1".to_string()) })?, + setup_password("ABCDEFGH", PasswordOptions { id: Some("password2".to_string()) })?, + setup_password("abcdefgh", PasswordOptions { id: Some("password3".to_string()) })?, ], MFKDF2Options { threshold: Some(2), ..Default::default() }, )?; @@ -52,18 +38,12 @@ fn entropy_2_of_3_passwords() -> Result<(), mfkdf2::error::MFKDF2Error> { } #[test] -fn entropy_1_of_3_passwords() -> Result<(), mfkdf2::error::MFKDF2Error> { - let setup = mfkdf2::setup::key( +fn entropy_1_of_3_passwords() -> MFKDF2Result<()> { + let setup = setup::key( &[ - mfkdf2::setup::factors::password("12345678", PasswordOptions { - id: Some("password1".to_string()), - })?, - mfkdf2::setup::factors::password("ABCDEFGH", PasswordOptions { - id: Some("password2".to_string()), - })?, - mfkdf2::setup::factors::password("abcdefgh", PasswordOptions { - id: Some("password3".to_string()), - })?, + setup_password("12345678", PasswordOptions { id: Some("password1".to_string()) })?, + setup_password("ABCDEFGH", PasswordOptions { id: Some("password2".to_string()) })?, + setup_password("abcdefgh", PasswordOptions { id: Some("password3".to_string()) })?, ], MFKDF2Options { threshold: Some(1), ..Default::default() }, )?; @@ -76,36 +56,22 @@ fn entropy_1_of_3_passwords() -> Result<(), mfkdf2::error::MFKDF2Error> { } #[test] -fn entropy_policy_combinators() -> Result<(), mfkdf2::error::MFKDF2Error> { +fn entropy_policy_combinators() -> MFKDF2Result<()> { // Mirrors the complex AND/OR/ANY nesting from the JS test - let policy = mfkdf2::policy::setup( - mfkdf2::policy::and( - mfkdf2::setup::factors::password("12345678", PasswordOptions { - id: Some("password1".to_string()), - })?, - mfkdf2::policy::any(vec![ - mfkdf2::setup::factors::password("12345678", PasswordOptions { - id: Some("password7".to_string()), - })?, - mfkdf2::policy::or( - mfkdf2::setup::factors::password("12345678", PasswordOptions { - id: Some("password3".to_string()), - })?, - mfkdf2::setup::factors::password("12345678", PasswordOptions { - id: Some("password2".to_string()), - })?, + let policy = policy::setup( + policy::and( + setup_password("12345678", PasswordOptions { id: Some("password1".to_string()) })?, + policy::any(vec![ + setup_password("12345678", PasswordOptions { id: Some("password7".to_string()) })?, + policy::or( + setup_password("12345678", PasswordOptions { id: Some("password3".to_string()) })?, + setup_password("12345678", PasswordOptions { id: Some("password2".to_string()) })?, )?, - mfkdf2::policy::and( - mfkdf2::setup::factors::password("12345678", PasswordOptions { - id: Some("password4".to_string()), - })?, - mfkdf2::policy::or( - mfkdf2::setup::factors::password("12345678", PasswordOptions { - id: Some("password5".to_string()), - })?, - mfkdf2::setup::factors::password("12345678", PasswordOptions { - id: Some("password6".to_string()), - })?, + policy::and( + setup_password("12345678", PasswordOptions { id: Some("password4".to_string()) })?, + policy::or( + setup_password("12345678", PasswordOptions { id: Some("password5".to_string()) })?, + setup_password("12345678", PasswordOptions { id: Some("password6".to_string()) })?, )?, )?, ])?, @@ -120,11 +86,11 @@ fn entropy_policy_combinators() -> Result<(), mfkdf2::error::MFKDF2Error> { } #[test] -fn entropy_totp_hotp_6_digits() -> Result<(), mfkdf2::error::MFKDF2Error> { - let setup = mfkdf2::setup::key( +fn entropy_totp_hotp_6_digits() -> MFKDF2Result<()> { + let setup = setup::key( &[ - mfkdf2::setup::factors::totp(Default::default())?, // default 6 digits - mfkdf2::setup::factors::hotp(Default::default())?, // default 6 digits + setup_totp(Default::default())?, // default 6 digits + setup_hotp(Default::default())?, // default 6 digits ], MFKDF2Options { threshold: Some(2), ..Default::default() }, )?; @@ -136,17 +102,11 @@ fn entropy_totp_hotp_6_digits() -> Result<(), mfkdf2::error::MFKDF2Error> { } #[test] -fn entropy_totp_hotp_8_digits() -> Result<(), mfkdf2::error::MFKDF2Error> { - let setup = mfkdf2::setup::key( +fn entropy_totp_hotp_8_digits() -> MFKDF2Result<()> { + let setup = setup::key( &[ - mfkdf2::setup::factors::totp(mfkdf2::setup::factors::totp::TOTPOptions { - digits: Some(8), - ..Default::default() - })?, - mfkdf2::setup::factors::hotp(mfkdf2::setup::factors::hotp::HOTPOptions { - digits: Some(8), - ..Default::default() - })?, + setup_totp(TOTPOptions { digits: Some(8), ..Default::default() })?, + setup_hotp(HOTPOptions { digits: Some(8), ..Default::default() })?, ], MFKDF2Options { threshold: Some(2), ..Default::default() }, )?; diff --git a/mfkdf2/tests/integration.rs b/mfkdf2/tests/integration.rs index 9dc2f53c..9f07cf17 100644 --- a/mfkdf2/tests/integration.rs +++ b/mfkdf2/tests/integration.rs @@ -3,28 +3,28 @@ mod common; use std::collections::HashMap; use hmac::{Hmac, Mac}; -use mfkdf2::definitions::factor::FactorParams; +use mfkdf2::prelude::*; use rstest::rstest; use sha1::Sha1; use crate::common::*; #[test] -fn key_setup() -> Result<(), mfkdf2::error::MFKDF2Error> { +fn key_setup() -> MFKDF2Result<()> { mock_mfkdf2_password()?; Ok(()) } #[test] -fn key_derive() -> Result<(), mfkdf2::error::MFKDF2Error> { +fn key_derive() -> MFKDF2Result<()> { let key = mock_mfkdf2_password()?; println!("Setup key: {}", key); - let factor = ("password_1".to_string(), mfkdf2::derive::factors::password("Tr0ubd4dour")?); + let factor = ("password_1".to_string(), derive_password("Tr0ubd4dour")?); let factors = HashMap::from([factor]); - let derived_key = mfkdf2::derive::key(&key.policy, factors, true, false)?; + let derived_key = derive::key(&key.policy, factors, true, false)?; println!("Derived key: {}", derived_key); assert_eq!(derived_key.key, key.key); @@ -38,12 +38,11 @@ fn key_derive_fail() { let key = mock_mfkdf2_password().unwrap(); println!("Setup key: {}", key); - let factor = - ("password_1".to_string(), mfkdf2::derive::factors::password("wrong_password").unwrap()); + let factor = ("password_1".to_string(), derive_password("wrong_password").unwrap()); let factors = HashMap::from([factor]); - let derived_key = mfkdf2::derive::key(&key.policy, factors, true, false).unwrap(); + let derived_key = derive::key(&key.policy, factors, true, false).unwrap(); println!("Derived key: {}", derived_key); assert_eq!(derived_key.key, key.key); @@ -57,21 +56,20 @@ fn key_derive_threshold() { let key = mock_threshold_mfkdf2().unwrap(); println!("Setup key: {}", key); - let factor = - ("password_1".to_string(), mfkdf2::derive::factors::password("Tr0ubd4dour").unwrap()); + let factor = ("password_1".to_string(), derive_password("Tr0ubd4dour").unwrap()); let factors = HashMap::from([factor]); - let derived_key = mfkdf2::derive::key(&key.policy, factors, true, false).unwrap(); + let derived_key = derive::key(&key.policy, factors, true, false).unwrap(); println!("Derived key: {}", derived_key); assert_eq!(derived_key.key, key.key); - let factor = ("password_2".to_string(), mfkdf2::derive::factors::password("hunter2").unwrap()); + let factor = ("password_2".to_string(), derive_password("hunter2").unwrap()); let factors = HashMap::from([factor]); - let derived_key = mfkdf2::derive::key(&key.policy, factors, true, false).unwrap(); + let derived_key = derive::key(&key.policy, factors, true, false).unwrap(); println!("Derived key: {}", derived_key); assert_eq!(derived_key.key, key.key); @@ -88,10 +86,8 @@ fn key_derive_password_question() { let key = mock_password_question_mfkdf2().unwrap(); println!("Setup key: {}", key); - let factor_password = - ("password_1".to_string(), mfkdf2::derive::factors::password("Tr0ubd4dour").unwrap()); - let factor_question = - ("question_1".to_string(), mfkdf2::derive::factors::question("Paris").unwrap()); + let factor_password = ("password_1".to_string(), derive_password("Tr0ubd4dour").unwrap()); + let factor_question = ("question_1".to_string(), derive_question("Paris").unwrap()); let factors = HashMap::from([factor_password, factor_question]); @@ -106,20 +102,17 @@ fn key_derive_uuid() { let key = mock_uuid_mfkdf2().unwrap(); println!("Setup key: {}", key); - let factor = ( - "uuid".to_string(), - mfkdf2::derive::factors::uuid(uuid::Uuid::from_u128(123_456_789_012)).unwrap(), - ); + let factor = ("uuid".to_string(), derive_uuid(uuid::Uuid::from_u128(123_456_789_012)).unwrap()); let factors = HashMap::from([factor]); - let derived_key = mfkdf2::derive::key(&key.policy, factors, true, false).unwrap(); + let derived_key = derive::key(&key.policy, factors, true, false).unwrap(); assert_eq!(derived_key.key, key.key); } #[test] -fn key_derive_hmacsha1() -> Result<(), mfkdf2::error::MFKDF2Error> { +fn key_derive_hmacsha1() -> MFKDF2Result<()> { let key = mock_hmacsha1_mfkdf2().unwrap(); println!("Setup key: {}", key); @@ -137,10 +130,10 @@ fn key_derive_hmacsha1() -> Result<(), mfkdf2::error::MFKDF2Error> { .into_bytes() .into(); - let factor = ("hmacsha1_1".to_string(), mfkdf2::derive::factors::hmacsha1(response).unwrap()); + let factor = ("hmacsha1_1".to_string(), derive_hmacsha1(response).unwrap()); let factors = HashMap::from([factor]); - let derived_key = mfkdf2::derive::key(&key.policy, factors, true, false)?; + let derived_key = derive::key(&key.policy, factors, true, false)?; println!("Derived key: {}", derived_key); assert_eq!(derived_key.key, key.key); @@ -186,14 +179,14 @@ fn policy_json_schema_compliance() { } #[test] -fn key_setup_hotp() -> Result<(), mfkdf2::error::MFKDF2Error> { +fn key_setup_hotp() -> MFKDF2Result<()> { let key = mock_hotp_mfkdf2().unwrap(); println!("Setup key: {}", key); Ok(()) } #[test] -fn key_derive_hotp() -> Result<(), mfkdf2::error::MFKDF2Error> { +fn key_derive_hotp() -> MFKDF2Result<()> { let key = mock_hotp_mfkdf2().unwrap(); println!("Setup key: {}", key); @@ -206,15 +199,15 @@ fn key_derive_hotp() -> Result<(), mfkdf2::error::MFKDF2Error> { // Generate the HOTP code that the user would need to provide // This simulates what would come from an authenticator app - let generated_code = mfkdf2::otpauth::generate_otp_token(&HOTP_SECRET, counter, &hash, digits); + let generated_code = generate_otp_token(&HOTP_SECRET, counter, &hash, digits); println!("Generated HOTP code: {}", generated_code); // Now use this code to derive the key - let factor = ("hotp_1".to_string(), mfkdf2::derive::factors::hotp(generated_code).unwrap()); + let factor = ("hotp_1".to_string(), derive_hotp(generated_code).unwrap()); let factors = HashMap::from([factor]); - let derived_key = mfkdf2::derive::key(&key.policy, factors, true, false)?; + let derived_key = derive::key(&key.policy, factors, true, false)?; println!("Derived key: {}", derived_key); assert_eq!(derived_key.key, key.key); @@ -229,10 +222,10 @@ fn key_derive_hotp_wrong_code() { // Use a wrong HOTP code let wrong_code = 123_456_u32; - let factor = ("hotp_1".to_string(), mfkdf2::derive::factors::hotp(wrong_code).unwrap()); + let factor = ("hotp_1".to_string(), derive_hotp(wrong_code).unwrap()); let factors = HashMap::from([factor]); - let derived_key = mfkdf2::derive::key(&key.policy, factors, true, false).unwrap(); + let derived_key = derive::key(&key.policy, factors, true, false).unwrap(); println!("Derived key: {}", derived_key); // This should fail because the wrong code will produce a different target @@ -240,42 +233,36 @@ fn key_derive_hotp_wrong_code() { } #[test] -fn totp_static() -> Result<(), mfkdf2::error::MFKDF2Error> { - let setup = mfkdf2::setup::key( - &[mfkdf2::setup::factors::totp(mfkdf2::setup::factors::totp::TOTPOptions { +fn totp_static() -> MFKDF2Result<()> { + let setup = setup::key( + &[setup_totp(TOTPOptions { secret: Some(b"abcdefghijklmnopqrst".to_vec()), time: Some(1), ..Default::default() })?], - mfkdf2::definitions::MFKDF2Options::default(), + MFKDF2Options::default(), )?; - let derived_key1 = mfkdf2::derive::key( + let derived_key1 = derive::key( &setup.policy, HashMap::from([( "totp".to_string(), - mfkdf2::derive::factors::totp( + derive_totp( 241063, - Some(mfkdf2::derive::factors::totp::TOTPDeriveOptions { - time: Some(30001), - ..Default::default() - }), + Some(derive_totp::TOTPDeriveOptions { time: Some(30001), ..Default::default() }), )?, )]), true, false, )?; - let derived_key2 = mfkdf2::derive::key( + let derived_key2 = derive::key( &derived_key1.policy, HashMap::from([( "totp".to_string(), - mfkdf2::derive::factors::totp( + derive_totp( 361687, - Some(mfkdf2::derive::factors::totp::TOTPDeriveOptions { - time: Some(60001), - ..Default::default() - }), + Some(derive_totp::TOTPDeriveOptions { time: Some(60001), ..Default::default() }), )?, )]), true, @@ -289,7 +276,7 @@ fn totp_static() -> Result<(), mfkdf2::error::MFKDF2Error> { } #[test] -fn key_derive_mixed_password_hotp() -> Result<(), mfkdf2::error::MFKDF2Error> { +fn key_derive_mixed_password_hotp() -> MFKDF2Result<()> { let key = mock_mixed_factors_mfkdf2().unwrap(); println!("Setup key: {}", key); @@ -301,17 +288,16 @@ fn key_derive_mixed_password_hotp() -> Result<(), mfkdf2::error::MFKDF2Error> { }; // Generate the correct HOTP code using SHA256 (different from previous test) - let generated_code = mfkdf2::otpauth::generate_otp_token(&HOTP_SECRET, counter, &hash, digits); + let generated_code = generate_otp_token(&HOTP_SECRET, counter, &hash, digits); println!("Generated HOTP code (SHA256): {}", generated_code); // Create both factors - let factor_password = - ("password_1".to_string(), mfkdf2::derive::factors::password("Tr0ubd4dour").unwrap()); - let factor_hotp = ("hotp_1".to_string(), mfkdf2::derive::factors::hotp(generated_code).unwrap()); + let factor_password = ("password_1".to_string(), derive_password("Tr0ubd4dour").unwrap()); + let factor_hotp = ("hotp_1".to_string(), derive_hotp(generated_code).unwrap()); let factors = HashMap::from([factor_password, factor_hotp]); - let derived_key = mfkdf2::derive::key(&key.policy, factors, true, false)?; + let derived_key = derive::key(&key.policy, factors, true, false)?; println!("Derived key: {}", derived_key); assert_eq!(derived_key.key, key.key); @@ -331,13 +317,13 @@ fn key_derivation_combinations( #[case] threshold: u8, #[case] derive_combinations: Vec>, #[case] derivation_runs: u32, -) -> Result<(), mfkdf2::error::MFKDF2Error> { +) -> MFKDF2Result<()> { // 1. Setup key let setup_factors: Vec<_> = setup_factor_names.into_iter().map(create_setup_factor).collect(); let options = mfkdf2::definitions::MFKDF2Options { threshold: Some(threshold), ..Default::default() }; - let setup_key = mfkdf2::setup::key(&setup_factors, options)?; + let setup_key = setup::key(&setup_factors, options)?; // 2. Loop through derivation combinations for combo in derive_combinations { @@ -346,7 +332,7 @@ fn key_derivation_combinations( let derive_factors: HashMap<_, _> = combo.iter().map(|name| create_derive_factor(name, &policy_for_run)).collect(); - let derived_key = mfkdf2::derive::key(&policy_for_run, derive_factors, true, false)?; + let derived_key = derive::key(&policy_for_run, derive_factors, true, false)?; assert_eq!( derived_key.key, setup_key.key, diff --git a/mfkdf2/tests/integrity.rs b/mfkdf2/tests/integrity.rs index 1eab99f8..8797496d 100644 --- a/mfkdf2/tests/integrity.rs +++ b/mfkdf2/tests/integrity.rs @@ -1,13 +1,8 @@ -#![allow(clippy::unwrap_used)] - mod common; use std::collections::HashMap; -use mfkdf2::{ - definitions::{MFKDF2DerivedKey, MFKDF2Options}, - policy::Policy, -}; +use mfkdf2::prelude::*; use crate::common::{create_derive_factor, create_setup_factor}; @@ -17,20 +12,16 @@ fn make_policy(setup_factor_names: &[&str], threshold: u8, integrity: bool) -> M let options = MFKDF2Options { threshold: Some(threshold), integrity: Some(integrity), ..Default::default() }; - mfkdf2::setup::key(&setup_factors, options).unwrap() + setup::key(&setup_factors, options).unwrap() } -fn derive_once( - policy: &Policy, - factor_names: &[&str], - verify_integrity: bool, -) -> mfkdf2::definitions::MFKDF2DerivedKey { +fn derive_once(policy: &Policy, factor_names: &[&str], verify_integrity: bool) -> MFKDF2DerivedKey { // build derive map using the shared harness (needs policy for TOTP/HOTP codes) let derive_map: HashMap<_, _> = factor_names.iter().map(|name| create_derive_factor(name, policy)).collect(); // derive - mfkdf2::derive::key(policy, derive_map, verify_integrity, false).unwrap() + derive::key(policy, derive_map, verify_integrity, false).unwrap() } #[test] @@ -48,7 +39,7 @@ fn integrity_disabled_allows_tamper() { } // Build derive map; override the id for the password entry to match the tampered id - let mut derive_map: HashMap = HashMap::new(); + let mut derive_map: HashMap = HashMap::new(); for name in ["password", "hotp", "totp", "uuid"] { let (mut id, factor) = create_derive_factor(name, &policy); if name == "password" { @@ -58,9 +49,9 @@ fn integrity_disabled_allows_tamper() { } // With integrity verification OFF, derivation must still succeed - let derived = mfkdf2::derive::key(&policy, derive_map, false, false).unwrap(); + let derived = derive::key(&policy, derive_map, false, false).unwrap(); // quick sanity: we can re-derive once more from the mutated policy - let _ = mfkdf2::derive::key(&derived.policy, HashMap::new(), false, false); // empty map just ensures type compiles; not used + let _ = derive::key(&derived.policy, HashMap::new(), false, false); // empty map just ensures type compiles; not used } #[test] @@ -88,7 +79,7 @@ fn integrity_enabled_rejects_policy_id_tamper() { let derive_map: HashMap<_, _> = ["password", "uuid"].iter().map(|name| create_derive_factor(name, &policy)).collect(); - let res = mfkdf2::derive::key(&policy, derive_map, true, false); + let res = derive::key(&policy, derive_map, true, false); assert!(res.is_err(), "expected integrity verification to fail after policy.id tamper"); } @@ -104,7 +95,7 @@ fn integrity_enabled_rejects_threshold_tamper() { let derive_map: HashMap<_, _> = ["password", "question"].iter().map(|name| create_derive_factor(name, &policy)).collect(); - let res = mfkdf2::derive::key(&policy, derive_map, true, false); + let res = derive::key(&policy, derive_map, true, false); assert!(res.is_err(), "expected integrity verification to fail after threshold tamper"); } @@ -120,7 +111,7 @@ fn integrity_enabled_rejects_salt_tamper() { let derive_map: HashMap<_, _> = ["password", "totp"].iter().map(|name| create_derive_factor(name, &policy)).collect(); - let res = mfkdf2::derive::key(&policy, derive_map, true, false); + let res = derive::key(&policy, derive_map, true, false); assert!(res.is_err(), "expected integrity verification to fail after salt tamper"); } @@ -138,7 +129,7 @@ fn integrity_enabled_rejects_factor_id_tamper() { } // Build derive map supplying password under tampered id — integrity must still reject - let mut derive_map: HashMap = HashMap::new(); + let mut derive_map: HashMap = HashMap::new(); for name in ["password", "uuid"] { let (mut id, factor) = create_derive_factor(name, &policy); if name == "password" { @@ -147,7 +138,7 @@ fn integrity_enabled_rejects_factor_id_tamper() { derive_map.insert(id, factor); } - let res = mfkdf2::derive::key(&policy, derive_map, true, false); + let res = derive::key(&policy, derive_map, true, false); assert!(res.is_err(), "expected integrity verification to fail after factor id tamper"); } @@ -170,7 +161,7 @@ fn integrity_enabled_rejects_derived_policy_tamper() { } // Supply factors; integrity ON must now reject - let mut derive_map: HashMap = HashMap::new(); + let mut derive_map: HashMap = HashMap::new(); for name in ["password", "hotp", "uuid", "totp"] { let (mut id, factor) = create_derive_factor(name, &tampered); if name == "password" { @@ -179,6 +170,6 @@ fn integrity_enabled_rejects_derived_policy_tamper() { derive_map.insert(id, factor); } - let res = mfkdf2::derive::key(&tampered, derive_map, true, false); + let res = derive::key(&tampered, derive_map, true, false); assert!(res.is_err(), "expected integrity verification to fail after tampering derived policy"); } diff --git a/mfkdf2/tests/security.rs b/mfkdf2/tests/security.rs index 66bc3244..d21151f8 100644 --- a/mfkdf2/tests/security.rs +++ b/mfkdf2/tests/security.rs @@ -5,22 +5,7 @@ use std::{ }; use base64::{Engine, engine::general_purpose}; -use mfkdf2::{ - constants::SECRET_SHARING_POLY, - definitions::{MFKDF2Options, factor::FactorParams}, - derive, - error::MFKDF2Error, - otpauth::{HashAlgorithm, generate_otp_token}, - policy::{self, PolicySetupOptions}, - setup::{ - self, - factors::{ - hotp::HOTPOptions, - password::PasswordOptions, - totp::{TOTPOptions, TOTPOutput}, - }, - }, -}; +use mfkdf2::prelude::*; use rand_chacha::rand_core::{RngCore, SeedableRng}; // Helper function to perform XOR operation on two byte arrays diff --git a/mfkdf2/tests/stack.rs b/mfkdf2/tests/stack.rs index e790dd26..7cbf6af6 100644 --- a/mfkdf2/tests/stack.rs +++ b/mfkdf2/tests/stack.rs @@ -1,66 +1,52 @@ use std::collections::HashMap; use hmac::{Hmac, Mac}; -use mfkdf2::definitions::factor::FactorParams; +use mfkdf2::prelude::*; use sha1::Sha1; +use uuid::Uuid; -const HMACSHA1_SECRET: [u8; 20] = [ +pub const HMACSHA1_SECRET: [u8; 20] = [ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, ]; -fn mock_setup_stack() -> Result { +fn mock_setup_stack() -> MFKDF2Result { let stacked_factors = vec![ - mfkdf2::setup::factors::password( - "Tr0ubd4dour", - mfkdf2::setup::factors::password::PasswordOptions { id: Some("password_1".to_string()) }, - ), - mfkdf2::setup::factors::question::question( - "my secret answer", - mfkdf2::setup::factors::question::QuestionOptions { - id: Some("question_1".to_string()), - question: Some("What is my secret?".to_string()), - }, - ), + setup_password("Tr0ubd4dour", PasswordOptions { id: Some("password_1".to_string()) })?, + setup_question("my secret answer", QuestionOptions { + id: Some("question_1".to_string()), + question: Some("What is my secret?".to_string()), + })?, ] .into_iter() - .collect::, _>>()?; + .collect::>(); let stacked_factors_2 = vec![ - mfkdf2::setup::factors::uuid::uuid(mfkdf2::setup::factors::uuid::UUIDOptions { + setup_uuid(UUIDOptions { id: Some("uuid_1".to_string()), - uuid: Some(uuid::Uuid::parse_str("f9bf78b9-54e7-4696-97dc-5e750de4c592").unwrap()), - }), - mfkdf2::setup::factors::hmacsha1(mfkdf2::setup::factors::hmacsha1::HmacSha1Options { + uuid: Some(Uuid::parse_str("f9bf78b9-54e7-4696-97dc-5e750de4c592").unwrap()), + })?, + setup_hmacsha1(HmacSha1Options { id: Some("hmacsha1_1".to_string()), secret: Some(HMACSHA1_SECRET.to_vec()), - }), + })?, ] .into_iter() - .collect::, _>>()?; + .collect::>(); - let key = mfkdf2::setup::key( + let key = setup::key( &[ - mfkdf2::setup::factors::stack( - stacked_factors, - mfkdf2::setup::factors::stack::StackOptions { - id: Some("stack_1".to_string()), - ..Default::default() - }, - )?, - mfkdf2::setup::factors::stack( - stacked_factors_2, - mfkdf2::setup::factors::stack::StackOptions { - id: Some("stack_2".to_string()), - ..Default::default() - }, - )?, - mfkdf2::setup::factors::password( - "my-secure-password", - mfkdf2::setup::factors::password::PasswordOptions { id: Some("password_3".to_string()) }, - )?, + setup_stack(stacked_factors, StackOptions { + id: Some("stack_1".to_string()), + ..Default::default() + })?, + setup_stack(stacked_factors_2, StackOptions { + id: Some("stack_2".to_string()), + ..Default::default() + })?, + setup_password("my-secure-password", PasswordOptions { id: Some("password_3".to_string()) })?, ], - mfkdf2::definitions::MFKDF2Options { threshold: Some(1), ..Default::default() }, + MFKDF2Options { threshold: Some(1), ..Default::default() }, )?; Ok(key) } @@ -69,13 +55,13 @@ fn mock_setup_stack() -> Result