Skip to content

Commit 18b70d7

Browse files
committed
add reconstitution docs
1 parent d2abb61 commit 18b70d7

26 files changed

Lines changed: 343 additions & 223 deletions

File tree

mfkdf2/README.md

Lines changed: 52 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ over time. It consists of two algorithms:
5959
Initializes the factor with a secret and produces a public state with initial key material.
6060

6161
```rust
62-
# use mfkdf2::setup::factors::password::{password, PasswordOptions};
63-
# use mfkdf2::setup::factors::totp::{totp, TOTPOptions};
62+
# use mfkdf2::setup::factors::{password, password::PasswordOptions};
63+
# use mfkdf2::setup::factors::{totp, totp::TOTPOptions};
6464
# use mfkdf2::error::MFKDF2Error;
6565
# let TOTP_SECRET = vec![0u8; 20];
6666
#
@@ -104,15 +104,16 @@ how a key is derived and ensures the key is the same every time (as long as the
104104
correct).
105105

106106
```rust
107-
# use mfkdf2::setup::factors::password::{password, PasswordOptions};
108-
# use mfkdf2::setup::factors::hmacsha1::{hmacsha1, HmacSha1Options};
109-
# use mfkdf2::setup::factors::hotp::{hotp, HOTPOptions};
110-
# use mfkdf2::setup::key::{key as setup_key, MFKDF2Options};
107+
# use mfkdf2::setup::factors::{password, password::PasswordOptions};
108+
# use mfkdf2::setup::factors::{hmacsha1, hmacsha1::HmacSha1Options};
109+
# use mfkdf2::setup::factors::{hotp, hotp::HOTPOptions};
110+
# use mfkdf2::setup;
111+
# use mfkdf2::definitions::MFKDF2Options;
111112
# use mfkdf2::error::MFKDF2Error;
112113
# let HOTP_SECRET = vec![0u8; 20];
113114
#
114115
// perform setup key
115-
let setup_derived_key = setup_key(
116+
let setup_derived_key = setup::key(
116117
&[
117118
password("password123", PasswordOptions::default()).expect("Failed to setup password factor"),
118119
hmacsha1(HmacSha1Options::default())?,
@@ -146,15 +147,16 @@ Derive a composite key with password, hmacsha1 and hotp factors. Derive returns
146147

147148
```rust
148149
# use std::collections::HashMap;
149-
# use mfkdf2::setup::factors::password::{password as setup_password, PasswordOptions};
150-
# use mfkdf2::setup::factors::hmacsha1::{hmacsha1 as setup_hmacsha1, HmacSha1Options};
151-
# use mfkdf2::setup::factors::hotp::{hotp as setup_hotp, HOTPOptions};
152-
# use mfkdf2::setup::key::{key as setup_key, MFKDF2Options};
153-
# use mfkdf2::derive::factors::password::password as derive_password;
154-
# use mfkdf2::derive::factors::hmacsha1::hmacsha1 as derive_hmacsha1;
155-
# use mfkdf2::derive::factors::hotp::hotp as derive_hotp;
150+
# use mfkdf2::setup::factors::{password as setup_password, password::PasswordOptions};
151+
# use mfkdf2::setup::factors::{hmacsha1 as setup_hmacsha1, hmacsha1::HmacSha1Options};
152+
# use mfkdf2::setup::factors::{hotp as setup_hotp, hotp::HOTPOptions};
153+
# use mfkdf2::setup;
154+
# use mfkdf2::derive::factors::password as derive_password;
155+
# use mfkdf2::derive::factors::hmacsha1 as derive_hmacsha1;
156+
# use mfkdf2::derive::factors::hotp as derive_hotp;
156157
# use mfkdf2::otpauth::generate_otp_token;
157-
# use mfkdf2::derive::key::key as derive_key;
158+
# use mfkdf2::derive;
159+
# use mfkdf2::definitions::MFKDF2Options;
158160
# use mfkdf2::error::MFKDF2Error;
159161
# use hmac::{Mac, Hmac};
160162
# use sha1::Sha1;
@@ -170,7 +172,7 @@ let setup_hotp_factor =
170172
setup_hotp(HOTPOptions { secret: Some(HOTP_SECRET.clone()), ..Default::default() })?;
171173

172174
// perform setup key
173-
let setup_derived_key = setup_key(
175+
let setup_derived_key = setup::key(
174176
&[setup_password_factor, setup_hmac_factor, setup_hotp_factor],
175177
MFKDF2Options::default(),
176178
)?;
@@ -204,7 +206,7 @@ let derive_hmac_factor = derive_hmacsha1(response.into())?;
204206
# let correct_code = generate_otp_token(&HOTP_SECRET, counter, &hash, digits);
205207
let derive_hotp_factor = derive_hotp(correct_code as u32)?;
206208

207-
let derived_key = derive_key(
209+
let derived_key = derive::key(
208210
&setup_derived_key.policy,
209211
HashMap::from([
210212
(String::from("password"), derive_password_factor),
@@ -237,15 +239,16 @@ recovery code. Any 2 of these 3 factors are sufficient to reproduce the key.
237239
# use std::collections::HashMap;
238240
#
239241
# use mfkdf2::error::MFKDF2Error;
240-
# use mfkdf2::setup::factors::password::{password as setup_password, PasswordOptions};
241-
# use mfkdf2::setup::factors::hotp::{hotp as setup_hotp, HOTPOptions};
242-
# use mfkdf2::setup::factors::uuid::{uuid as setup_uuid, UUIDOptions};
243-
# use mfkdf2::setup::key::{key as setup_key, MFKDF2Options};
244-
# use mfkdf2::derive::factors::hotp::hotp as derive_hotp;
245-
# use mfkdf2::derive::factors::uuid::uuid as derive_uuid;
246-
# use mfkdf2::derive::key::key as derive_key;
247-
# use mfkdf2::otpauth::{generate_otp_token as generate_hotp_code, HashAlgorithm};
242+
# use mfkdf2::setup;
248243
# use mfkdf2::setup::FactorSetup;
244+
# use mfkdf2::setup::factors::{password as setup_password, password::PasswordOptions};
245+
# use mfkdf2::setup::factors::{hotp as setup_hotp, hotp::HOTPOptions};
246+
# use mfkdf2::setup::factors::{uuid as setup_uuid, uuid::UUIDOptions};
247+
# use mfkdf2::derive::factors::hotp as derive_hotp;
248+
# use mfkdf2::derive::factors::uuid as derive_uuid;
249+
# use mfkdf2::derive;
250+
# use mfkdf2::otpauth::{generate_otp_token as generate_hotp_code, HashAlgorithm};
251+
# use mfkdf2::definitions::MFKDF2Options;
249252
# use uuid::Uuid;
250253
#
251254
// setup phase: construct factors
@@ -264,7 +267,7 @@ let setup_uuid_factor =
264267

265268
// configure a 2‑of‑3 threshold policy
266269
let options = MFKDF2Options { threshold: Some(2), ..MFKDF2Options::default() };
267-
let setup_derived = setup_key(&[password_factor, setup_hotp_factor, setup_uuid_factor], options)?;
270+
let setup_derived = setup::key(&[password_factor, setup_hotp_factor, setup_uuid_factor], options)?;
268271

269272
// derive phase: build inputs for any 2 factors
270273
let policy_hotp_factor: &mfkdf2::policy::PolicyFactor = setup_derived
@@ -294,7 +297,7 @@ derive_uuid_factor.id = Some("uuid".to_string());
294297
derive_factors.insert("uuid".to_string(), derive_uuid_factor);
295298

296299
// only 2 out of the 3 factors are provided here
297-
let derived = derive_key(&setup_derived.policy, derive_factors, true, false)?;
300+
let derived = derive::key(&setup_derived.policy, derive_factors, true, false)?;
298301
assert_eq!(derived.key, setup_derived.key);
299302
# Ok::<(), mfkdf2::error::MFKDF2Error>(())
300303
```
@@ -304,12 +307,13 @@ Threshold value must be between 1 and the number of factors, otherwise
304307

305308
```rust
306309
# use mfkdf2::error::{MFKDF2Error, MFKDF2Result};
307-
# use mfkdf2::setup::factors::password::{password, PasswordOptions};
308-
# use mfkdf2::setup::key::{key as setup_key, MFKDF2Options};
310+
# use mfkdf2::setup::factors::{password, password::PasswordOptions};
311+
# use mfkdf2::setup;
312+
# use mfkdf2::definitions::MFKDF2Options;
309313
#
310314
// requesting 2‑of‑1 factors causes MFKDF2Error::InvalidThreshold
311315
let result =
312-
setup_key(&[password("password123", PasswordOptions::default())?], MFKDF2Options { threshold: Some(2), ..MFKDF2Options::default() });
316+
setup::key(&[password("password123", PasswordOptions::default())?], MFKDF2Options { threshold: Some(2), ..MFKDF2Options::default() });
313317
assert!(matches!(result, Err(MFKDF2Error::InvalidThreshold)));
314318
# Ok::<(), mfkdf2::error::MFKDF2Error>(())
315319
```
@@ -321,27 +325,28 @@ If insufficient factors are provided, share recovery fails and
321325
# use std::collections::HashMap;
322326
#
323327
# use mfkdf2::error::{MFKDF2Error, MFKDF2Result};
324-
# use mfkdf2::setup::factors::password::{password as setup_password, PasswordOptions};
325-
# use mfkdf2::setup::key::{key as setup_key, MFKDF2Options};
326-
# use mfkdf2::derive::factors::password::password as derive_password;
327-
# use mfkdf2::derive::key::key as derive_key;
328+
# use mfkdf2::setup::factors::{password as setup_password, password::PasswordOptions};
329+
# use mfkdf2::setup;
330+
# use mfkdf2::definitions::MFKDF2Options;
331+
# use mfkdf2::derive::factors::password as derive_password;
332+
# use mfkdf2::derive;
328333
#
329334
// setup phase with a 2‑of‑2 password policy
330335
let setup_factors = &[
331336
setup_password("primary‑password", PasswordOptions { id: Some("pw1".into()) })?,
332337
setup_password("backup‑password", PasswordOptions { id: Some("pw2".into()) })?,
333338
];
334339
let options = MFKDF2Options { threshold: Some(2), ..MFKDF2Options::default() };
335-
let setup_derived = setup_key(setup_factors, options)?;
340+
let setup_derived = setup::key(setup_factors, options)?;
336341

337342
// derive phase provides only one out of the two required factors
338343
let mut derive_factors = HashMap::new();
339344
let mut derive_pw1 = derive_password("primary‑password")?;
340345
derive_pw1.id = Some("pw1".into());
341346
derive_factors.insert("pw1".into(), derive_pw1);
342347

343-
let result = derive_key(&setup_derived.policy, derive_factors, true, false);
344-
assert!(matches!(result, Err(MFKDF2Error::ShareRecoveryError)));
348+
let result = derive::key(&setup_derived.policy, derive_factors, true, false);
349+
assert!(matches!(result, Err(MFKDF2Error::ShareRecovery)));
345350
# Ok::<(), mfkdf2::error::MFKDF2Error>(())
346351
```
347352

@@ -368,12 +373,13 @@ policy between the stack and a third password:
368373
# use std::collections::HashMap;
369374
#
370375
# use mfkdf2::error::MFKDF2Error;
371-
# use mfkdf2::setup::factors::password::{password as setup_password, PasswordOptions};
372-
# use mfkdf2::setup::factors::stack::{stack as setup_stack, StackOptions};
373-
# use mfkdf2::setup::key::{key as setup_key, MFKDF2Options};
374-
# use mfkdf2::derive::factors::password::password as derive_password;
375-
# use mfkdf2::derive::factors::stack::stack as derive_stack;
376-
# use mfkdf2::derive::key::key as derive_key;
376+
# use mfkdf2::setup::factors::{password as setup_password, password::PasswordOptions};
377+
# use mfkdf2::setup::factors::{stack as setup_stack, stack::StackOptions};
378+
# use mfkdf2::setup;
379+
# use mfkdf2::derive::factors::password as derive_password;
380+
# use mfkdf2::derive::factors::stack as derive_stack;
381+
# use mfkdf2::derive;
382+
# use mfkdf2::definitions::MFKDF2Options;
377383
#
378384
// inner stack: password₁ ∧ password₂
379385
let inner = vec![
@@ -390,7 +396,7 @@ let stacked = setup_stack(inner, StackOptions {
390396
// outer policy: (password₁ ∧ password₂) ∨ password₃
391397
let password3 = setup_password("password3", PasswordOptions { id: Some("password3".into()) })?;
392398

393-
let setup_derived = setup_key(&[stacked, password3], MFKDF2Options {
399+
let setup_derived = setup::key(&[stacked, password3], MFKDF2Options {
394400
threshold: Some(1),
395401
..MFKDF2Options::default()
396402
})?;
@@ -401,7 +407,7 @@ let derive_stack_factor = derive_stack(HashMap::from([
401407
("password2".to_string(), derive_password("password2")?),
402408
]))?;
403409

404-
let derived = derive_key(
410+
let derived = derive::key(
405411
&setup_derived.policy,
406412
HashMap::from([("stack".to_string(), derive_stack_factor)]),
407413
false,
@@ -413,7 +419,7 @@ let derived = derive_key(
413419
```
414420

415421
The same outer key can also be derived with only `password3` by supplying a single password
416-
factor keyed by `"password3"` to [setup key](`crate::derive::key::key`).
422+
factor keyed by `"password3"` to [setup key](`crate::derive::key`).
417423

418424
# Feature Flags
419425

mfkdf2/src/definitions/mfkdf_derived_key/mod.rs

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,37 @@ use crate::{
99
policy::Policy,
1010
};
1111

12-
pub mod crypto;
12+
mod crypto;
1313
pub mod hints;
1414
pub mod mfdpg;
15-
pub mod persistence;
15+
mod persistence;
1616
pub mod reconstitution;
17-
pub mod strengthening;
17+
mod strengthening;
1818

19-
/// MFKDF2 derived key.
19+
/// MFKDF2 Derived key after the setup or derive operation.
20+
///
21+
/// An [`MFKDF2DerivedKey`] bundles the static derived key material together with the resolved
22+
/// [`Policy`] and auxiliary metadata needed for threshold recovery and factor management.
23+
/// It is produced by the MFKDF2 setup and derive algorithms (see [`crate::setup::key`] and
24+
/// [`crate::derive::key`]).
2025
#[cfg_attr(feature = "bindings", derive(uniffi::Record))]
2126
#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)]
2227
pub struct MFKDF2DerivedKey {
28+
/// Authentication policy describing factors, threshold, and integrity configuration associated
29+
/// with this key.
2330
pub policy: Policy,
31+
/// Final 32‑byte key output of the KDF
2432
pub key: Key,
33+
/// Internal secret material that is split into per‑factor shares for threshold recovery
2534
pub secret: Vec<u8>,
35+
/// Shamir‑style shares of `secret`, one per factor, used by reconstitution and
36+
/// threshold‑management routines.
2637
pub shares: Vec<Vec<u8>>,
38+
/// Per‑factor public outputs produced during setup or derive (such as strength metrics or
39+
/// factor‑specific metadata).
2740
pub outputs: HashMap<String, Value>,
41+
/// Measured and theoretical entropy estimates for the derived key, useful for auditing and
42+
/// security analysis.
2843
pub entropy: MFKDF2Entropy,
2944
}
3045

0 commit comments

Comments
 (0)