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