oxigdal_security/encryption/
mod.rs1pub mod at_rest;
4pub mod envelope;
5pub mod in_transit;
6pub mod key_management;
7
8pub use at_rest::{AtRestEncryptor, FieldEncryptor};
10pub use envelope::EnvelopeEncryptor;
11pub use in_transit::TlsConfigBuilder;
12pub use key_management::KeyManager;
13
14use crate::error::{Result, SecurityError};
15use serde::{Deserialize, Serialize};
16
17#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
19pub enum EncryptionAlgorithm {
20 #[default]
22 Aes256Gcm,
23 ChaCha20Poly1305,
25}
26
27#[derive(Debug, Clone, Serialize, Deserialize)]
29pub struct EncryptionMetadata {
30 pub algorithm: EncryptionAlgorithm,
32 pub key_id: String,
34 pub iv: Vec<u8>,
36 pub aad: Option<Vec<u8>>,
38 pub encrypted_at: chrono::DateTime<chrono::Utc>,
40}
41
42impl EncryptionMetadata {
43 pub fn new(
45 algorithm: EncryptionAlgorithm,
46 key_id: String,
47 iv: Vec<u8>,
48 aad: Option<Vec<u8>>,
49 ) -> Self {
50 Self {
51 algorithm,
52 key_id,
53 iv,
54 aad,
55 encrypted_at: chrono::Utc::now(),
56 }
57 }
58}
59
60#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct EncryptedData {
63 pub ciphertext: Vec<u8>,
65 pub metadata: EncryptionMetadata,
67}
68
69impl EncryptedData {
70 pub fn new(ciphertext: Vec<u8>, metadata: EncryptionMetadata) -> Self {
72 Self {
73 ciphertext,
74 metadata,
75 }
76 }
77
78 pub fn to_json_bytes(&self) -> Result<Vec<u8>> {
80 serde_json::to_vec(self).map_err(SecurityError::from)
81 }
82
83 pub fn from_json_bytes(bytes: &[u8]) -> Result<Self> {
85 serde_json::from_slice(bytes).map_err(SecurityError::from)
86 }
87}
88
89#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
91pub enum KeyDerivationFunction {
92 Pbkdf2Sha256,
94 #[default]
96 Argon2id,
97}
98
99#[derive(Debug, Clone, Serialize, Deserialize)]
101pub struct KeyDerivationParams {
102 pub kdf: KeyDerivationFunction,
104 pub salt: Vec<u8>,
106 pub iterations: Option<u32>,
108 pub memory_cost: Option<u32>,
110 pub time_cost: Option<u32>,
112 pub parallelism: Option<u32>,
114}
115
116impl KeyDerivationParams {
117 pub fn pbkdf2_recommended(salt: Vec<u8>) -> Self {
119 Self {
120 kdf: KeyDerivationFunction::Pbkdf2Sha256,
121 salt,
122 iterations: Some(600000), memory_cost: None,
124 time_cost: None,
125 parallelism: None,
126 }
127 }
128
129 pub fn argon2_recommended(salt: Vec<u8>) -> Self {
131 Self {
132 kdf: KeyDerivationFunction::Argon2id,
133 salt,
134 iterations: None,
135 memory_cost: Some(19456), time_cost: Some(2),
137 parallelism: Some(1),
138 }
139 }
140}
141
142pub fn derive_key(
144 password: &[u8],
145 params: &KeyDerivationParams,
146 key_length: usize,
147) -> Result<Vec<u8>> {
148 match params.kdf {
149 KeyDerivationFunction::Pbkdf2Sha256 => {
150 let iterations = params
151 .iterations
152 .ok_or_else(|| SecurityError::key_derivation("iterations required for PBKDF2"))?;
153
154 use ring::pbkdf2;
155 let mut key = vec![0u8; key_length];
156 pbkdf2::derive(
157 pbkdf2::PBKDF2_HMAC_SHA256,
158 std::num::NonZeroU32::new(iterations)
159 .ok_or_else(|| SecurityError::key_derivation("invalid iterations"))?,
160 ¶ms.salt,
161 password,
162 &mut key,
163 );
164 Ok(key)
165 }
166 KeyDerivationFunction::Argon2id => {
167 use argon2::{Algorithm, Argon2, Params, Version};
168
169 let memory_cost = params
170 .memory_cost
171 .ok_or_else(|| SecurityError::key_derivation("memory_cost required for Argon2"))?;
172 let time_cost = params
173 .time_cost
174 .ok_or_else(|| SecurityError::key_derivation("time_cost required for Argon2"))?;
175 let parallelism = params
176 .parallelism
177 .ok_or_else(|| SecurityError::key_derivation("parallelism required for Argon2"))?;
178
179 let argon2_params = Params::new(memory_cost, time_cost, parallelism, Some(key_length))
180 .map_err(|e| {
181 SecurityError::key_derivation(format!("invalid Argon2 params: {}", e))
182 })?;
183
184 let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, argon2_params);
185
186 let mut key = vec![0u8; key_length];
187 argon2
188 .hash_password_into(password, ¶ms.salt, &mut key)
189 .map_err(|e| SecurityError::key_derivation(format!("Argon2 error: {}", e)))?;
190
191 Ok(key)
192 }
193 }
194}
195
196#[cfg(test)]
197mod tests {
198 use super::*;
199
200 #[test]
201 fn test_key_derivation_pbkdf2() {
202 let password = b"test_password";
203 let salt = b"test_salt_12345678";
204 let params = KeyDerivationParams::pbkdf2_recommended(salt.to_vec());
205
206 let key = derive_key(password, ¶ms, 32).expect("key derivation failed");
207 assert_eq!(key.len(), 32);
208
209 let key2 = derive_key(password, ¶ms, 32).expect("key derivation failed");
211 assert_eq!(key, key2);
212
213 let key3 = derive_key(b"different", ¶ms, 32).expect("key derivation failed");
215 assert_ne!(key, key3);
216 }
217
218 #[test]
219 fn test_key_derivation_argon2() {
220 let password = b"test_password";
221 let salt = b"test_salt_12345678";
222 let params = KeyDerivationParams::argon2_recommended(salt.to_vec());
223
224 let key = derive_key(password, ¶ms, 32).expect("key derivation failed");
225 assert_eq!(key.len(), 32);
226
227 let key2 = derive_key(password, ¶ms, 32).expect("key derivation failed");
229 assert_eq!(key, key2);
230 }
231
232 #[test]
233 fn test_encryption_metadata_serialization() {
234 let metadata = EncryptionMetadata::new(
235 EncryptionAlgorithm::Aes256Gcm,
236 "key-001".to_string(),
237 vec![1, 2, 3, 4, 5],
238 Some(vec![6, 7, 8]),
239 );
240
241 let json = serde_json::to_string(&metadata).expect("serialization failed");
242 let deserialized: EncryptionMetadata =
243 serde_json::from_str(&json).expect("deserialization failed");
244
245 assert_eq!(deserialized.algorithm, metadata.algorithm);
246 assert_eq!(deserialized.key_id, metadata.key_id);
247 assert_eq!(deserialized.iv, metadata.iv);
248 assert_eq!(deserialized.aad, metadata.aad);
249 }
250}