1use aes_gcm::{
4 aead::{Aead, AeadCore, KeyInit, OsRng},
5 Aes256Gcm, Key, Nonce,
6};
7use anyhow::Result;
8use base64::{engine::general_purpose, Engine as _};
9
10pub fn derive_key_from_password(password: &str) -> Result<[u8; 32]> {
13 use std::collections::hash_map::DefaultHasher;
14 use std::hash::{Hash, Hasher};
15
16 let mut hasher = DefaultHasher::new();
18 password.hash(&mut hasher);
19 let hash1 = hasher.finish();
20
21 let mut hasher2 = DefaultHasher::new();
23 format!("{}{}", password, hash1).hash(&mut hasher2);
24 let hash2 = hasher2.finish();
25
26 let mut key = [0u8; 32];
28 key[0..8].copy_from_slice(&hash1.to_le_bytes());
29 key[8..16].copy_from_slice(&hash2.to_le_bytes());
30 key[16..24].copy_from_slice(&hash1.to_be_bytes());
31 key[24..32].copy_from_slice(&hash2.to_be_bytes());
32
33 Ok(key)
34}
35
36pub fn encrypt_data(data: &[u8], key: &[u8; 32]) -> Result<Vec<u8>> {
38 let cipher = Aes256Gcm::new(Key::<Aes256Gcm>::from_slice(key));
39 let nonce = Aes256Gcm::generate_nonce(&mut OsRng);
40
41 let ciphertext = cipher
42 .encrypt(&nonce, data)
43 .map_err(|e| anyhow::anyhow!("Encryption failed: {}", e))?;
44
45 let mut result = Vec::with_capacity(nonce.len() + ciphertext.len());
47 result.extend_from_slice(&nonce);
48 result.extend_from_slice(&ciphertext);
49
50 Ok(result)
51}
52
53pub fn decrypt_data(encrypted_data: &[u8], key: &[u8; 32]) -> Result<Vec<u8>> {
55 if encrypted_data.len() < 12 {
56 anyhow::bail!("Invalid encrypted data: too short");
57 }
58
59 let cipher = Aes256Gcm::new(Key::<Aes256Gcm>::from_slice(key));
60
61 let (nonce_bytes, ciphertext) = encrypted_data.split_at(12);
63 let nonce = Nonce::from_slice(nonce_bytes);
64
65 let plaintext = cipher
66 .decrypt(nonce, ciphertext)
67 .map_err(|e| anyhow::anyhow!("Decryption failed: {}", e))?;
68
69 Ok(plaintext)
70}
71
72pub fn encode_base64(data: &[u8]) -> String {
74 general_purpose::STANDARD.encode(data)
75}
76
77pub fn decode_base64(data: &str) -> Result<Vec<u8>> {
79 general_purpose::STANDARD
80 .decode(data)
81 .map_err(|e| anyhow::anyhow!("Base64 decode failed: {}", e))
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 #[test]
89 fn test_key_derivation() {
90 let password = "test_password_123";
91 let key1 = derive_key_from_password(password).unwrap();
92 let key2 = derive_key_from_password(password).unwrap();
93
94 assert_eq!(key1, key2);
96
97 let key3 = derive_key_from_password("different_password").unwrap();
99 assert_ne!(key1, key3);
100 }
101
102 #[test]
103 fn test_encryption_decryption() {
104 let data = b"Hello, World! This is test data for encryption.";
105 let password = "test_password_123";
106 let key = derive_key_from_password(password).unwrap();
107
108 let encrypted = encrypt_data(data, &key).unwrap();
110 assert_ne!(encrypted.as_slice(), data);
111 assert!(encrypted.len() > data.len()); let decrypted = decrypt_data(&encrypted, &key).unwrap();
115 assert_eq!(decrypted.as_slice(), data);
116 }
117
118 #[test]
119 fn test_encryption_with_wrong_key() {
120 let data = b"Hello, World!";
121 let key1 = derive_key_from_password("password1").unwrap();
122 let key2 = derive_key_from_password("password2").unwrap();
123
124 let encrypted = encrypt_data(data, &key1).unwrap();
125
126 assert!(decrypt_data(&encrypted, &key2).is_err());
128 }
129
130 #[test]
131 fn test_base64_encoding() {
132 let data = b"Hello, World!";
133 let encoded = encode_base64(data);
134 let decoded = decode_base64(&encoded).unwrap();
135
136 assert_eq!(decoded.as_slice(), data);
137 }
138
139 #[test]
140 fn test_invalid_encrypted_data() {
141 let key = derive_key_from_password("test").unwrap();
142
143 assert!(decrypt_data(b"short", &key).is_err());
145
146 let invalid_data = vec![0u8; 20];
148 assert!(decrypt_data(&invalid_data, &key).is_err());
149 }
150}