askar_storage/protect/
store_key.rs

1use super::kdf::KdfMethod;
2
3use super::pass_key::PassKey;
4use crate::{
5    crypto::{
6        alg::chacha20::{Chacha20Key, C20P},
7        buffer::{ArrayKey, ResizeBuffer, SecretBytes},
8        encrypt::{KeyAeadInPlace, KeyAeadMeta},
9        random::RandomDet,
10        repr::{KeyGen, KeyMeta, KeySecretBytes},
11    },
12    error::Error,
13};
14
15pub const PREFIX_KDF: &str = "kdf";
16pub const PREFIX_RAW: &str = "raw";
17pub const PREFIX_NONE: &str = "none";
18
19pub type StoreKeyType = Chacha20Key<C20P>;
20
21type StoreKeyNonce = ArrayKey<<StoreKeyType as KeyAeadMeta>::NonceSize>;
22
23/// Create a new raw (non-derived) store key
24pub fn generate_raw_store_key(seed: Option<&[u8]>) -> Result<PassKey<'static>, Error> {
25    let key = if let Some(seed) = seed {
26        StoreKey::from(StoreKeyType::generate(RandomDet::new(seed))?)
27    } else {
28        StoreKey::from(StoreKeyType::random()?)
29    };
30    Ok(key.to_passkey())
31}
32
33pub fn parse_raw_store_key(raw_key: &str) -> Result<StoreKey, Error> {
34    ArrayKey::<<StoreKeyType as KeyMeta>::KeySize>::temp(|key| {
35        let key_len = bs58::decode(raw_key)
36            .onto(key.as_mut_slice())
37            .map_err(|_| err_msg!(Input, "Error parsing raw key as base58 value"))?;
38        if key_len != key.len() {
39            Err(err_msg!(Input, "Incorrect length for encoded raw key"))
40        } else {
41            Ok(StoreKey::from(StoreKeyType::from_secret_bytes(&*key)?))
42        }
43    })
44}
45
46#[derive(Clone, Debug)]
47pub struct StoreKey(pub Option<StoreKeyType>);
48
49impl StoreKey {
50    pub const fn empty() -> Self {
51        Self(None)
52    }
53
54    pub fn random() -> Result<Self, Error> {
55        Ok(Self(Some(StoreKeyType::random()?)))
56    }
57
58    #[allow(unused)]
59    pub fn is_empty(&self) -> bool {
60        self.0.is_none()
61    }
62
63    pub fn wrap_data(&self, mut data: SecretBytes) -> Result<Vec<u8>, Error> {
64        match &self.0 {
65            Some(key) => {
66                let nonce = StoreKeyNonce::random();
67                key.encrypt_in_place(&mut data, nonce.as_ref(), &[])?;
68                data.buffer_insert(0, nonce.as_ref())?;
69                Ok(data.into_vec())
70            }
71            None => Ok(data.into_vec()),
72        }
73    }
74
75    pub fn unwrap_data(&self, ciphertext: Vec<u8>) -> Result<SecretBytes, Error> {
76        match &self.0 {
77            Some(key) => {
78                let nonce = StoreKeyNonce::from_slice(&ciphertext[..StoreKeyNonce::SIZE]);
79                let mut buffer = SecretBytes::from(ciphertext);
80                buffer.buffer_remove(0..StoreKeyNonce::SIZE)?;
81                key.decrypt_in_place(&mut buffer, nonce.as_ref(), &[])?;
82                Ok(buffer)
83            }
84            None => Ok(ciphertext.into()),
85        }
86    }
87
88    pub fn to_passkey(&self) -> PassKey<'static> {
89        if let Some(key) = self.0.as_ref() {
90            PassKey::from(key.with_secret_bytes(|sk| bs58::encode(sk.unwrap()).into_string()))
91        } else {
92            PassKey::empty()
93        }
94    }
95}
96
97impl From<StoreKeyType> for StoreKey {
98    fn from(data: StoreKeyType) -> Self {
99        Self(Some(data))
100    }
101}
102
103/// Supported methods for generating or referencing a new store key
104#[derive(Clone, Debug, PartialEq, Eq, Hash)]
105pub enum StoreKeyMethod {
106    // CreateManagedKey(String),
107    // ExistingManagedKey(String),
108    /// Derive a new wrapping key using a key derivation function
109    DeriveKey(KdfMethod),
110    /// Wrap using an externally-managed raw key
111    RawKey,
112    /// No wrapping key in effect
113    Unprotected,
114}
115
116impl StoreKeyMethod {
117    /// Parse a URI string into a store key method
118    pub fn parse_uri(uri: &str) -> Result<Self, Error> {
119        let mut prefix_and_detail = uri.splitn(2, ':');
120        let prefix = prefix_and_detail.next().unwrap_or_default();
121        // let detail = prefix_and_detail.next().unwrap_or_default();
122        match prefix {
123            PREFIX_RAW => Ok(Self::RawKey),
124            PREFIX_KDF => {
125                let (method, _) = KdfMethod::decode(uri)?;
126                Ok(Self::DeriveKey(method))
127            }
128            PREFIX_NONE => Ok(Self::Unprotected),
129            _ => Err(err_msg!(Unsupported, "Invalid store key method")),
130        }
131    }
132
133    pub(crate) fn resolve(
134        &self,
135        pass_key: PassKey<'_>,
136    ) -> Result<(StoreKey, StoreKeyReference), Error> {
137        match self {
138            // Self::CreateManagedKey(_mgr_ref) => unimplemented!(),
139            // Self::ExistingManagedKey(String) => unimplemented!(),
140            Self::DeriveKey(method) => {
141                if !pass_key.is_none() {
142                    let (key, detail) = method.derive_new_key(&pass_key)?;
143                    let key_ref = StoreKeyReference::DeriveKey(*method, detail);
144                    Ok((key, key_ref))
145                } else {
146                    Err(err_msg!(Input, "Key derivation password not provided"))
147                }
148            }
149            Self::RawKey => {
150                let key = if !pass_key.is_empty() {
151                    parse_raw_store_key(&pass_key)?
152                } else {
153                    StoreKey::random()?
154                };
155                Ok((key, StoreKeyReference::RawKey))
156            }
157            Self::Unprotected => Ok((StoreKey::empty(), StoreKeyReference::Unprotected)),
158        }
159    }
160}
161
162impl Default for StoreKeyMethod {
163    fn default() -> Self {
164        Self::DeriveKey(KdfMethod::Argon2i(Default::default()))
165    }
166}
167
168impl From<StoreKeyReference> for StoreKeyMethod {
169    fn from(key_ref: StoreKeyReference) -> Self {
170        match key_ref {
171            StoreKeyReference::DeriveKey(method, _) => Self::DeriveKey(method),
172            StoreKeyReference::RawKey => Self::RawKey,
173            StoreKeyReference::Unprotected => Self::Unprotected,
174        }
175    }
176}
177
178#[derive(Clone, Debug, PartialEq, Eq, Hash)]
179pub enum StoreKeyReference {
180    // ManagedKey(String),
181    DeriveKey(KdfMethod, String),
182    RawKey,
183    Unprotected,
184}
185
186impl StoreKeyReference {
187    pub fn parse_uri(uri: &str) -> Result<Self, Error> {
188        let mut prefix_and_detail = uri.splitn(2, ':');
189        let prefix = prefix_and_detail.next().unwrap_or_default();
190        match prefix {
191            PREFIX_RAW => Ok(Self::RawKey),
192            PREFIX_KDF => {
193                let (method, detail) = KdfMethod::decode(uri)?;
194                Ok(Self::DeriveKey(method, detail))
195            }
196            PREFIX_NONE => Ok(Self::Unprotected),
197            _ => Err(err_msg!(
198                Unsupported,
199                "Invalid store key method for reference"
200            )),
201        }
202    }
203
204    pub fn compare_method(&self, method: &StoreKeyMethod) -> bool {
205        match self {
206            // Self::ManagedKey(_keyref) => matches!(method, WrapKeyMethod::CreateManagedKey(..)),
207            Self::DeriveKey(kdf_method, _detail) => {
208                matches!(method, StoreKeyMethod::DeriveKey(m) if m == kdf_method)
209            }
210            Self::RawKey => *method == StoreKeyMethod::RawKey,
211            Self::Unprotected => *method == StoreKeyMethod::Unprotected,
212        }
213    }
214
215    pub fn into_uri(self) -> String {
216        match self {
217            // Self::ManagedKey(keyref) => keyref,
218            Self::DeriveKey(method, detail) => method.encode(Some(detail.as_str())),
219            Self::RawKey => PREFIX_RAW.to_string(),
220            Self::Unprotected => PREFIX_NONE.to_string(),
221        }
222    }
223
224    pub fn resolve(&self, pass_key: PassKey<'_>) -> Result<StoreKey, Error> {
225        match self {
226            // Self::ManagedKey(_key_ref) => unimplemented!(),
227            Self::DeriveKey(method, detail) => {
228                if !pass_key.is_none() {
229                    method.derive_key(&pass_key, detail)
230                } else {
231                    Err(err_msg!(Input, "Key derivation password not provided"))
232                }
233            }
234            Self::RawKey => {
235                if !pass_key.is_empty() {
236                    parse_raw_store_key(&pass_key)
237                } else {
238                    Err(err_msg!(Input, "Encoded raw key not provided"))
239                }
240            }
241            Self::Unprotected => Ok(StoreKey::empty()),
242        }
243    }
244}
245
246#[cfg(test)]
247mod tests {
248    use super::*;
249    use crate::error::ErrorKind;
250
251    #[test]
252    fn protection_method_parse() {
253        let parse = StoreKeyMethod::parse_uri;
254        assert_eq!(parse("none"), Ok(StoreKeyMethod::Unprotected));
255        assert_eq!(parse("raw"), Ok(StoreKeyMethod::RawKey));
256        assert_eq!(
257            parse("kdf:argon2i"),
258            Ok(StoreKeyMethod::DeriveKey(KdfMethod::Argon2i(
259                Default::default()
260            )))
261        );
262        assert_eq!(
263            parse("other:method:etc").unwrap_err().kind(),
264            ErrorKind::Unsupported
265        );
266    }
267
268    #[test]
269    fn derived_key_wrap() {
270        let input = b"test data";
271        let pass = PassKey::from("pass");
272        let (key, key_ref) = StoreKeyMethod::DeriveKey(KdfMethod::Argon2i(Default::default()))
273            .resolve(pass.as_ref())
274            .expect("Error deriving new key");
275        assert!(!key.is_empty());
276        let wrapped = key
277            .wrap_data((&input[..]).into())
278            .expect("Error wrapping input");
279        assert_ne!(wrapped, &input[..]);
280        let unwrapped = key.unwrap_data(wrapped).expect("Error unwrapping data");
281        assert_eq!(unwrapped, &input[..]);
282        let key_uri = key_ref.into_uri();
283        assert!(key_uri.starts_with("kdf:argon2i:13:mod?salt="));
284    }
285
286    #[test]
287    fn derived_key_unwrap_expected() {
288        let input = b"test data";
289        let wrapped = Vec::from(hex!(
290            "c29c66fde50b30b8a077da1ea9bcf4dfeb5fabea12050973aed0e8251f20fad8205cfd2dec"
291        ));
292        let pass = PassKey::from("pass");
293        let key_ref = StoreKeyReference::parse_uri(
294            "kdf:argon2i:13:mod?salt=a553cfb9c558b5c11c78efcfa06f3e29",
295        )
296        .expect("Error parsing derived key ref");
297        let key = key_ref.resolve(pass).expect("Error deriving existing key");
298        let unwrapped = key.unwrap_data(wrapped).expect("Error unwrapping data");
299        assert_eq!(unwrapped, &input[..]);
300    }
301
302    #[test]
303    fn derived_key_check_bad_password() {
304        let wrapped = Vec::from(hex!(
305            "c29c66fde50b30b8a077da1ea9bcf4dfeb5fabea12050973aed0e8251f20fad8205cfd2dec"
306        ));
307        let key_ref = StoreKeyReference::parse_uri(
308            "kdf:argon2i:13:mod?salt=a553cfb9c558b5c11c78efcfa06f3e29",
309        )
310        .expect("Error parsing derived key ref");
311        let check_bad_pass = key_ref
312            .resolve("not my pass".into())
313            .expect("Error deriving comparison key");
314        let unwrapped_err = check_bad_pass.unwrap_data(wrapped);
315        assert!(unwrapped_err.is_err());
316    }
317
318    #[test]
319    fn raw_key_seed_lengths() {
320        // 'short' is less than 32 bytes
321        let _ = generate_raw_store_key(Some(b"short key"))
322            .expect("Error creating raw key from short seed");
323        // 'long' is greater than 32 bytes
324        let _ = generate_raw_store_key(Some(
325            b"long key long key long key long key long key long key long key",
326        ))
327        .expect("Error creating raw key from long seed");
328    }
329
330    #[test]
331    fn raw_key_wrap() {
332        let input = b"test data";
333        let raw_key = generate_raw_store_key(None).unwrap();
334
335        let (key, key_ref) = StoreKeyMethod::RawKey
336            .resolve(raw_key.as_ref())
337            .expect("Error resolving raw key");
338        assert!(!key.is_empty());
339        let wrapped = key
340            .wrap_data((&input[..]).into())
341            .expect("Error wrapping input");
342        assert_ne!(wrapped, &input[..]);
343
344        // round trip the key reference
345        let key_uri = key_ref.into_uri();
346        let key_ref = StoreKeyReference::parse_uri(&key_uri).expect("Error parsing raw key URI");
347        let key = key_ref.resolve(raw_key).expect("Error resolving raw key");
348
349        let unwrapped = key.unwrap_data(wrapped).expect("Error unwrapping data");
350        assert_eq!(unwrapped, &input[..]);
351
352        let check_no_key = key_ref.resolve(None.into());
353        assert!(check_no_key.is_err());
354
355        let check_bad_key = key_ref.resolve("not the key".into());
356        assert!(check_bad_key.is_err());
357    }
358
359    #[test]
360    fn unprotected_wrap() {
361        let input = b"test data";
362        let (key, key_ref) = StoreKeyMethod::Unprotected
363            .resolve(None.into())
364            .expect("Error resolving unprotected");
365        assert!(key.is_empty());
366        let wrapped = key
367            .wrap_data((&input[..]).into())
368            .expect("Error wrapping unprotected");
369        assert_eq!(wrapped, &input[..]);
370
371        // round trip the key reference
372        let key_uri = key_ref.into_uri();
373        let key_ref =
374            StoreKeyReference::parse_uri(&key_uri).expect("Error parsing unprotected key ref");
375        let key = key_ref
376            .resolve(None.into())
377            .expect("Error resolving unprotected key ref");
378
379        let unwrapped = key
380            .unwrap_data(wrapped)
381            .expect("Error unwrapping unprotected");
382        assert_eq!(unwrapped, &input[..]);
383    }
384}