1use super::KeyFile;
10use crate::crypto::sha256;
11use secstr::SecStr;
12
13#[derive(Clone, Debug, PartialEq)]
18pub struct CompositeKey(SecStr);
19
20impl CompositeKey {
21 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 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 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 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 super::*;
98 use crate::types::{KeyFile, KeyFileType};
99 use secstr::SecStr;
100
101 #[test]
102 fn test_from_both_returns_correct_instance() {
103 let array = [
104 184, 53, 98, 70, 154, 211, 44, 121, 45, 59, 104, 22, 210, 47, 92, 167, 10, 193, 98,
105 121, 81, 174, 1, 128, 96, 122, 3, 12, 5, 33, 202, 40,
106 ];
107 let key = KeyFile {
108 key: SecStr::new(vec![0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64]),
109 file_type: KeyFileType::Xml,
110 };
111 let password = "secret";
112 let expected = CompositeKey::secure(array);
113 let actual = CompositeKey::from_both(password, key);
114 assert_eq!(actual, expected);
115 }
116
117 #[test]
118 fn test_from_key_file_returns_correct_instance() {
119 let array = [
120 94, 136, 72, 152, 218, 40, 4, 113, 81, 208, 229, 111, 141, 198, 41, 39, 115, 96, 61,
121 13, 106, 171, 189, 214, 42, 17, 239, 114, 29, 21, 66, 216,
122 ];
123 let key = KeyFile {
124 key: SecStr::new(vec![0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64]),
125 file_type: KeyFileType::Xml,
126 };
127 let expected = CompositeKey::secure(array);
128 let actual = CompositeKey::from_key_file(key);
129 assert_eq!(actual, expected);
130 }
131
132 #[test]
133 fn test_from_password_returns_correct_instance() {
134 let array = [
135 56, 129, 33, 157, 8, 125, 217, 198, 52, 55, 63, 211, 61, 250, 51, 162, 203, 107, 252,
136 108, 82, 11, 100, 184, 187, 96, 239, 44, 235, 83, 74, 231,
137 ];
138 let password = "secret";
139 let expected = CompositeKey::secure(array);
140 let actual = CompositeKey::from_password(password);
141 assert_eq!(actual, expected);
142 }
143
144 #[test]
145 fn test_unsecure_inverses_secure() {
146 let array = [
147 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
148 25, 26, 27, 28, 29, 30, 31, 32,
149 ];
150 let expected = array.clone();
151 let actual = CompositeKey::unsecure(&CompositeKey::secure(array));
152 assert_eq!(actual, expected);
153 }
154}