keepass_db/
key.rs

1use ring::digest::{Context, SHA256};
2
3/// Composite key protecting the password database
4///
5/// This key is composed of a password and/or a key file which
6/// must be provided when opening a KeePass password database
7/// ```
8/// use keepass_db::Key;
9/// let mut key = Key::new();
10/// key.set_user_password("secret");
11/// ```
12pub struct Key {
13    user_password: Option<Vec<u8>>,
14    keyfile: Option<Vec<u8>>,
15    windows_credentials: Option<Vec<u8>>,
16}
17
18impl Key {
19    /// Create a new composite key
20    /// ```
21    /// # use keepass_db::Key;
22    /// let mut key = Key::new();
23    /// ```
24    pub fn new() -> Key {
25        Key {
26            user_password: None,
27            keyfile: None,
28            windows_credentials: None,
29        }
30    }
31
32    /// Set the password for the compsite key
33    /// ```
34    /// # use keepass_db::Key;
35    /// # let mut key = Key::new();
36    /// key.set_user_password("secret");
37    /// ```
38    pub fn set_user_password<T>(&mut self, user_password: T)
39    where
40        T: AsRef<[u8]>,
41    {
42        let mut context = Context::new(&SHA256);
43        context.update(user_password.as_ref());
44        self.user_password = Some(context.finish().as_ref().to_owned());
45    }
46
47    /// Load a key file for the composite key
48    /// ```
49    /// # use keepass_db::Key;
50    /// # let mut key = Key::new();
51    /// key.set_keyfile("secret");
52    /// ```
53    pub fn set_keyfile<T>(&mut self, keyfile: T)
54    where
55        T: AsRef<[u8]>,
56    {
57        let mut context = Context::new(&SHA256);
58        context.update(keyfile.as_ref());
59        self.keyfile = Some(context.finish().as_ref().to_owned());
60    }
61
62    /* TODO Use this function */
63    fn _set_windows_credentials<T>(&mut self, windows_credentials: T)
64    where
65        T: AsRef<[u8]>,
66    {
67        let mut context = Context::new(&SHA256);
68        context.update(windows_credentials.as_ref());
69        self.windows_credentials = Some(context.finish().as_ref().to_owned());
70    }
71
72    pub(crate) fn composite_key(&self) -> Vec<u8> {
73        let mut context = Context::new(&SHA256);
74
75        if let Some(key) = &self.user_password {
76            context.update(&key);
77        }
78
79        if let Some(key) = &self.keyfile {
80            context.update(&key);
81        }
82
83        if let Some(key) = &self.windows_credentials {
84            context.update(&key);
85        }
86
87        context.finish().as_ref().to_owned()
88    }
89
90    pub(crate) fn composite_key_kdb1(&self) -> Vec<u8> {
91        if self.user_password == None {
92            return self.keyfile.clone().unwrap();
93        }
94
95        if self.keyfile == None {
96            return self.user_password.clone().unwrap();
97        }
98
99        let mut context = Context::new(&SHA256);
100        context.update(&self.user_password.clone().unwrap());
101        context.update(&self.keyfile.clone().unwrap());
102        context.finish().as_ref().to_owned()
103    }
104}
105
106#[cfg(test)]
107mod tests {
108    use hex::FromHex;
109
110    use super::*;
111
112    // Simple password is asdf
113    const PASSWORD_SIMPLE: &str = "61736466";
114
115    // Composite key generated from simple, password-only lock
116    const COMPOSITE_KEY_PASSWORD: &str =
117        "fe9a32f5b565da46af951e4aab23c24b8c1565eb0b6603a03118b7d225a21e8c";
118
119    #[test]
120    fn test_user_password() {
121        let data = Vec::from_hex(PASSWORD_SIMPLE).unwrap();
122        let mut key = Key::new();
123        key.set_user_password(data);
124        assert_eq!(
125            key.composite_key(),
126            Vec::from_hex(COMPOSITE_KEY_PASSWORD).unwrap()
127        );
128    }
129}