lockbook_shared/
secret_filename.rs1use crate::crypto::{AESEncrypted, AESKey};
2use crate::symkey::{convert_key, generate_nonce};
3use crate::{SharedErrorKind, SharedResult};
4use aead::{generic_array::GenericArray, Aead};
5use hmac::{Hmac, Mac, NewMac};
6use serde::{Deserialize, Serialize};
7use sha2::Sha256;
8use std::hash::Hash;
9
10pub type HmacSha256 = Hmac<Sha256>;
11
12#[derive(Serialize, Deserialize, Debug, Clone)]
15pub struct SecretFileName {
16 pub encrypted_value: AESEncrypted<String>,
17 pub hmac: [u8; 32],
18}
19
20impl SecretFileName {
21 pub fn from_str(to_encrypt: &str, key: &AESKey, parent_key: &AESKey) -> SharedResult<Self> {
22 let serialized = bincode::serialize(to_encrypt)?;
23
24 let hmac = {
25 let mut mac = HmacSha256::new_from_slice(parent_key)
26 .map_err(SharedErrorKind::HmacCreationError)?;
27 mac.update(serialized.as_ref());
28 mac.finalize().into_bytes()
29 }
30 .into();
31
32 let encrypted_value = {
33 let nonce = &generate_nonce();
34 let encrypted = convert_key(key)
35 .encrypt(
36 GenericArray::from_slice(nonce),
37 aead::Payload { msg: &serialized, aad: &[] },
38 )
39 .map_err(SharedErrorKind::Encryption)?;
40 AESEncrypted::new(encrypted, nonce.to_vec())
41 };
42
43 Ok(SecretFileName { encrypted_value, hmac })
44 }
45
46 pub fn to_string(&self, key: &AESKey) -> SharedResult<String> {
47 let nonce = GenericArray::from_slice(&self.encrypted_value.nonce);
48 let decrypted = convert_key(key)
49 .decrypt(nonce, aead::Payload { msg: &self.encrypted_value.value, aad: &[] })
50 .map_err(SharedErrorKind::Decryption)?;
51 let deserialized = bincode::deserialize(&decrypted)?;
52 Ok(deserialized)
53 }
54
55 pub fn verify_hmac(&self, key: &AESKey, parent_key: &AESKey) -> SharedResult<()> {
56 let decrypted = self.to_string(key)?;
57 let mut mac =
58 HmacSha256::new_from_slice(parent_key).map_err(SharedErrorKind::HmacCreationError)?;
59 mac.update(decrypted.as_ref());
60 mac.verify(&self.hmac)
61 .map_err(SharedErrorKind::HmacValidationError)?;
62 Ok(())
63 }
64}
65
66impl PartialEq for SecretFileName {
68 fn eq(&self, other: &Self) -> bool {
69 self.hmac == other.hmac
70 }
71}
72
73impl Eq for SecretFileName {}
74
75impl Hash for SecretFileName {
76 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
77 self.hmac.hash(state);
78 }
79}
80
81#[cfg(test)]
82mod unit_tests {
83 use crate::{secret_filename::SecretFileName, symkey::generate_key};
84 use uuid::Uuid;
85
86 #[test]
87 fn test_to_string_from_string() {
88 let key = generate_key();
89 let parent_key = generate_key();
90 let test_value = Uuid::new_v4().to_string();
91 let secret = SecretFileName::from_str(&test_value, &key, &parent_key).unwrap();
92 let decrypted = secret.to_string(&key).unwrap();
93
94 assert_eq!(test_value, decrypted);
95 }
96
97 #[test]
98 fn test_hmac_encryption_failure() {
99 let key = generate_key();
100 let parent_key = generate_key();
101 let test_value = Uuid::new_v4().to_string();
102 let mut secret = SecretFileName::from_str(&test_value, &key, &parent_key).unwrap();
103 secret.hmac[10] = !secret.hmac[10];
104 secret.hmac[11] = !secret.hmac[11];
105 secret.hmac[12] = !secret.hmac[12];
106 secret.hmac[13] = !secret.hmac[13];
107 secret.hmac[14] = !secret.hmac[14];
108 secret.verify_hmac(&key, &parent_key).unwrap_err();
109 }
110
111 #[test]
112 fn attempt_value_forge() {
113 let key = generate_key();
114 let parent_key = generate_key();
115
116 let test_value1 = Uuid::new_v4().to_string();
117 let test_value2 = Uuid::new_v4().to_string();
118 let secret1 = SecretFileName::from_str(&test_value1, &key, &parent_key).unwrap();
119 let mut secret2 = SecretFileName::from_str(&test_value2, &key, &parent_key).unwrap();
120
121 secret2.encrypted_value = secret1.encrypted_value;
122
123 secret2.verify_hmac(&key, &parent_key).unwrap_err();
124 }
125}