leptos_sync_core/security/
mod.rs1use serde::{Deserialize, Serialize};
4use thiserror::Error;
5
6pub mod encryption;
7pub mod compression;
8pub mod hashing;
9
10#[derive(Error, Debug)]
11pub enum SecurityError {
12 #[error("Encryption error: {0}")]
13 Encryption(String),
14 #[error("Decryption error: {0}")]
15 Decryption(String),
16 #[error("Compression error: {0}")]
17 Compression(String),
18 #[error("Decompression error: {0}")]
19 Decompression(String),
20 #[error("Hash error: {0}")]
21 Hash(String),
22 #[error("Invalid key: {0}")]
23 InvalidKey(String),
24 #[error("Invalid algorithm: {0}")]
25 InvalidAlgorithm(String),
26 #[error("Invalid data: {0}")]
27 InvalidData(String),
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct SecurityConfig {
33 pub encryption_enabled: bool,
34 pub compression_enabled: bool,
35 pub encryption_algorithm: EncryptionAlgorithm,
36 pub compression_algorithm: CompressionAlgorithm,
37 pub key_derivation: KeyDerivationConfig,
38 pub integrity_checking: bool,
39}
40
41impl Default for SecurityConfig {
42 fn default() -> Self {
43 Self {
44 encryption_enabled: true,
45 compression_enabled: true,
46 encryption_algorithm: EncryptionAlgorithm::Aes256Gcm,
47 compression_algorithm: CompressionAlgorithm::Lz4,
48 key_derivation: KeyDerivationConfig::default(),
49 integrity_checking: true,
50 }
51 }
52}
53
54pub use encryption::EncryptionAlgorithm;
56
57pub use compression::CompressionAlgorithm;
59
60#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct KeyDerivationConfig {
63 pub algorithm: KeyDerivationAlgorithm,
64 pub iterations: u32,
65 pub salt_length: usize,
66 pub key_length: usize,
67}
68
69impl Default for KeyDerivationConfig {
70 fn default() -> Self {
71 Self {
72 algorithm: KeyDerivationAlgorithm::Argon2,
73 iterations: 100_000,
74 salt_length: 32,
75 key_length: 32,
76 }
77 }
78}
79
80#[derive(Debug, Clone, Serialize, Deserialize)]
82pub enum KeyDerivationAlgorithm {
83 Argon2,
84 Pbkdf2,
85 Scrypt,
86}
87
88pub struct SecurityManager {
90 config: SecurityConfig,
91 encryption: encryption::EncryptionManager,
92 compression: compression::CompressionManager,
93 hashing: hashing::HashManager,
94}
95
96impl SecurityManager {
97 pub fn new(config: SecurityConfig) -> Result<Self, SecurityError> {
98 let encryption = encryption::EncryptionManager::new(config.encryption_algorithm.clone())?;
99 let compression = compression::CompressionManager::new(config.compression_algorithm.clone())?;
100 let hashing = hashing::HashManager::new()?;
101
102 Ok(Self {
103 config,
104 encryption,
105 compression,
106 hashing,
107 })
108 }
109
110 pub async fn secure_data(
112 &self,
113 data: &[u8],
114 key: &[u8],
115 nonce: Option<&[u8]>,
116 ) -> Result<Vec<u8>, SecurityError> {
117 let mut processed_data = data.to_vec();
118
119 if self.config.compression_enabled {
121 processed_data = self.compression.compress(&processed_data)?;
122 }
123
124 if self.config.encryption_enabled {
126 processed_data = self.encryption.encrypt(&processed_data, key, nonce)?;
127 }
128
129 if self.config.integrity_checking {
131 let hash = self.hashing.hash(&processed_data)?;
132 processed_data.extend_from_slice(&hash);
133 }
134
135 Ok(processed_data)
136 }
137
138 pub async fn unsecure_data(
140 &self,
141 data: &[u8],
142 key: &[u8],
143 nonce: Option<&[u8]>,
144 ) -> Result<Vec<u8>, SecurityError> {
145 let mut processed_data = data.to_vec();
146
147 if self.config.integrity_checking {
149 let expected_hash_len = 32; if processed_data.len() < expected_hash_len {
151 return Err(SecurityError::InvalidData("Data too short for integrity check".to_string()));
152 }
153
154 let data_len = processed_data.len() - expected_hash_len;
155 let (data_part, hash_part) = processed_data.split_at(data_len);
156
157 let actual_hash = self.hashing.hash(data_part)?;
158 if actual_hash != hash_part {
159 return Err(SecurityError::Hash("Integrity check failed".to_string()));
160 }
161
162 processed_data = data_part.to_vec();
163 }
164
165 if self.config.encryption_enabled {
167 processed_data = self.encryption.decrypt(&processed_data, key, nonce)?;
168 }
169
170 if self.config.compression_enabled {
172 processed_data = self.compression.decompress(&processed_data)?;
173 }
174
175 Ok(processed_data)
176 }
177
178 pub async fn derive_key(
180 &self,
181 password: &str,
182 salt: Option<&[u8]>,
183 ) -> Result<Vec<u8>, SecurityError> {
184 let salt = salt.unwrap_or_else(|| b"default_salt");
185
186 match self.config.key_derivation.algorithm {
187 KeyDerivationAlgorithm::Argon2 => {
188 self.hashing.derive_key_argon2(
190 password.as_bytes(),
191 salt,
192 self.config.key_derivation.iterations,
193 self.config.key_derivation.key_length,
194 )
195 }
196 KeyDerivationAlgorithm::Pbkdf2 => {
197 self.hashing.derive_key_pbkdf2(
199 password.as_bytes(),
200 salt,
201 self.config.key_derivation.iterations,
202 self.config.key_derivation.key_length,
203 )
204 }
205 KeyDerivationAlgorithm::Scrypt => {
206 self.hashing.derive_key_scrypt(
208 password.as_bytes(),
209 salt,
210 self.config.key_derivation.iterations,
211 self.config.key_derivation.key_length,
212 )
213 }
214 }
215 }
216
217 pub fn generate_nonce(&self) -> Result<Vec<u8>, SecurityError> {
219 self.encryption.generate_nonce()
220 }
221
222 pub fn config(&self) -> &SecurityConfig {
224 &self.config
225 }
226
227 pub fn update_config(&mut self, config: SecurityConfig) -> Result<(), SecurityError> {
229 let encryption = encryption::EncryptionManager::new(config.encryption_algorithm.clone())?;
230 let compression = compression::CompressionManager::new(config.compression_algorithm.clone())?;
231
232 self.config = config;
233 self.encryption = encryption;
234 self.compression = compression;
235
236 Ok(())
237 }
238}
239
240#[cfg(test)]
241mod tests {
242 use super::*;
243
244 #[tokio::test]
245 async fn test_security_manager_creation() {
246 let config = SecurityConfig::default();
247 let manager = SecurityManager::new(config);
248 assert!(manager.is_ok());
249 }
250
251 #[tokio::test]
252 async fn test_security_config_default() {
253 let config = SecurityConfig::default();
254 assert!(config.encryption_enabled);
255 assert!(config.compression_enabled);
256 assert!(config.integrity_checking);
257 }
258
259 #[tokio::test]
260 async fn test_key_derivation_config_default() {
261 let config = KeyDerivationConfig::default();
262 assert_eq!(config.iterations, 100_000);
263 assert_eq!(config.salt_length, 32);
264 assert_eq!(config.key_length, 32);
265 }
266}