1#[cfg(all(feature = "session-encryption", not(target_arch = "wasm32")))]
6use aes_gcm::{
7 aead::{Aead, KeyInit},
8 Aes256Gcm, Key, Nonce,
9};
10
11#[cfg(all(feature = "session-encryption", not(target_arch = "wasm32")))]
12use argon2::Argon2;
13
14#[cfg(feature = "session-encryption")]
15use crate::error::{Error, Result};
16#[cfg(feature = "session-encryption")]
17use crate::session::SessionData;
18#[cfg(feature = "session-encryption")]
19use rand::RngCore;
20#[cfg(feature = "session-encryption")]
21use serde::{Deserialize, Serialize};
22
23#[cfg(feature = "session-encryption")]
25#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct EncryptedSessionData {
27 pub encrypted_data: Vec<u8>,
29 pub nonce: Vec<u8>,
31 pub salt: Option<Vec<u8>>,
33 pub metadata: EncryptionMetadata,
35}
36
37#[cfg(feature = "session-encryption")]
39#[derive(Debug, Clone, Serialize, Deserialize)]
40pub struct EncryptionMetadata {
41 pub algorithm: String,
43 pub kdf: Option<String>,
45 pub version: u32,
47}
48
49#[cfg(all(feature = "session-encryption", not(target_arch = "wasm32")))]
51pub struct SessionEncryptor {
52 cipher: Aes256Gcm,
53}
54
55#[cfg(all(feature = "session-encryption", not(target_arch = "wasm32")))]
56impl SessionEncryptor {
57 pub fn new(key: [u8; 32]) -> Result<Self> {
59 let key = Key::<Aes256Gcm>::from_slice(&key);
60 let cipher = Aes256Gcm::new(key);
61 Ok(Self { cipher })
62 }
63
64 pub fn from_password(password: &str, salt: Option<&[u8]>) -> Result<(Self, Vec<u8>)> {
66 let salt = match salt {
67 Some(s) => s.to_vec(),
68 None => {
69 let mut salt = vec![0u8; 16];
70 rand::thread_rng().fill_bytes(&mut salt);
71 salt
72 }
73 };
74
75 let argon2 = Argon2::default();
76 let mut key = [0u8; 32];
77
78 argon2
79 .hash_password_into(password.as_bytes(), &salt, &mut key)
80 .map_err(|e| Error::crypto(format!("Failed to derive key from password: {}", e)))?;
81
82 let encryptor = Self::new(key)?;
83 Ok((encryptor, salt))
84 }
85
86 pub fn encrypt_session(&self, session_data: &SessionData) -> Result<SessionData> {
88 let serialized = serde_json::to_vec(session_data).map_err(|e| {
90 Error::crypto(format!("Failed to serialize session for encryption: {}", e))
91 })?;
92
93 let nonce_bytes = rand::random::<[u8; 12]>();
95 let nonce = Nonce::from_slice(&nonce_bytes);
96
97 let encrypted_data = self
99 .cipher
100 .encrypt(nonce, serialized.as_ref())
101 .map_err(|e| Error::crypto(format!("Failed to encrypt session: {}", e)))?;
102
103 let encrypted_container = EncryptedSessionData {
105 encrypted_data,
106 nonce: nonce.to_vec(),
107 salt: None,
108 metadata: EncryptionMetadata {
109 algorithm: "AES-256-GCM".to_string(),
110 kdf: None,
111 version: 1,
112 },
113 };
114
115 let mut encrypted_session = session_data.clone();
117 encrypted_session.platform_data.insert(
118 "encrypted_payload".to_string(),
119 serde_json::to_value(&encrypted_container).map_err(|e| {
120 Error::crypto(format!("Failed to serialize encrypted container: {}", e))
121 })?,
122 );
123
124 encrypted_session.session.access_token = "***ENCRYPTED***".to_string();
126 encrypted_session.session.refresh_token = "***ENCRYPTED***".to_string();
127 encrypted_session.session.user.email = None;
128 encrypted_session.session.user.phone = None;
129
130 Ok(encrypted_session)
131 }
132
133 pub fn decrypt_session(&self, encrypted_session: &SessionData) -> Result<SessionData> {
135 let encrypted_container_value = encrypted_session
137 .platform_data
138 .get("encrypted_payload")
139 .ok_or_else(|| Error::crypto("No encrypted payload found in session"))?;
140
141 let encrypted_container: EncryptedSessionData =
142 serde_json::from_value(encrypted_container_value.clone()).map_err(|e| {
143 Error::crypto(format!("Failed to deserialize encrypted container: {}", e))
144 })?;
145
146 if encrypted_container.metadata.algorithm != "AES-256-GCM" {
148 return Err(Error::crypto(format!(
149 "Unsupported encryption algorithm: {}",
150 encrypted_container.metadata.algorithm
151 )));
152 }
153
154 if encrypted_container.metadata.version != 1 {
155 return Err(Error::crypto(format!(
156 "Unsupported encryption version: {}",
157 encrypted_container.metadata.version
158 )));
159 }
160
161 let nonce = Nonce::from_slice(&encrypted_container.nonce);
163 let decrypted_data = self
164 .cipher
165 .decrypt(nonce, encrypted_container.encrypted_data.as_ref())
166 .map_err(|e| Error::crypto(format!("Failed to decrypt session: {}", e)))?;
167
168 let original_session: SessionData =
170 serde_json::from_slice(&decrypted_data).map_err(|e| {
171 Error::crypto(format!("Failed to deserialize decrypted session: {}", e))
172 })?;
173
174 Ok(original_session)
175 }
176
177 pub fn generate_key() -> [u8; 32] {
179 rand::random()
180 }
181}
182
183#[cfg(all(feature = "session-encryption", target_arch = "wasm32"))]
185#[derive(Debug)]
186pub struct SessionEncryptor {
187 key: [u8; 32],
188}
189
190#[cfg(all(feature = "session-encryption", target_arch = "wasm32"))]
191impl SessionEncryptor {
192 pub fn new(key: [u8; 32]) -> Result<Self> {
194 Ok(Self { key })
195 }
196
197 pub fn encrypt_session(&self, session_data: &SessionData) -> Result<SessionData> {
199 let serialized = serde_json::to_vec(session_data).map_err(|e| {
204 Error::crypto(format!("Failed to serialize session for encryption: {}", e))
205 })?;
206
207 let mut encrypted_data = Vec::with_capacity(serialized.len());
209 for (i, byte) in serialized.iter().enumerate() {
210 encrypted_data.push(byte ^ self.key[i % 32]);
211 }
212
213 let encrypted_container = EncryptedSessionData {
215 encrypted_data,
216 nonce: vec![0; 12], salt: None,
218 metadata: EncryptionMetadata {
219 algorithm: "XOR-DEMO".to_string(),
220 kdf: None,
221 version: 1,
222 },
223 };
224
225 let mut encrypted_session = session_data.clone();
227 encrypted_session.platform_data.insert(
228 "encrypted_payload".to_string(),
229 serde_json::to_value(&encrypted_container).map_err(|e| {
230 Error::crypto(format!("Failed to serialize encrypted container: {}", e))
231 })?,
232 );
233
234 encrypted_session.session.access_token = "***ENCRYPTED***".to_string();
236 encrypted_session.session.refresh_token = "***ENCRYPTED***".to_string();
237 encrypted_session.session.user.email = None;
238 encrypted_session.session.user.phone = None;
239
240 Ok(encrypted_session)
241 }
242
243 pub fn decrypt_session(&self, encrypted_session: &SessionData) -> Result<SessionData> {
245 let encrypted_container_value = encrypted_session
247 .platform_data
248 .get("encrypted_payload")
249 .ok_or_else(|| Error::crypto("No encrypted payload found in session"))?;
250
251 let encrypted_container: EncryptedSessionData =
252 serde_json::from_value(encrypted_container_value.clone()).map_err(|e| {
253 Error::crypto(format!("Failed to deserialize encrypted container: {}", e))
254 })?;
255
256 if encrypted_container.metadata.algorithm != "XOR-DEMO" {
258 return Err(Error::crypto(format!(
259 "Unsupported encryption algorithm: {}",
260 encrypted_container.metadata.algorithm
261 )));
262 }
263
264 let mut decrypted_data = Vec::with_capacity(encrypted_container.encrypted_data.len());
266 for (i, byte) in encrypted_container.encrypted_data.iter().enumerate() {
267 decrypted_data.push(byte ^ self.key[i % 32]);
268 }
269
270 let original_session: SessionData =
272 serde_json::from_slice(&decrypted_data).map_err(|e| {
273 Error::crypto(format!("Failed to deserialize decrypted session: {}", e))
274 })?;
275
276 Ok(original_session)
277 }
278
279 pub fn generate_key() -> [u8; 32] {
281 [0; 32] }
285}
286
287#[cfg(feature = "session-encryption")]
289pub struct KeyManager;
290
291#[cfg(feature = "session-encryption")]
292impl KeyManager {
293 pub fn generate_encryption_key() -> [u8; 32] {
295 SessionEncryptor::generate_key()
296 }
297
298 #[cfg(not(target_arch = "wasm32"))]
300 pub fn derive_key_from_password(
301 password: &str,
302 salt: Option<&[u8]>,
303 ) -> Result<([u8; 32], Vec<u8>)> {
304 use rand::RngCore;
305
306 let salt = salt.map(|s| s.to_vec()).unwrap_or_else(|| {
307 let mut salt = vec![0u8; 16];
308 rand::thread_rng().fill_bytes(&mut salt);
309 salt
310 });
311
312 let mut key = [0u8; 32];
315 let combined = format!("{}{}", password, hex::encode(&salt));
316 let hash = combined.bytes().cycle().take(32).collect::<Vec<_>>();
317 key.copy_from_slice(&hash);
318
319 Ok((key, salt))
320 }
321
322 #[cfg(all(feature = "session-encryption", not(target_arch = "wasm32")))]
324 pub fn store_key_securely(service: &str, username: &str, key: &[u8; 32]) -> Result<()> {
325 let entry = keyring::Entry::new(service, username)
326 .map_err(|e| Error::crypto(format!("Failed to create keyring entry: {}", e)))?;
327
328 let key_hex = hex::encode(key);
329 entry
330 .set_password(&key_hex)
331 .map_err(|e| Error::crypto(format!("Failed to store key in keyring: {}", e)))?;
332
333 Ok(())
334 }
335
336 #[cfg(all(feature = "session-encryption", not(target_arch = "wasm32")))]
338 pub fn retrieve_key_securely(service: &str, username: &str) -> Result<[u8; 32]> {
339 let entry = keyring::Entry::new(service, username)
340 .map_err(|e| Error::crypto(format!("Failed to create keyring entry: {}", e)))?;
341
342 let key_hex = entry
343 .get_password()
344 .map_err(|e| Error::crypto(format!("Failed to retrieve key from keyring: {}", e)))?;
345
346 let key_bytes = hex::decode(&key_hex)
347 .map_err(|e| Error::crypto(format!("Failed to decode key from hex: {}", e)))?;
348
349 if key_bytes.len() != 32 {
350 return Err(Error::crypto("Invalid key length"));
351 }
352
353 let mut key = [0u8; 32];
354 key.copy_from_slice(&key_bytes);
355 Ok(key)
356 }
357}