Skip to content

Commit a075462

Browse files
committed
add missing docs
1 parent 7c3591b commit a075462

32 files changed

Lines changed: 143 additions & 118 deletions

README.md

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -115,32 +115,30 @@ cargo run --bin uniffi-bindgen generate --library target/debug/libmfkdf2.dylib -
115115
## Usage
116116

117117
```rust
118-
use std::collections::HashMap;
118+
# use std::collections::HashMap;
119119
use mfkdf2::{derive, setup};
120120
use mfkdf2::setup::{factors::hotp::HOTPOptions, password::PasswordOptions, key::MFKDF2Options};
121121
use mfkdf2::derive::factors::{hotp::HOTPOptions, password::PasswordOptions};
122122
123-
fn main() -> Result<(), Box<dyn std::error::Error>> {
124-
// 1. Define factors
125-
let password_factor = setup::password("my-super-secret-password", PasswordOptions::default())?;
126-
let totp_factor = setup::hotp("base32-encoded-secret", HOTPOptions::default())?;
123+
// 1. Define factors
124+
let password_factor = setup::password("my-super-secret-password", PasswordOptions::default())?;
125+
let totp_factor = setup::hotp("base32-encoded-secret", HOTPOptions::default())?;
127126
128-
// 2. Set up the key with the policy
129-
let key = setup::key(vec![password_factor, totp_factor], MFKDF2Options::default())?;
127+
// 2. Set up the key with the policy
128+
let key = setup::key(vec![password_factor, totp_factor], MFKDF2Options::default())?;
130129
131-
println!("Key: {:?}", key);
130+
println!("Key: {:?}", key);
132131
133-
let factors = HashMap::from([
134-
("password".to_string(), derive::factors::password("my-super-secret-password")?),
135-
"hotp".to_string(), derive::factors::hotp("123456")?),
136-
]);
137-
// 3. Derive the key using user inputs
138-
let derived_key = derive::key(&key.policy, factors, true, false)?;
132+
let factors = HashMap::from([
133+
("password".to_string(), derive::factors::password("my-super-secret-password")?),
134+
"hotp".to_string(), derive::factors::hotp("123456")?),
135+
]);
136+
// 3. Derive the key using user inputs
137+
let derived_key = derive::key(&key.policy, factors, true, false)?;
139138
140-
println!("Derived Key: {:?}", derived_key);
139+
println!("Derived Key: {:?}", derived_key);
141140
142-
Ok(())
143-
}
141+
# Ok::<(), mfkdf2::error::MFKDF2Error>(())
144142
```
145143
146144
## Development

mfkdf2/src/constants.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1+
//! Constants for MFKDF2.
2+
13
/// Irreducible polynomial used in the secret sharing scheme: x⁸ + x⁴ + x³ + x + 1
24
pub const SECRET_SHARING_POLY: u16 = 0x11B;

mfkdf2/src/crypto.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,15 @@ use sha1::Sha1;
88
use sha2::Sha256;
99

1010
/// Derives a 32-byte key using HKDF-SHA256 with the given salt and info.
11-
pub fn hkdf_sha256_with_info(input: &[u8], salt: &[u8], info: &[u8]) -> [u8; 32] {
11+
pub(crate) fn hkdf_sha256_with_info(input: &[u8], salt: &[u8], info: &[u8]) -> [u8; 32] {
1212
let hk = Hkdf::<Sha256>::new(Some(salt), input);
1313
let mut okm = [0u8; 32];
1414
hk.expand(info, &mut okm).expect("HKDF expand");
1515
okm
1616
}
1717

1818
/// Encrypts a buffer using AES256-ECB with the given 32-byte key.
19-
pub fn encrypt(data: &[u8], key: &[u8; 32]) -> Vec<u8> {
19+
pub(crate) fn encrypt(data: &[u8], key: &[u8; 32]) -> Vec<u8> {
2020
// Ensure the input is a multiple of 16 by zero-padding if necessary.
2121
let mut buf = {
2222
let mut v = data.to_vec();
@@ -35,21 +35,21 @@ pub fn encrypt(data: &[u8], key: &[u8; 32]) -> Vec<u8> {
3535

3636
/// Decrypts a buffer using AES256-ECB with the given 32-byte key.
3737
// TODO (@lonerapier): check every use of decrypt and unpad properly or use assert.
38-
pub fn decrypt(mut data: Vec<u8>, key: &[u8; 32]) -> Vec<u8> {
38+
pub(crate) fn decrypt(mut data: Vec<u8>, key: &[u8; 32]) -> Vec<u8> {
3939
let cipher = Decryptor::<Aes256>::new_from_slice(key).expect("Invalid AES key");
4040
let _ = cipher.decrypt_padded_mut::<NoPadding>(&mut data).expect("ECB decrypt");
4141
data
4242
}
4343

4444
/// Computes an HMAC-SHA1 over the given challenge using the provided secret.
45-
pub fn hmacsha1(secret: &[u8], challenge: &[u8]) -> [u8; 20] {
45+
pub(crate) fn hmacsha1(secret: &[u8], challenge: &[u8]) -> [u8; 20] {
4646
let mut mac = <Hmac<Sha1> as Mac>::new_from_slice(secret).unwrap();
4747
mac.update(challenge);
4848
mac.finalize().into_bytes().into()
4949
}
5050

5151
/// Computes an HMAC-SHA256 over the given input using the provided secret.
52-
pub fn hmacsha256(secret: &[u8], input: &[u8]) -> [u8; 32] {
52+
pub(crate) fn hmacsha256(secret: &[u8], input: &[u8]) -> [u8; 32] {
5353
let mut mac = <Hmac<Sha256> as Mac>::new_from_slice(secret).unwrap();
5454
mac.update(input);
5555
mac.finalize().into_bytes().into()

mfkdf2/src/definitions/factor.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
//! # MFKDF2 Factor
2+
//!
3+
//! A Factor represents an authentication primitive. Each factor has:
4+
//!
5+
//! - **Factor material**: the secret input (e.g., a password, TOTP secret, hardware key seed)
6+
//! - **Public state**: non-secret metadata the factor needs to operate (e.g., counters,
7+
//! identifiers)
18
use serde::{Deserialize, Serialize};
29

310
use crate::setup::factors::{hmacsha1, hotp, ooba, passkey, password, question, stack, totp, uuid};
@@ -67,8 +74,10 @@ pub struct MFKDF2Factor {
6774
}
6875

6976
impl MFKDF2Factor {
77+
/// Returns the type of the factor.
7078
pub fn kind(&self) -> String { self.factor_type.kind() }
7179

80+
/// Returns the bytes of the factor material.
7281
pub fn data(&self) -> Vec<u8> { self.factor_type.bytes() }
7382
}
7483

@@ -94,15 +103,25 @@ impl std::fmt::Debug for MFKDF2Factor {
94103
#[cfg_attr(feature = "bindings", derive(uniffi::Enum))]
95104
#[derive(Clone, Debug, Serialize, Deserialize)]
96105
pub enum FactorType {
106+
/// [`password::Password`] factor.
97107
Password(password::Password),
108+
/// [`hotp::HOTP`] factor.
98109
HOTP(hotp::HOTP),
110+
/// [`question::Question`] factor.
99111
Question(question::Question),
112+
/// [`uuid::UUIDFactor`] factor.
100113
UUID(uuid::UUIDFactor),
114+
/// [`hmacsha1::HmacSha1`] factor.
101115
HmacSha1(hmacsha1::HmacSha1),
116+
/// [`totp::TOTP`] factor.
102117
TOTP(totp::TOTP),
118+
/// [`ooba::Ooba`] factor.
103119
OOBA(ooba::Ooba),
120+
/// [`passkey::Passkey`] factor.
104121
Passkey(passkey::Passkey),
122+
/// [`stack::Stack`] factor.
105123
Stack(stack::Stack),
124+
/// [Persisted](`crate::derive::factors::persisted::Persisted`) factor.
106125
Persisted(crate::derive::factors::persisted::Persisted),
107126
}
108127

mfkdf2/src/definitions/mfkdf_derived_key/hints.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -97,15 +97,13 @@ impl MFKDF2DerivedKey {
9797
///
9898
/// use mfkdf2::{
9999
/// definitions::MFKDF2Options,
100-
/// derive::{self, factors::password as derive_password},
100+
/// derive,
101101
/// error::MFKDF2Error,
102102
/// setup::{
103103
/// self,
104104
/// factors::{password, password::PasswordOptions},
105105
/// },
106106
/// };
107-
///
108-
/// # fn main() -> Result<(), MFKDF2Error> {
109107
/// // Create a policy with a single password factor.
110108
/// let mut setup_key = setup::key(
111109
/// &[password("correct horse battery staple", PasswordOptions {
@@ -125,14 +123,16 @@ impl MFKDF2DerivedKey {
125123
/// // hints and return `MFKDF2Error::HintMismatch` if they do not match.
126124
/// let derived_key = derive::key(
127125
/// &setup_key.policy,
128-
/// HashMap::from([("password1".to_string(), derive_password("correct horse battery staple")?)]),
126+
/// HashMap::from([(
127+
/// "password1".to_string(),
128+
/// derive::factors::password("correct horse battery staple")?,
129+
/// )]),
129130
/// true, // integrity
130131
/// false, // allow_partial
131132
/// )?;
132133
///
133134
/// assert_eq!(derived_key.key, setup_key.key);
134-
/// # Ok(())
135-
/// # }
135+
/// # Ok::<(), mfkdf2::error::MFKDF2Error>(())
136136
/// ```
137137
pub fn add_hint(&mut self, factor_id: &str, bits: Option<u8>) -> Result<(), MFKDF2Error> {
138138
let bits = bits.unwrap_or(7);

mfkdf2/src/definitions/mfkdf_derived_key/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
//! # MFKDF2 Derived Key
2+
//!
3+
//! The security properties of MFKDF allow the derived key to itself be used to authenticate end
4+
//! users and implicitly verify all of their authentication factors. Because a properly-configured
5+
//! MFKDF key (`K`) cannot feasibly be derived without the presentation of all constituent factors,
6+
//! verifying a user’s derivation of `K` effectively constitutes verification of all factors.
7+
//!
8+
//! In practice, this means `MFKDF2DerivedKey` can safely serve as a high-entropy application root
9+
//! key, while the embedded [`Policy`] and threshold secret-sharing scheme enable flexible recovery
10+
//! flows (such as `t`‑of‑`n` factor policies) without weakening the guarantees provided by the
11+
//! underlying multi-factor construction.
112
use std::collections::HashMap;
213

314
use base64::engine::general_purpose;

mfkdf2/src/definitions/mfkdf_derived_key/persistence.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,10 @@ impl crate::definitions::MFKDF2DerivedKey {
1414
/// factors::{password, password::PasswordOptions},
1515
/// },
1616
/// };
17-
/// # fn main() -> Result<(), MFKDF2Error> {
1817
/// let setup_key =
1918
/// setup::key(&[password("password", PasswordOptions::default())?], MFKDF2Options::default())?;
2019
/// let share = setup_key.persist_factor("password");
21-
/// # Ok(())
22-
/// # }
20+
/// # Ok::<(), mfkdf2::error::MFKDF2Error>(())
2321
/// ```
2422
pub fn persist_factor(&self, id: &str) -> Vec<u8> {
2523
let index = self.policy.factors.iter().position(|f| f.id == id).unwrap();

mfkdf2/src/derive/factors/hmacsha1.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -91,18 +91,16 @@ impl FactorDerive for HmacSha1 {
9191
/// # error::MFKDF2Result,
9292
/// # setup::{
9393
/// # self,
94-
/// # factors::hmacsha1::{HmacSha1Options, hmacsha1 as setup_hmacsha1},
94+
/// # factors::hmacsha1::{HmacSha1Options},
9595
/// # },
9696
/// # definitions::MFKDF2Options,
9797
/// # derive,
9898
/// # };
9999
/// # use hmac::{Mac, Hmac};
100100
/// # use sha1::Sha1;
101101
/// # const HMACSHA1_SECRET: [u8; 20] = [0x11; 20];
102-
/// #
103-
/// # fn main() -> MFKDF2Result<()> {
104102
/// // KeySetup: build a policy with a single HMAC‑SHA1 factor
105-
/// let setup_factor = setup_hmacsha1(HmacSha1Options {
103+
/// let setup_factor = setup::factors::hmacsha1(HmacSha1Options {
106104
/// secret: Some(HMACSHA1_SECRET.to_vec()),
107105
/// ..Default::default()
108106
/// })?;
@@ -122,7 +120,7 @@ impl FactorDerive for HmacSha1 {
122120
/// .into();
123121
///
124122
/// // Build the derive‑time HMAC witness and run KeyDerive
125-
/// let derive_factor = crate::derive::factors::hmacsha1(response.into())?;
123+
/// let derive_factor = derive::factors::hmacsha1(response.into())?;
126124
/// let derived_key = derive::key(
127125
/// &setup_key.policy,
128126
/// HashMap::from([("hmacsha1".to_string(), derive_factor)]),
@@ -131,8 +129,7 @@ impl FactorDerive for HmacSha1 {
131129
/// )?;
132130
///
133131
/// assert_eq!(derived_key.key, setup_key.key);
134-
/// # Ok(())
135-
/// # }
132+
/// # Ok::<(), mfkdf2::error::MFKDF2Error>(())
136133
/// ```
137134
pub fn hmacsha1(response: HmacSha1Response) -> MFKDF2Result<MFKDF2Factor> {
138135
Ok(MFKDF2Factor {

mfkdf2/src/derive/factors/hotp.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,11 @@ impl FactorDerive for HOTP {
9292
/// # otpauth::HashAlgorithm,
9393
/// # setup::{
9494
/// # self,
95-
/// # factors::hotp::{HOTPOptions, hotp as setup_hotp},
95+
/// # factors::hotp::{HOTPOptions},
9696
/// # },
9797
/// # definitions::MFKDF2Options,
9898
/// # derive,
9999
/// # };
100-
/// #
101-
/// # fn main() -> MFKDF2Result<()> {
102100
/// let secret = b"hello world mfkdf2!!".to_vec();
103101
/// let options = HOTPOptions {
104102
/// id: Some("hotp".to_string()),
@@ -108,7 +106,7 @@ impl FactorDerive for HOTP {
108106
/// ..Default::default()
109107
/// };
110108
///
111-
/// let setup_factor = setup_hotp(options)?;
109+
/// let setup_factor = setup::factors::hotp(options)?;
112110
/// let hotp = if let mfkdf2::definitions::FactorType::HOTP(ref h) = setup_factor.factor_type {
113111
/// h.clone()
114112
/// } else {
@@ -126,7 +124,7 @@ impl FactorDerive for HOTP {
126124
/// hotp.config.digits,
127125
/// );
128126
///
129-
/// let derive_factor = crate::derive::factors::hotp(code)?;
127+
/// let derive_factor = derive::factors::hotp(code)?;
130128
/// let derived_key = derive::key(
131129
/// &setup_key.policy,
132130
/// HashMap::from([("hotp".to_string(), derive_factor)]),
@@ -135,8 +133,7 @@ impl FactorDerive for HOTP {
135133
/// )?;
136134
///
137135
/// assert_eq!(derived_key.key, setup_key.key);
138-
/// # Ok(())
139-
/// # }
136+
/// # Ok::<(), mfkdf2::error::MFKDF2Error>(())
140137
/// ```
141138
pub fn hotp(code: u32) -> MFKDF2Result<MFKDF2Factor> {
142139
// Create HOTP factor with the user-provided code

mfkdf2/src/derive/factors/ooba.rs

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -103,17 +103,12 @@ impl FactorDerive for Ooba {
103103
/// # error::MFKDF2Result,
104104
/// # setup::{
105105
/// # self,
106-
/// # factors::ooba::{ooba as setup_ooba, OobaOptions},
106+
/// # factors::ooba::{OobaOptions},
107107
/// # },
108108
/// # definitions::MFKDF2Options,
109109
/// # derive,
110-
/// # derive::factors::ooba as derive_ooba,
111110
/// # };
112111
/// # use base64::Engine;
113-
/// # use sha2::Sha256;
114-
/// # use rsa::Oaep;
115-
/// #
116-
/// # fn main() -> MFKDF2Result<()> {
117112
/// let bits = 2048;
118113
/// let private_key =
119114
/// RsaPrivateKey::new(&mut rsa::rand_core::OsRng, bits).expect("failed to generate a key");
@@ -128,7 +123,7 @@ impl FactorDerive for Ooba {
128123
/// "e": e
129124
/// }))?;
130125
///
131-
/// let setup_factor = setup_ooba(OobaOptions {
126+
/// let setup_factor = setup::factors::ooba(OobaOptions {
132127
/// id: Some("ooba".into()),
133128
/// length: Some(8),
134129
/// key: Some(jwk),
@@ -141,11 +136,11 @@ impl FactorDerive for Ooba {
141136
/// setup_key.policy.factors.iter().find(|f| f.id == "ooba").unwrap();
142137
/// let setup_params = &policy_factor.params;
143138
/// let ciphertext = hex::decode(setup_params["next"].as_str().unwrap()).unwrap();
144-
/// let plaintext = private_key.decrypt(Oaep::new::<Sha256>(), &ciphertext).unwrap();
139+
/// let plaintext = private_key.decrypt(rsa::Oaep::new::<sha2::Sha256>(), &ciphertext).unwrap();
145140
/// let decoded: serde_json::Value = serde_json::from_slice(&plaintext).unwrap();
146141
/// let code = decoded["code"].as_str().unwrap();
147142
///
148-
/// let derive_factor = derive_ooba(code)?;
143+
/// let derive_factor = derive::factors::ooba(code)?;
149144
/// let derived_key = derive::key(
150145
/// &setup_key.policy,
151146
/// HashMap::from([("ooba".to_string(), derive_factor)]),
@@ -154,8 +149,7 @@ impl FactorDerive for Ooba {
154149
/// )?;
155150
///
156151
/// assert_eq!(derived_key.key, setup_key.key);
157-
/// # Ok(())
158-
/// # }
152+
/// # Ok::<(), mfkdf2::error::MFKDF2Error>(())
159153
/// ```
160154
pub fn ooba(code: &str) -> MFKDF2Result<MFKDF2Factor> {
161155
if code.is_empty() {
@@ -216,7 +210,7 @@ mod tests {
216210
params: Some(json!({"foo":"bar"})),
217211
};
218212

219-
let result = crate::setup::factors::ooba::ooba(options);
213+
let result = crate::setup::factors::ooba(options);
220214
assert!(result.is_ok());
221215

222216
result.unwrap()
@@ -328,7 +322,7 @@ mod tests {
328322
key: Some(jwk),
329323
params: Some(json!({"foo":"bar"})),
330324
};
331-
let setup = crate::setup::factors::ooba::ooba(options).unwrap();
325+
let setup = crate::setup::factors::ooba(options).unwrap();
332326

333327
// Setup for derive
334328
let setup_params = setup.factor_type.setup().params([0u8; 32].into()).unwrap();

0 commit comments

Comments
 (0)