dryoc/kdf.rs
1//! # Key derivation functions
2//!
3//! [`Kdf`] implements libsodium's key derivation functions, based on the
4//! Blake2b hash function.
5//!
6//! You should use [`Kdf`] when you want to:
7//!
8//! * create many subkeys from a main key, without having to risk leaking the
9//! main key
10//! * ensure that if a subkey were to become compromised, one could not derive
11//! the main key
12//!
13//! # Rustaceous API example
14//!
15//! ```
16//! use base64::Engine as _;
17//! use base64::engine::general_purpose;
18//! use dryoc::kdf::*;
19//!
20//! // Randomly generate a main key and context, using the default stack-allocated
21//! // types
22//! let key = Kdf::gen_with_defaults();
23//! let subkey_id = 0;
24//!
25//! let subkey = key.derive_subkey_to_vec(subkey_id).expect("derive failed");
26//! println!(
27//! "Subkey {}: {}",
28//! subkey_id,
29//! general_purpose::STANDARD.encode(&subkey)
30//! );
31//! ```
32//!
33//! ## Additional resources
34//!
35//! * See <https://doc.libsodium.org/key_derivation> for additional details on
36//! key derivation
37
38#[cfg(feature = "serde")]
39use serde::{Deserialize, Serialize};
40use zeroize::Zeroize;
41
42use crate::classic::crypto_kdf::crypto_kdf_derive_from_key;
43use crate::constants::{CRYPTO_KDF_CONTEXTBYTES, CRYPTO_KDF_KEYBYTES};
44use crate::error::Error;
45use crate::types::*;
46
47/// Stack-allocated key type alias for key derivation with [`Kdf`].
48pub type Key = StackByteArray<CRYPTO_KDF_KEYBYTES>;
49/// Stack-allocated context type alias for key derivation with [`Kdf`].
50pub type Context = StackByteArray<CRYPTO_KDF_CONTEXTBYTES>;
51
52#[cfg_attr(
53 feature = "serde",
54 derive(Zeroize, Clone, Debug, Serialize, Deserialize)
55)]
56#[cfg_attr(not(feature = "serde"), derive(Zeroize, Clone, Debug))]
57/// Key derivation implementation based on Blake2b, compatible with libsodium's
58/// `crypto_kdf_*` functions.
59pub struct Kdf<
60 Key: ByteArray<CRYPTO_KDF_KEYBYTES> + Zeroize,
61 Context: ByteArray<CRYPTO_KDF_CONTEXTBYTES> + Zeroize,
62> {
63 main_key: Key,
64 context: Context,
65}
66
67/// Stack-allocated type alias for [`Kdf`]. Provided for convenience.
68pub type StackKdf = Kdf<Key, Context>;
69
70#[cfg(any(feature = "nightly", all(doc, not(doctest))))]
71#[cfg_attr(all(feature = "nightly", doc), doc(cfg(feature = "nightly")))]
72pub mod protected {
73 //! # Protected memory type aliases for [`Kdf`]
74 //!
75 //! This mod provides re-exports of type aliases for protected memory usage
76 //! with [`Kdf`]. These type aliases are provided for
77 //! convenience.
78 //!
79 //! ## Example
80 //!
81 //! ```
82 //! use base64::Engine as _;
83 //! use base64::engine::general_purpose;
84 //! use dryoc::kdf::Kdf;
85 //! use dryoc::kdf::protected::*;
86 //!
87 //! // Randomly generate a main key and context, using locked memory
88 //! let key: LockedKdf = Kdf::gen();
89 //! let subkey_id = 0;
90 //!
91 //! let subkey: Locked<Key> = key.derive_subkey(subkey_id).expect("derive failed");
92 //! println!(
93 //! "Subkey {}: {}",
94 //! subkey_id,
95 //! general_purpose::STANDARD.encode(&subkey)
96 //! );
97 //! ```
98 use super::*;
99 pub use crate::protected::*;
100
101 /// Heap-allocated, page-aligned key type alias for key derivation with
102 /// [`Kdf`].
103 pub type Key = HeapByteArray<CRYPTO_KDF_KEYBYTES>;
104 /// Heap-allocated, page-aligned context type alias for key derivation with
105 /// [`Kdf`].
106 pub type Context = HeapByteArray<CRYPTO_KDF_CONTEXTBYTES>;
107
108 /// Locked [`Kdf`], provided as a type alias for convenience.
109 pub type LockedKdf = Kdf<Locked<Key>, Locked<Context>>;
110}
111
112impl<
113 Key: NewByteArray<CRYPTO_KDF_KEYBYTES> + Zeroize,
114 Context: NewByteArray<CRYPTO_KDF_CONTEXTBYTES> + Zeroize,
115> Kdf<Key, Context>
116{
117 /// Randomly generates a new pair of main key and context.
118 pub fn gen() -> Self {
119 Self {
120 main_key: Key::gen(),
121 context: Context::gen(),
122 }
123 }
124}
125
126impl<
127 Key: ByteArray<CRYPTO_KDF_KEYBYTES> + Zeroize,
128 Context: ByteArray<CRYPTO_KDF_CONTEXTBYTES> + Zeroize,
129> Kdf<Key, Context>
130{
131 /// Derives a subkey for `subkey_id`, returning it.
132 pub fn derive_subkey<Subkey: NewByteArray<CRYPTO_KDF_KEYBYTES>>(
133 &self,
134 subkey_id: u64,
135 ) -> Result<Subkey, Error> {
136 let mut subkey = Subkey::new_byte_array();
137 crypto_kdf_derive_from_key(
138 subkey.as_mut_array(),
139 subkey_id,
140 self.context.as_array(),
141 self.main_key.as_array(),
142 )?;
143 Ok(subkey)
144 }
145
146 /// Derives a subkey for `subkey_id`, returning it as a [`Vec`]. Provided
147 /// for convenience.
148 pub fn derive_subkey_to_vec(&self, subkey_id: u64) -> Result<Vec<u8>, Error> {
149 self.derive_subkey(subkey_id)
150 }
151
152 /// Constructs a new instance from `key` and `context`, consuming them both.
153 pub fn from_parts(main_key: Key, context: Context) -> Self {
154 Self { main_key, context }
155 }
156
157 /// Moves the key and context out of this instance, returning them as a
158 /// tuple.
159 pub fn into_parts(self) -> (Key, Context) {
160 (self.main_key, self.context)
161 }
162}
163
164impl Kdf<Key, Context> {
165 /// Randomly generates a new pair of main key and context.
166 pub fn gen_with_defaults() -> Self {
167 Self {
168 main_key: Key::gen(),
169 context: Context::gen(),
170 }
171 }
172}
173
174#[cfg(test)]
175mod tests {
176 use super::*;
177
178 #[test]
179 fn test_kdf() {
180 let key = StackKdf::gen();
181
182 let _subkey = key.derive_subkey_to_vec(0).expect("derive failed");
183 }
184}