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
23pub 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#[derive(Clone, Debug, PartialEq, Eq, Hash)]
105pub enum StoreKeyMethod {
106 DeriveKey(KdfMethod),
110 RawKey,
112 Unprotected,
114}
115
116impl StoreKeyMethod {
117 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 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::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 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::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::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::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 let _ = generate_raw_store_key(Some(b"short key"))
322 .expect("Error creating raw key from short seed");
323 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 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 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}