bc_components/encrypted_key/
encrypted_key_impl.rs1use anyhow::{Error, Result};
7use dcbor::prelude::*;
8
9use super::SSHAgentParams;
10use crate::{
11 Argon2idParams, EncryptedMessage, HKDFParams, KeyDerivation,
12 KeyDerivationMethod, KeyDerivationParams, PBKDF2Params, ScryptParams,
13 SymmetricKey, tags,
14};
15
16#[derive(Debug, Clone, PartialEq, Eq)]
64pub struct EncryptedKey {
65 params: KeyDerivationParams,
66 encrypted_message: EncryptedMessage,
67}
68
69impl EncryptedKey {
70 pub fn lock_opt(
71 mut params: KeyDerivationParams,
72 secret: impl AsRef<[u8]>,
73 content_key: &SymmetricKey,
74 ) -> Result<Self> {
75 let encrypted_message = params.lock(content_key, secret)?;
76 Ok(Self { params, encrypted_message })
77 }
78
79 pub fn lock(
80 method: KeyDerivationMethod,
81 secret: impl AsRef<[u8]>,
82 content_key: &SymmetricKey,
83 ) -> Result<Self> {
84 match method {
85 KeyDerivationMethod::HKDF => Self::lock_opt(
86 KeyDerivationParams::HKDF(HKDFParams::new()),
87 secret,
88 content_key,
89 ),
90 KeyDerivationMethod::PBKDF2 => Self::lock_opt(
91 KeyDerivationParams::PBKDF2(PBKDF2Params::new()),
92 secret,
93 content_key,
94 ),
95 KeyDerivationMethod::Scrypt => Self::lock_opt(
96 KeyDerivationParams::Scrypt(ScryptParams::new()),
97 secret,
98 content_key,
99 ),
100 KeyDerivationMethod::Argon2id => Self::lock_opt(
101 KeyDerivationParams::Argon2id(Argon2idParams::new()),
102 secret,
103 content_key,
104 ),
105 KeyDerivationMethod::SSHAgent => Self::lock_opt(
106 KeyDerivationParams::SSHAgent(SSHAgentParams::new()),
107 secret,
108 content_key,
109 ),
110 }
111 }
112
113 pub fn encrypted_message(&self) -> &EncryptedMessage {
114 &self.encrypted_message
115 }
116
117 pub fn aad_cbor(&self) -> Result<CBOR> {
118 self.encrypted_message()
119 .aad_cbor()
120 .ok_or_else(|| Error::msg("Missing AAD CBOR in EncryptedMessage"))
121 }
122
123 pub fn unlock(&self, secret: impl AsRef<[u8]>) -> Result<SymmetricKey> {
124 let encrypted_message = &self.encrypted_message();
125 let cbor = self.aad_cbor()?;
126 let array = cbor.clone().try_into_array()?;
127 let method = array
128 .first()
129 .ok_or_else(|| Error::msg("Missing method"))?
130 .try_into()?;
131 match method {
132 KeyDerivationMethod::HKDF => {
133 let params = HKDFParams::try_from(cbor)?;
134 params.unlock(encrypted_message, secret)
135 }
136 KeyDerivationMethod::PBKDF2 => {
137 let params = PBKDF2Params::try_from(cbor)?;
138 params.unlock(encrypted_message, secret)
139 }
140 KeyDerivationMethod::Scrypt => {
141 let params = ScryptParams::try_from(cbor)?;
142 params.unlock(encrypted_message, secret)
143 }
144 KeyDerivationMethod::Argon2id => {
145 let params = Argon2idParams::try_from(cbor)?;
146 params.unlock(encrypted_message, secret)
147 }
148 KeyDerivationMethod::SSHAgent => {
149 let params = SSHAgentParams::try_from(cbor)?;
150 params.unlock(encrypted_message, secret)
151 }
152 }
153 }
154
155 pub fn is_password_based(&self) -> bool { self.params.is_password_based() }
156
157 pub fn is_ssh_agent(&self) -> bool { self.params.is_ssh_agent() }
158}
159
160impl std::fmt::Display for EncryptedKey {
161 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
162 write!(f, "EncryptedKey({})", self.params)
163 }
164}
165
166impl CBORTagged for EncryptedKey {
167 fn cbor_tags() -> Vec<Tag> { tags_for_values(&[tags::TAG_ENCRYPTED_KEY]) }
168}
169
170impl From<EncryptedKey> for CBOR {
171 fn from(value: EncryptedKey) -> Self { value.tagged_cbor() }
172}
173
174impl CBORTaggedEncodable for EncryptedKey {
175 fn untagged_cbor(&self) -> CBOR { self.encrypted_message().clone().into() }
176}
177
178impl TryFrom<CBOR> for EncryptedKey {
179 type Error = dcbor::Error;
180
181 fn try_from(value: CBOR) -> dcbor::Result<Self> {
182 Self::from_tagged_cbor(value)
183 }
184}
185
186impl CBORTaggedDecodable for EncryptedKey {
187 fn from_untagged_cbor(untagged_cbor: CBOR) -> dcbor::Result<Self> {
188 let encrypted_key: EncryptedMessage = untagged_cbor.try_into()?;
189 let params_cbor = CBOR::try_from_data(encrypted_key.aad())?;
190 let params = params_cbor.try_into()?;
191 Ok(Self { params, encrypted_message: encrypted_key })
192 }
193}
194
195#[cfg(test)]
196mod tests {
197 use super::*;
198
199 fn test_secret() -> &'static [u8] { b"correct horse battery staple" }
200
201 fn test_content_key() -> SymmetricKey { SymmetricKey::new() }
202
203 #[test]
204 fn test_encrypted_key_hkdf_roundtrip() {
205 crate::register_tags();
206 let secret = test_secret();
207 let content_key = test_content_key();
208
209 let encrypted =
210 EncryptedKey::lock(KeyDerivationMethod::HKDF, secret, &content_key)
211 .unwrap();
212 assert_eq!(format!("{}", encrypted), "EncryptedKey(HKDF(SHA256))");
213 let cbor = encrypted.clone().to_cbor();
214 let encrypted2 = EncryptedKey::try_from(cbor).unwrap();
215 let decrypted = EncryptedKey::unlock(&encrypted2, secret).unwrap();
216
217 assert_eq!(content_key, decrypted);
218 }
219
220 #[test]
221 fn test_encrypted_key_pbkdf2_roundtrip() {
222 let secret = test_secret();
223 let content_key = test_content_key();
224
225 let encrypted = EncryptedKey::lock(
226 KeyDerivationMethod::PBKDF2,
227 secret,
228 &content_key,
229 )
230 .unwrap();
231 assert_eq!(format!("{}", encrypted), "EncryptedKey(PBKDF2(SHA256))");
232 let cbor = encrypted.clone().to_cbor();
233 let encrypted2 = EncryptedKey::try_from(cbor).unwrap();
234 let decrypted = EncryptedKey::unlock(&encrypted2, secret).unwrap();
235
236 assert_eq!(content_key, decrypted);
237 }
238
239 #[test]
240 fn test_encrypted_key_scrypt_roundtrip() {
241 let secret = test_secret();
242 let content_key = test_content_key();
243
244 let encrypted = EncryptedKey::lock(
245 KeyDerivationMethod::Scrypt,
246 secret,
247 &content_key,
248 )
249 .unwrap();
250 assert_eq!(format!("{}", encrypted), "EncryptedKey(Scrypt)");
251 let cbor = encrypted.clone().to_cbor();
252 let encrypted2 = EncryptedKey::try_from(cbor).unwrap();
253 let decrypted = EncryptedKey::unlock(&encrypted2, secret).unwrap();
254
255 assert_eq!(content_key, decrypted);
256 }
257
258 #[test]
259 fn test_encrypted_key_argon2id_roundtrip() {
260 let secret = test_secret();
261 let content_key = test_content_key();
262
263 let argon2id = EncryptedKey::lock(
264 KeyDerivationMethod::Argon2id,
265 secret,
266 &content_key,
267 )
268 .unwrap();
269 assert_eq!(format!("{}", argon2id), "EncryptedKey(Argon2id)");
270 let cbor = argon2id.clone().to_cbor();
271 let argon2id2 = EncryptedKey::try_from(cbor).unwrap();
272 let decrypted = EncryptedKey::unlock(&argon2id2, secret).unwrap();
273
274 assert_eq!(content_key, decrypted);
275 }
276
277 #[test]
278 fn test_encrypted_key_wrong_secret_fails() {
279 let secret = test_secret();
280 let wrong_secret = b"wrong secret";
281 let content_key = test_content_key();
282
283 let encrypted =
284 EncryptedKey::lock(KeyDerivationMethod::HKDF, secret, &content_key)
285 .unwrap();
286 let result = EncryptedKey::unlock(&encrypted, wrong_secret);
287 assert!(result.is_err());
288
289 let encrypted = EncryptedKey::lock(
290 KeyDerivationMethod::PBKDF2,
291 secret,
292 &content_key,
293 )
294 .unwrap();
295 let result = EncryptedKey::unlock(&encrypted, wrong_secret);
296 assert!(result.is_err());
297
298 let encrypted = EncryptedKey::lock(
299 KeyDerivationMethod::Scrypt,
300 secret,
301 &content_key,
302 )
303 .unwrap();
304 let result = EncryptedKey::unlock(&encrypted, wrong_secret);
305 assert!(result.is_err());
306
307 let encrypted = EncryptedKey::lock(
308 KeyDerivationMethod::Argon2id,
309 secret,
310 &content_key,
311 )
312 .unwrap();
313 let result = EncryptedKey::unlock(&encrypted, wrong_secret);
314 assert!(result.is_err());
315 }
316
317 #[test]
318 fn test_encrypted_key_params_variant() {
319 let secret = test_secret();
320 let content_key = test_content_key();
321
322 let hkdf =
323 EncryptedKey::lock(KeyDerivationMethod::HKDF, secret, &content_key)
324 .unwrap();
325 matches!(hkdf.params, KeyDerivationParams::HKDF(_));
326
327 let pbkdf2 = EncryptedKey::lock(
328 KeyDerivationMethod::PBKDF2,
329 secret,
330 &content_key,
331 )
332 .unwrap();
333 matches!(pbkdf2.params, KeyDerivationParams::PBKDF2(_));
334
335 let scrypt = EncryptedKey::lock(
336 KeyDerivationMethod::Scrypt,
337 secret,
338 &content_key,
339 )
340 .unwrap();
341 matches!(scrypt.params, KeyDerivationParams::Scrypt(_));
342
343 let argon2id = EncryptedKey::lock(
344 KeyDerivationMethod::Argon2id,
345 secret,
346 &content_key,
347 )
348 .unwrap();
349 matches!(argon2id.params, KeyDerivationParams::Argon2id(_));
350 }
351}