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
53#[allow(dead_code)]
55pub fn decrypt_data(encrypted_data: &[u8], key: &[u8; 32]) -> Result<Vec<u8>> {
56 if encrypted_data.len() < 12 {
57 anyhow::bail!("Invalid encrypted data: too short");
58 }
59
60 let cipher = Aes256Gcm::new(Key::<Aes256Gcm>::from_slice(key));
61
62 let (nonce_bytes, ciphertext) = encrypted_data.split_at(12);
64 let nonce = Nonce::from_slice(nonce_bytes);
65
66 let plaintext = cipher
67 .decrypt(nonce, ciphertext)
68 .map_err(|e| anyhow::anyhow!("Decryption failed: {}", e))?;
69
70 Ok(plaintext)
71}
72
73#[allow(dead_code)]
75pub fn encode_base64(data: &[u8]) -> String {
76 general_purpose::STANDARD.encode(data)
77}
78
79#[allow(dead_code)]
81pub fn decode_base64(data: &str) -> Result<Vec<u8>> {
82 general_purpose::STANDARD
83 .decode(data)
84 .map_err(|e| anyhow::anyhow!("Base64 decode failed: {}", e))
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 #[test]
92 fn test_key_derivation() {
93 let password = "test_password_123";
94 let key1 = derive_key_from_password(password).unwrap();
95 let key2 = derive_key_from_password(password).unwrap();
96
97 assert_eq!(key1, key2);
99
100 let key3 = derive_key_from_password("different_password").unwrap();
102 assert_ne!(key1, key3);
103 }
104
105 #[test]
106 fn test_encryption_decryption() {
107 let data = b"Hello, World! This is test data for encryption.";
108 let password = "test_password_123";
109 let key = derive_key_from_password(password).unwrap();
110
111 let encrypted = encrypt_data(data, &key).unwrap();
113 assert_ne!(encrypted.as_slice(), data);
114 assert!(encrypted.len() > data.len()); let decrypted = decrypt_data(&encrypted, &key).unwrap();
118 assert_eq!(decrypted.as_slice(), data);
119 }
120
121 #[test]
122 fn test_encryption_with_wrong_key() {
123 let data = b"Hello, World!";
124 let key1 = derive_key_from_password("password1").unwrap();
125 let key2 = derive_key_from_password("password2").unwrap();
126
127 let encrypted = encrypt_data(data, &key1).unwrap();
128
129 assert!(decrypt_data(&encrypted, &key2).is_err());
131 }
132
133 #[test]
134 fn test_base64_encoding() {
135 let data = b"Hello, World!";
136 let encoded = encode_base64(data);
137 let decoded = decode_base64(&encoded).unwrap();
138
139 assert_eq!(decoded.as_slice(), data);
140 }
141
142 #[test]
143 fn test_invalid_encrypted_data() {
144 let key = derive_key_from_password("test").unwrap();
145
146 assert!(decrypt_data(b"short", &key).is_err());
148
149 let invalid_data = vec![0u8; 20];
151 assert!(decrypt_data(&invalid_data, &key).is_err());
152 }
153}