kpdb/types/
composite_key.rs

1// Copyright (c) 2016-2017 Martijn Rijkeboer <[email protected]>
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use crypto::sha256;
10use secstr::SecStr;
11use super::KeyFile;
12
13/// Composition of the user's key data.
14///
15/// This data type uses secstr's `SecStr` to protect the key data. To
16/// retrieve the protected data use the `unsecure` method.
17#[derive(Clone, Debug, PartialEq)]
18pub struct CompositeKey(SecStr);
19
20impl CompositeKey {
21    /// Create a composite key from both a password and a key file.
22    ///
23    /// # Examples
24    ///
25    /// ```rust,no_run
26    /// # use kpdb::Result;
27    /// use kpdb::{CompositeKey, KeyFile};
28    /// use std::fs::File;
29    ///
30    /// # fn from_both_example() -> Result<()> {
31    /// let mut file = try!(File::open("database.key"));
32    /// let key_file = try!(KeyFile::open(&mut file));
33    /// let key = CompositeKey::from_both("secret", key_file);
34    /// # Ok(())
35    /// # }
36    /// ```
37    pub fn from_both<S: Into<String>>(password: S, key_file: KeyFile) -> CompositeKey {
38        let password = sha256::hash(&[&password.into().into_bytes()]);
39        let combined = sha256::hash(&[&password, &key_file.key.unsecure()]);
40        CompositeKey::secure(combined)
41    }
42
43    /// Create a composite key from a key file.
44    ///
45    /// # Examples
46    ///
47    /// ```rust,no_run
48    /// # use kpdb::Result;
49    /// use kpdb::{CompositeKey, KeyFile};
50    /// use std::fs::File;
51    ///
52    /// # fn from_key_file_example() -> Result<()> {
53    /// let mut file = try!(File::open("database.key"));
54    /// let key_file = try!(KeyFile::open(&mut file));
55    /// let key = CompositeKey::from_key_file(key_file);
56    /// # Ok(())
57    /// # }
58    /// ```
59    pub fn from_key_file(key_file: KeyFile) -> CompositeKey {
60        let combined = sha256::hash(&[&key_file.key.unsecure()]);
61        CompositeKey::secure(combined)
62    }
63
64    /// Create a composite key from a password.
65    ///
66    /// # Examples
67    ///
68    /// ```rust
69    /// use kpdb::CompositeKey;
70    ///
71    /// let key = CompositeKey::from_password("secret");
72    /// ```
73    pub fn from_password<S: Into<String>>(password: S) -> CompositeKey {
74        let password = sha256::hash(&[&password.into().into_bytes()]);
75        let combined = sha256::hash(&[&password]);
76        CompositeKey::secure(combined)
77    }
78
79    /// Gets the protected data from this composite key.
80    pub fn unsecure(&self) -> [u8; 32] {
81        let unsecure = self.0.unsecure();
82        let mut array = [0u8; 32];
83        for (u, a) in unsecure.iter().zip(array.iter_mut()) {
84            *a = *u;
85        }
86        array
87    }
88
89    fn secure(key: [u8; 32]) -> CompositeKey {
90        CompositeKey(SecStr::new(key.to_vec()))
91    }
92}
93
94#[cfg(test)]
95mod tests {
96
97    use secstr::SecStr;
98    use super::*;
99    use types::{KeyFile, KeyFileType};
100
101    #[test]
102    fn test_from_both_returns_correct_instance() {
103        let array = [
104            184,
105            53,
106            98,
107            70,
108            154,
109            211,
110            44,
111            121,
112            45,
113            59,
114            104,
115            22,
116            210,
117            47,
118            92,
119            167,
120            10,
121            193,
122            98,
123            121,
124            81,
125            174,
126            1,
127            128,
128            96,
129            122,
130            3,
131            12,
132            5,
133            33,
134            202,
135            40,
136        ];
137        let key = KeyFile {
138            key: SecStr::new(vec![0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64]),
139            file_type: KeyFileType::Xml,
140        };
141        let password = "secret";
142        let expected = CompositeKey::secure(array);
143        let actual = CompositeKey::from_both(password, key);
144        assert_eq!(actual, expected);
145    }
146
147    #[test]
148    fn test_from_key_file_returns_correct_instance() {
149        let array = [
150            94,
151            136,
152            72,
153            152,
154            218,
155            40,
156            4,
157            113,
158            81,
159            208,
160            229,
161            111,
162            141,
163            198,
164            41,
165            39,
166            115,
167            96,
168            61,
169            13,
170            106,
171            171,
172            189,
173            214,
174            42,
175            17,
176            239,
177            114,
178            29,
179            21,
180            66,
181            216,
182        ];
183        let key = KeyFile {
184            key: SecStr::new(vec![0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64]),
185            file_type: KeyFileType::Xml,
186        };
187        let expected = CompositeKey::secure(array);
188        let actual = CompositeKey::from_key_file(key);
189        assert_eq!(actual, expected);
190    }
191
192    #[test]
193    fn test_from_password_returns_correct_instance() {
194        let array = [
195            56,
196            129,
197            33,
198            157,
199            8,
200            125,
201            217,
202            198,
203            52,
204            55,
205            63,
206            211,
207            61,
208            250,
209            51,
210            162,
211            203,
212            107,
213            252,
214            108,
215            82,
216            11,
217            100,
218            184,
219            187,
220            96,
221            239,
222            44,
223            235,
224            83,
225            74,
226            231,
227        ];
228        let password = "secret";
229        let expected = CompositeKey::secure(array);
230        let actual = CompositeKey::from_password(password);
231        assert_eq!(actual, expected);
232    }
233
234    #[test]
235    fn test_unsecure_inverses_secure() {
236        let array = [
237            1,
238            2,
239            3,
240            4,
241            5,
242            6,
243            7,
244            8,
245            9,
246            10,
247            11,
248            12,
249            13,
250            14,
251            15,
252            16,
253            17,
254            18,
255            19,
256            20,
257            21,
258            22,
259            23,
260            24,
261            25,
262            26,
263            27,
264            28,
265            29,
266            30,
267            31,
268            32,
269        ];
270        let expected = array.clone();
271        let actual = CompositeKey::unsecure(&CompositeKey::secure(array));
272        assert_eq!(actual, expected);
273    }
274}