oxigdal_security/encryption/
at_rest.rs1use crate::encryption::{EncryptedData, EncryptionAlgorithm, EncryptionMetadata};
4use crate::error::{Result, SecurityError};
5use aes_gcm::{
6 Aes256Gcm, Nonce,
7 aead::{Aead, KeyInit},
8};
9use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64};
10use chacha20poly1305::ChaCha20Poly1305;
11
12pub struct AtRestEncryptor {
14 algorithm: EncryptionAlgorithm,
15 key: Vec<u8>,
16 key_id: String,
17}
18
19impl AtRestEncryptor {
20 pub fn new(algorithm: EncryptionAlgorithm, key: Vec<u8>, key_id: String) -> Result<Self> {
22 let required_length = match algorithm {
24 EncryptionAlgorithm::Aes256Gcm => 32,
25 EncryptionAlgorithm::ChaCha20Poly1305 => 32,
26 };
27
28 if key.len() != required_length {
29 return Err(SecurityError::encryption(format!(
30 "Invalid key length: expected {}, got {}",
31 required_length,
32 key.len()
33 )));
34 }
35
36 Ok(Self {
37 algorithm,
38 key,
39 key_id,
40 })
41 }
42
43 pub fn generate_key(algorithm: EncryptionAlgorithm) -> Vec<u8> {
45 let mut key = vec![
46 0u8;
47 match algorithm {
48 EncryptionAlgorithm::Aes256Gcm => 32,
49 EncryptionAlgorithm::ChaCha20Poly1305 => 32,
50 }
51 ];
52 getrandom::fill(&mut key).expect("getrandom failed");
53 key
54 }
55
56 pub fn encrypt(&self, plaintext: &[u8], aad: Option<&[u8]>) -> Result<EncryptedData> {
58 match self.algorithm {
59 EncryptionAlgorithm::Aes256Gcm => self.encrypt_aes_gcm(plaintext, aad),
60 EncryptionAlgorithm::ChaCha20Poly1305 => self.encrypt_chacha(plaintext, aad),
61 }
62 }
63
64 pub fn decrypt(&self, encrypted: &EncryptedData) -> Result<Vec<u8>> {
66 if encrypted.metadata.algorithm != self.algorithm {
68 return Err(SecurityError::decryption(format!(
69 "Algorithm mismatch: expected {:?}, got {:?}",
70 self.algorithm, encrypted.metadata.algorithm
71 )));
72 }
73
74 if encrypted.metadata.key_id != self.key_id {
76 return Err(SecurityError::decryption(format!(
77 "Key ID mismatch: expected {}, got {}",
78 self.key_id, encrypted.metadata.key_id
79 )));
80 }
81
82 match self.algorithm {
83 EncryptionAlgorithm::Aes256Gcm => self.decrypt_aes_gcm(encrypted),
84 EncryptionAlgorithm::ChaCha20Poly1305 => self.decrypt_chacha(encrypted),
85 }
86 }
87
88 fn encrypt_aes_gcm(&self, plaintext: &[u8], aad: Option<&[u8]>) -> Result<EncryptedData> {
89 let cipher = Aes256Gcm::new_from_slice(&self.key)
90 .map_err(|e| SecurityError::encryption(format!("Failed to create cipher: {}", e)))?;
91
92 let mut nonce_bytes = [0u8; 12];
94 getrandom::fill(&mut nonce_bytes).expect("getrandom failed");
95 let nonce = Nonce::from_slice(&nonce_bytes);
96
97 let ciphertext = if let Some(aad_data) = aad {
99 cipher
100 .encrypt(
101 nonce,
102 aes_gcm::aead::Payload {
103 msg: plaintext,
104 aad: aad_data,
105 },
106 )
107 .map_err(|e| SecurityError::encryption(format!("Encryption failed: {}", e)))?
108 } else {
109 cipher
110 .encrypt(nonce, plaintext)
111 .map_err(|e| SecurityError::encryption(format!("Encryption failed: {}", e)))?
112 };
113
114 let metadata = EncryptionMetadata::new(
115 self.algorithm,
116 self.key_id.clone(),
117 nonce_bytes.to_vec(),
118 aad.map(|a| a.to_vec()),
119 );
120
121 Ok(EncryptedData::new(ciphertext, metadata))
122 }
123
124 fn decrypt_aes_gcm(&self, encrypted: &EncryptedData) -> Result<Vec<u8>> {
125 let cipher = Aes256Gcm::new_from_slice(&self.key)
126 .map_err(|e| SecurityError::decryption(format!("Failed to create cipher: {}", e)))?;
127
128 if encrypted.metadata.iv.len() != 12 {
129 return Err(SecurityError::decryption(format!(
130 "Invalid nonce length: expected 12, got {}",
131 encrypted.metadata.iv.len()
132 )));
133 }
134
135 let nonce = Nonce::from_slice(&encrypted.metadata.iv);
136
137 let plaintext = if let Some(ref aad) = encrypted.metadata.aad {
138 cipher
139 .decrypt(
140 nonce,
141 aes_gcm::aead::Payload {
142 msg: &encrypted.ciphertext,
143 aad,
144 },
145 )
146 .map_err(|e| SecurityError::decryption(format!("Decryption failed: {}", e)))?
147 } else {
148 cipher
149 .decrypt(nonce, encrypted.ciphertext.as_ref())
150 .map_err(|e| SecurityError::decryption(format!("Decryption failed: {}", e)))?
151 };
152
153 Ok(plaintext)
154 }
155
156 fn encrypt_chacha(&self, plaintext: &[u8], aad: Option<&[u8]>) -> Result<EncryptedData> {
157 let cipher = ChaCha20Poly1305::new_from_slice(&self.key)
158 .map_err(|e| SecurityError::encryption(format!("Failed to create cipher: {}", e)))?;
159
160 let mut nonce_bytes = [0u8; 12];
162 getrandom::fill(&mut nonce_bytes).expect("getrandom failed");
163 let nonce = chacha20poly1305::Nonce::from_slice(&nonce_bytes);
164
165 let ciphertext = if let Some(aad_data) = aad {
167 cipher
168 .encrypt(
169 nonce,
170 chacha20poly1305::aead::Payload {
171 msg: plaintext,
172 aad: aad_data,
173 },
174 )
175 .map_err(|e| SecurityError::encryption(format!("Encryption failed: {}", e)))?
176 } else {
177 cipher
178 .encrypt(nonce, plaintext)
179 .map_err(|e| SecurityError::encryption(format!("Encryption failed: {}", e)))?
180 };
181
182 let metadata = EncryptionMetadata::new(
183 self.algorithm,
184 self.key_id.clone(),
185 nonce_bytes.to_vec(),
186 aad.map(|a| a.to_vec()),
187 );
188
189 Ok(EncryptedData::new(ciphertext, metadata))
190 }
191
192 fn decrypt_chacha(&self, encrypted: &EncryptedData) -> Result<Vec<u8>> {
193 let cipher = ChaCha20Poly1305::new_from_slice(&self.key)
194 .map_err(|e| SecurityError::decryption(format!("Failed to create cipher: {}", e)))?;
195
196 if encrypted.metadata.iv.len() != 12 {
197 return Err(SecurityError::decryption(format!(
198 "Invalid nonce length: expected 12, got {}",
199 encrypted.metadata.iv.len()
200 )));
201 }
202
203 let nonce = chacha20poly1305::Nonce::from_slice(&encrypted.metadata.iv);
204
205 let plaintext = if let Some(ref aad) = encrypted.metadata.aad {
206 cipher
207 .decrypt(
208 nonce,
209 chacha20poly1305::aead::Payload {
210 msg: &encrypted.ciphertext,
211 aad,
212 },
213 )
214 .map_err(|e| SecurityError::decryption(format!("Decryption failed: {}", e)))?
215 } else {
216 cipher
217 .decrypt(nonce, encrypted.ciphertext.as_ref())
218 .map_err(|e| SecurityError::decryption(format!("Decryption failed: {}", e)))?
219 };
220
221 Ok(plaintext)
222 }
223
224 pub fn encrypt_in_place(
226 &self,
227 buffer: &mut Vec<u8>,
228 aad: Option<&[u8]>,
229 ) -> Result<EncryptionMetadata> {
230 let encrypted = self.encrypt(buffer, aad)?;
231 buffer.clear();
232 buffer.extend_from_slice(&encrypted.ciphertext);
233 Ok(encrypted.metadata)
234 }
235
236 pub fn algorithm(&self) -> EncryptionAlgorithm {
238 self.algorithm
239 }
240
241 pub fn key_id(&self) -> &str {
243 &self.key_id
244 }
245}
246
247pub struct FieldEncryptor {
249 encryptor: AtRestEncryptor,
250}
251
252impl FieldEncryptor {
253 pub fn new(encryptor: AtRestEncryptor) -> Self {
255 Self { encryptor }
256 }
257
258 pub fn encrypt_string(&self, value: &str) -> Result<String> {
260 let encrypted = self.encryptor.encrypt(value.as_bytes(), None)?;
261 let json = serde_json::to_string(&encrypted)?;
262 Ok(BASE64.encode(json))
263 }
264
265 pub fn decrypt_string(&self, encrypted: &str) -> Result<String> {
267 let json = BASE64
268 .decode(encrypted)
269 .map_err(|e| SecurityError::decryption(format!("Base64 decode failed: {}", e)))?;
270 let encrypted_data: EncryptedData = serde_json::from_slice(&json)?;
271 let plaintext = self.encryptor.decrypt(&encrypted_data)?;
272 String::from_utf8(plaintext)
273 .map_err(|e| SecurityError::decryption(format!("UTF-8 decode failed: {}", e)))
274 }
275
276 pub fn encrypt_json<T: serde::Serialize>(&self, value: &T) -> Result<String> {
278 let json = serde_json::to_vec(value)?;
279 let encrypted = self.encryptor.encrypt(&json, None)?;
280 let encrypted_json = serde_json::to_string(&encrypted)?;
281 Ok(BASE64.encode(encrypted_json))
282 }
283
284 pub fn decrypt_json<T: serde::de::DeserializeOwned>(&self, encrypted: &str) -> Result<T> {
286 let json = BASE64
287 .decode(encrypted)
288 .map_err(|e| SecurityError::decryption(format!("Base64 decode failed: {}", e)))?;
289 let encrypted_data: EncryptedData = serde_json::from_slice(&json)?;
290 let plaintext = self.encryptor.decrypt(&encrypted_data)?;
291 serde_json::from_slice(&plaintext).map_err(SecurityError::from)
292 }
293}
294
295#[cfg(test)]
296mod tests {
297 use super::*;
298
299 #[test]
300 fn test_aes_gcm_encryption() {
301 let key = AtRestEncryptor::generate_key(EncryptionAlgorithm::Aes256Gcm);
302 let encryptor =
303 AtRestEncryptor::new(EncryptionAlgorithm::Aes256Gcm, key, "test-key".to_string())
304 .expect("Failed to create encryptor");
305
306 let plaintext = b"Hello, World!";
307 let encrypted = encryptor
308 .encrypt(plaintext, None)
309 .expect("Encryption failed");
310
311 assert_ne!(encrypted.ciphertext, plaintext);
312 assert_eq!(encrypted.metadata.algorithm, EncryptionAlgorithm::Aes256Gcm);
313
314 let decrypted = encryptor.decrypt(&encrypted).expect("Decryption failed");
315 assert_eq!(decrypted, plaintext);
316 }
317
318 #[test]
319 fn test_aes_gcm_with_aad() {
320 let key = AtRestEncryptor::generate_key(EncryptionAlgorithm::Aes256Gcm);
321 let encryptor =
322 AtRestEncryptor::new(EncryptionAlgorithm::Aes256Gcm, key, "test-key".to_string())
323 .expect("Failed to create encryptor");
324
325 let plaintext = b"Hello, World!";
326 let aad = b"additional data";
327 let encrypted = encryptor
328 .encrypt(plaintext, Some(aad))
329 .expect("Encryption failed");
330
331 let decrypted = encryptor.decrypt(&encrypted).expect("Decryption failed");
332 assert_eq!(decrypted, plaintext);
333 }
334
335 #[test]
336 fn test_chacha_encryption() {
337 let key = AtRestEncryptor::generate_key(EncryptionAlgorithm::ChaCha20Poly1305);
338 let encryptor = AtRestEncryptor::new(
339 EncryptionAlgorithm::ChaCha20Poly1305,
340 key,
341 "test-key".to_string(),
342 )
343 .expect("Failed to create encryptor");
344
345 let plaintext = b"Hello, World!";
346 let encrypted = encryptor
347 .encrypt(plaintext, None)
348 .expect("Encryption failed");
349
350 assert_ne!(encrypted.ciphertext, plaintext);
351 assert_eq!(
352 encrypted.metadata.algorithm,
353 EncryptionAlgorithm::ChaCha20Poly1305
354 );
355
356 let decrypted = encryptor.decrypt(&encrypted).expect("Decryption failed");
357 assert_eq!(decrypted, plaintext);
358 }
359
360 #[test]
361 fn test_field_encryptor_string() {
362 let key = AtRestEncryptor::generate_key(EncryptionAlgorithm::Aes256Gcm);
363 let encryptor =
364 AtRestEncryptor::new(EncryptionAlgorithm::Aes256Gcm, key, "test-key".to_string())
365 .expect("Failed to create encryptor");
366 let field_encryptor = FieldEncryptor::new(encryptor);
367
368 let original = "sensitive data";
369 let encrypted = field_encryptor
370 .encrypt_string(original)
371 .expect("Encryption failed");
372
373 assert_ne!(encrypted, original);
374
375 let decrypted = field_encryptor
376 .decrypt_string(&encrypted)
377 .expect("Decryption failed");
378 assert_eq!(decrypted, original);
379 }
380
381 #[test]
382 fn test_encrypt_in_place() {
383 let key = AtRestEncryptor::generate_key(EncryptionAlgorithm::Aes256Gcm);
384 let encryptor =
385 AtRestEncryptor::new(EncryptionAlgorithm::Aes256Gcm, key, "test-key".to_string())
386 .expect("Failed to create encryptor");
387
388 let mut buffer = b"Hello, World!".to_vec();
389 let original = buffer.clone();
390
391 let metadata = encryptor
392 .encrypt_in_place(&mut buffer, None)
393 .expect("Encryption failed");
394
395 assert_ne!(buffer, original);
396
397 let encrypted = EncryptedData::new(buffer, metadata);
398 let decrypted = encryptor.decrypt(&encrypted).expect("Decryption failed");
399 assert_eq!(decrypted, original);
400 }
401}