seed_keeper_core/
lib.rs

1// include readme
2#![doc = include_str!("../README.md")]
3
4pub mod error;
5pub mod seed;
6pub mod wrap;
7
8pub use argon2::Error;
9use std::ops::Deref;
10pub use zeroize::Zeroizing;
11
12use argon2::Argon2;
13
14/// Use [Input] if you want to persist state of the passphrase and salt.
15///
16/// If you are looking for a one-time use, use [derive_key] function instead.
17pub struct Input {
18    passphrase: Zeroizing<Vec<u8>>,
19    salt: Zeroizing<Vec<u8>>,
20}
21
22impl Input {
23    /// Takes any password an salt inputs which derefs into [u8]
24    pub fn new(pwd: impl AsRef<[u8]>, salt: impl AsRef<[u8]>) -> Self {
25        Self {
26            passphrase: Zeroizing::new(pwd.as_ref().to_vec()),
27            salt: Zeroizing::new(salt.as_ref().to_vec()),
28        }
29    }
30
31    /// Generates and returns a [u8; 32], wrapped in [Zeroizing]
32    /// Generate output key material using Argon2 passwrod hashing
33    /// Function generates a [u8; 32] directly from a password and salt
34    ///
35    /// Password must be a minimum of 8 bytes
36    /// Salt ust be a minimum of 4 bytes long
37    ///
38    /// Otherwise, an Argon2 [Error] is returned
39    pub fn derive_key(&self) -> Result<Zeroizing<[u8; 32]>, Error> {
40        let mut output_key_material = Zeroizing::new([0u8; 32]);
41        Argon2::default().hash_password_into(
42            self.passphrase.deref(),
43            self.salt.deref(),
44            &mut *output_key_material,
45        )?;
46
47        Ok(output_key_material)
48    }
49}
50
51/// Generate output key material using Argon2 passwrod hashing
52/// Function generates a [Seed] directly from a password and salt
53///
54/// Password must be a minimum of 8 bytes
55/// Salt ust be a minimum of 4 bytes long
56///
57/// Otherwise, an Argon2 [Error] is returned
58pub fn derive_key(
59    pwd: impl AsRef<[u8]>,
60    salt: impl AsRef<[u8]>,
61) -> Result<Zeroizing<[u8; 32]>, Error> {
62    let mut output_key_material = Zeroizing::new([0u8; 32]); // default size is 32 bytes
63
64    Argon2::default().hash_password_into(pwd.as_ref(), salt.as_ref(), &mut *output_key_material)?;
65
66    Ok(output_key_material)
67}
68
69#[cfg(test)]
70mod tests {
71    use super::*;
72    use seed::Seed;
73
74    #[test]
75    fn it_works() -> Result<(), Error> {
76        let salt = b"some@email.com"; // Salt should be unique per password
77        let password = b"some random words that you made up, for sure!";
78
79        let mut output_key_material_1 = Seed::new(Zeroizing::new([0u8; 32]));
80        let mut output_key_material_2 = Seed::default(); // default size is 32 bytes
81        let mut output_key_material_3: Vec<u8> = vec![0; 48]; // non-zero length vectors are ok too
82
83        Argon2::default().hash_password_into(password, salt, &mut output_key_material_1)?;
84        Argon2::default().hash_password_into(password, salt, &mut output_key_material_2)?;
85        Argon2::default().hash_password_into(password, salt, &mut output_key_material_3)?;
86
87        assert_eq!(output_key_material_1, output_key_material_2);
88
89        drop(output_key_material_1);
90        drop(output_key_material_2);
91        drop(output_key_material_3);
92
93        Ok(())
94    }
95
96    #[test]
97    fn api_works() -> Result<(), Error> {
98        let password = "some random words that you made up, for sure!".to_string();
99        let salt = b"some@email.com"; // Salt should be unique per password
100
101        let input = Input::new(&password, salt);
102
103        let seed = input.derive_key()?;
104
105        assert_eq!(
106            seed.as_ref(),
107            [
108                164, 103, 254, 113, 126, 241, 57, 240, 100, 56, 243, 125, 155, 224, 40, 242, 178,
109                136, 222, 133, 220, 141, 127, 10, 88, 199, 181, 11, 241, 91, 149, 249
110            ]
111        );
112
113        // print out Seed
114        println!("Seed {:?}", seed);
115
116        // also for direct fn
117        let seed = derive_key(password, salt)?;
118
119        assert_eq!(
120            seed.as_ref(),
121            [
122                164, 103, 254, 113, 126, 241, 57, 240, 100, 56, 243, 125, 155, 224, 40, 242, 178,
123                136, 222, 133, 220, 141, 127, 10, 88, 199, 181, 11, 241, 91, 149, 249
124            ]
125        );
126
127        Ok(())
128    }
129}