1use cbc::{cipher::{BlockDecryptMut, BlockEncryptMut, KeyIvInit}};
2use hmac::{Hmac, Mac};
3use sha2::{Sha256, Sha512, Digest};
4use subtle::ConstantTimeEq;
5
6type Aes256Cbc = cbc::Encryptor<aes::Aes256>;
7type Aes256CbcDec = cbc::Decryptor<aes::Aes256>;
8type HmacSha256 = Hmac<Sha256>;
9
10pub fn encrypt(key: &[u8], data: &[u8], iv: &[u8]) -> Result<Vec<u8>, Box<dyn std::error::Error + Send + Sync>> {
12 if key.len() != 32 {
13 return Err("Key must be 32 bytes".into());
14 }
15 if iv.len() != 16 {
16 return Err("IV must be 16 bytes".into());
17 }
18
19 let cipher = Aes256Cbc::new(key.into(), iv.into());
20 Ok(cipher.encrypt_padded_vec_mut::<cbc::cipher::block_padding::Pkcs7>(data))
21}
22
23pub fn decrypt(key: &[u8], data: &[u8], iv: &[u8]) -> Result<Vec<u8>, Box<dyn std::error::Error + Send + Sync>> {
25 if key.len() != 32 {
26 return Err("Key must be 32 bytes".into());
27 }
28 if iv.len() != 16 {
29 return Err("IV must be 16 bytes".into());
30 }
31
32 let cipher = Aes256CbcDec::new(key.into(), iv.into());
33 cipher.decrypt_padded_vec_mut::<cbc::cipher::block_padding::Pkcs7>(data)
34 .map_err(|e| format!("Decryption error: {:?}", e).into())
35}
36
37pub fn calculate_mac(key: &[u8], data: &[u8]) -> Vec<u8> {
39 let mut mac = HmacSha256::new_from_slice(key).expect("HMAC can take key of any size");
40 mac.update(data);
41 mac.finalize().into_bytes().to_vec()
42}
43
44pub fn hash(data: &[u8]) -> Vec<u8> {
46 let mut hasher = Sha512::new();
47 hasher.update(data);
48 hasher.finalize().to_vec()
49}
50
51pub fn calculate_sha512(data: &[u8]) -> Vec<u8> {
53 hash(data)
54}
55
56pub fn derive_secrets(input: &[u8], salt: &[u8], info: &[u8], chunks: Option<usize>) -> Result<Vec<Vec<u8>>, Box<dyn std::error::Error + Send + Sync>> {
58 if salt.len() != 32 {
59 return Err("Got salt of incorrect length".into());
60 }
61
62 let chunks = chunks.unwrap_or(3);
63 if chunks < 1 || chunks > 3 {
64 return Err("Chunks must be between 1 and 3".into());
65 }
66
67 let prk = calculate_mac(salt, input);
68
69 let mut results = Vec::new();
70 let mut info_array = vec![0u8; info.len() + 1 + 32];
71 info_array[32..32 + info.len()].copy_from_slice(info);
72 let len = info_array.len();
73 info_array[len - 1] = 1;
74
75 let first = calculate_mac(&prk, &info_array[32..]);
76 results.push(first.clone());
77
78 if chunks > 1 {
79 info_array[..32].copy_from_slice(&first);
80 let len = info_array.len();
81 info_array[len - 1] = 2;
82 let second = calculate_mac(&prk, &info_array[..]);
83 results.push(second.clone());
84
85 if chunks > 2 {
86 info_array[..32].copy_from_slice(&second);
87 let len = info_array.len();
88 info_array[len - 1] = 3;
89 let third = calculate_mac(&prk, &info_array[..]);
90 results.push(third);
91 }
92 }
93
94 Ok(results)
95}
96
97pub fn verify_mac(data: &[u8], key: &[u8], mac: &[u8], length: usize) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
99 let calculated_mac = calculate_mac(key, data);
100 let calculated_mac = &calculated_mac[..length];
101
102 if mac.len() != length || calculated_mac.len() != length {
103 return Err("Bad MAC length".into());
104 }
105
106 if calculated_mac.ct_eq(mac).into() {
107 Ok(())
108 } else {
109 Err("Bad MAC".into())
110 }
111}