1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
//! `crypto_kdf` equivalent (`docs/dstu-crypto-project.md` "Mapping onto the libsodium API",
//! `docs/TASKS.md` T-105, roadmap Step 3 item 2 - `docs/DECISIONS.md` D-66) - a thin libsodium-ergonomics
//! wrapper over [`Kupyna256Kdf`],
//! matching [`crate::crypto_auth`]'s reasoning exactly: only the 256-bit variant is exposed here
//! (D-47's "delete the knob", same as `crypto_auth`'s choice among `Kupyna{256,384,512}Kmac`; the
//! other two sizes stay available at `hazmat::kupyna_kdf`), and the master key is an opaque,
//! `Zeroize`-on-drop [`MasterKey`] type rather than a raw `[u8; 32]`.
//!
//! Unlike `crypto_auth`, there is no error to foreclose either way: `hazmat::kupyna_kdf::
//! Kupyna256Kdf::derive_subkey` is already infallible (fixed-length arrays in, fixed-length array
//! out, no key-length check to fail). [`MasterKey`] adds `Zeroize`-on-drop and an OS-CSPRNG
//! `generate()`, matching `crypto_secretbox`'s `SecretKey`/`crypto_auth`'s `Key` precedent, not a
//! change in fallibility.
//!
//! Provenance is otherwise identical to the `hazmat` layer: no DSTU standard or reference
//! implementation of "a KDF using Kupyna" exists anywhere, so - unlike every other module in this
//! crate - there is no oracle vector for this construction, ever (D-45); verification is
//! determinism/distinctness property tests only, inherited unchanged from `hazmat::kupyna_kdf`.
//!
//! # Example
//!
//! Derives many independent-looking subkeys from one master key, instead of generating and storing
//! a fresh random key per purpose - useful when you want, say, a separate encryption key and MAC
//! key derived from one secret rather than managing two unrelated secrets.
//!
//! ```rust
//! use dstu_core::crypto_kdf::MasterKey;
//!
//! let master_key = MasterKey::generate().expect("OS CSPRNG should not fail");
//!
//! let encryption_subkey = master_key.derive_subkey(0, b"encrypt_");
//! let mac_subkey = master_key.derive_subkey(1, b"mac_key_");
//!
//! // Different subkey_id (holding context fixed) gives a different, unrelated-looking subkey.
//! assert_ne!(encryption_subkey, mac_subkey);
//! // Deterministic: the same id/context always re-derives the same subkey.
//! assert_eq!(encryption_subkey, master_key.derive_subkey(0, b"encrypt_"));
//! ```
use crateKupyna256Kdf;
use Zeroize;
/// A `crypto_kdf` master key. Always exactly 32 bytes - [`Kupyna256Kdf`]'s fixed key length (see
/// the module doc).
;