1pub mod keyderivation;
36pub mod keymanagement;
37pub mod signatures;
38pub mod keyexchange;
39pub mod hashing;
40pub mod keywrap;
41
42pub use keyderivation::{DerivedKey, Hkdf, PasswordStrength, Pbkdf2};
43pub use keymanagement::{KeyMetadata, KeyStore, RotationPolicy};
44pub use signatures::{Ed25519KeyPair, Ed25519PublicKey, HmacKey, SignatureSuite};
45pub use keyexchange::{X25519KeyPair, X25519PublicKey, SharedSecret};
46pub use hashing::{HashAlgorithm, Hasher, HashOutput};
47pub use keywrap::{KeyWrapper, WrappedKey};
48
49use aes_gcm::{
50 aead::{Aead, KeyInit, OsRng},
51 Aes256Gcm, Nonce,
52};
53use argon2::{
54 password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString},
55 Algorithm, Argon2, Params, Version,
56};
57use hmac::Hmac;
58use rand::RngCore;
59use sha2::Sha256;
60use thiserror::Error;
61use zeroize::{Zeroize, ZeroizeOnDrop};
62
63type HmacSha256 = Hmac<Sha256>;
64
65#[derive(Error, Debug)]
67pub enum CryptoError {
68 #[error("Password hashing failed: {0}")]
69 HashingError(String),
70
71 #[error("Password verification failed")]
72 VerificationError,
73
74 #[error("Encryption failed: {0}")]
75 EncryptionError(String),
76
77 #[error("Decryption failed: {0}")]
78 DecryptionError(String),
79
80 #[error("Invalid key length")]
81 InvalidKeyLength,
82
83 #[error("HMAC generation failed: {0}")]
84 HmacError(String),
85
86 #[error("Weak password: {0}")]
87 WeakPassword(String),
88}
89
90#[derive(Zeroize, ZeroizeOnDrop)]
92pub struct SecurePassword {
93 password: Vec<u8>,
94}
95
96impl SecurePassword {
97 pub fn new(password: impl Into<Vec<u8>>) -> Self {
99 Self {
100 password: password.into(),
101 }
102 }
103
104 pub fn as_bytes(&self) -> &[u8] {
106 &self.password
107 }
108}
109
110#[derive(Zeroize, ZeroizeOnDrop)]
112pub struct SecureKey {
113 key: Vec<u8>,
114}
115
116impl SecureKey {
117 pub fn new(key: Vec<u8>) -> Result<Self, CryptoError> {
119 if key.len() != 32 {
120 return Err(CryptoError::InvalidKeyLength);
121 }
122 Ok(Self { key })
123 }
124
125 pub fn generate() -> Self {
127 let mut key = vec![0u8; 32];
128 OsRng.fill_bytes(&mut key);
129 Self { key }
130 }
131
132 pub fn as_bytes(&self) -> &[u8] {
134 &self.key
135 }
136}
137
138pub mod password {
140 use super::*;
141
142 pub fn hash_password(password: &SecurePassword) -> Result<String, CryptoError> {
149 let salt = SaltString::generate(&mut OsRng);
150 let argon2 = Argon2::default();
151
152 let password_hash = argon2
153 .hash_password(password.as_bytes(), &salt)
154 .map_err(|e| CryptoError::HashingError(e.to_string()))?;
155
156 Ok(password_hash.to_string())
157 }
158
159 pub fn verify_password(password: &SecurePassword, hash: &str) -> Result<bool, CryptoError> {
161 let parsed_hash =
162 PasswordHash::new(hash).map_err(|e| CryptoError::HashingError(e.to_string()))?;
163
164 let argon2 = Argon2::default();
165
166 match argon2.verify_password(password.as_bytes(), &parsed_hash) {
167 Ok(()) => Ok(true),
168 Err(_) => Ok(false),
169 }
170 }
171
172 #[derive(Debug, Clone)]
174 pub struct PasswordStrength {
175 pub min_length: usize,
176 pub require_uppercase: bool,
177 pub require_lowercase: bool,
178 pub require_digit: bool,
179 pub require_special: bool,
180 }
181
182 impl Default for PasswordStrength {
183 fn default() -> Self {
184 Self {
185 min_length: 12,
186 require_uppercase: true,
187 require_lowercase: true,
188 require_digit: true,
189 require_special: true,
190 }
191 }
192 }
193
194 pub fn validate_password_strength(
196 password: &SecurePassword,
197 requirements: &PasswordStrength,
198 ) -> Result<(), CryptoError> {
199 let password_str = std::str::from_utf8(password.as_bytes())
200 .map_err(|_| CryptoError::WeakPassword("Invalid UTF-8".to_string()))?;
201
202 if password_str.len() < requirements.min_length {
203 return Err(CryptoError::WeakPassword(format!(
204 "Password must be at least {} characters",
205 requirements.min_length
206 )));
207 }
208
209 if requirements.require_uppercase && !password_str.chars().any(|c| c.is_uppercase()) {
210 return Err(CryptoError::WeakPassword(
211 "Password must contain uppercase letters".to_string(),
212 ));
213 }
214
215 if requirements.require_lowercase && !password_str.chars().any(|c| c.is_lowercase()) {
216 return Err(CryptoError::WeakPassword(
217 "Password must contain lowercase letters".to_string(),
218 ));
219 }
220
221 if requirements.require_digit && !password_str.chars().any(|c| c.is_ascii_digit()) {
222 return Err(CryptoError::WeakPassword(
223 "Password must contain digits".to_string(),
224 ));
225 }
226
227 if requirements.require_special
228 && !password_str
229 .chars()
230 .any(|c| !c.is_alphanumeric() && !c.is_whitespace())
231 {
232 return Err(CryptoError::WeakPassword(
233 "Password must contain special characters".to_string(),
234 ));
235 }
236
237 Ok(())
238 }
239
240 pub fn derive_key_from_password(
242 password: &SecurePassword,
243 salt: &[u8],
244 ) -> Result<SecureKey, CryptoError> {
245 if salt.len() < 16 {
246 return Err(CryptoError::HashingError(
247 "Salt must be at least 16 bytes".to_string(),
248 ));
249 }
250
251 let params = Params::new(65536, 3, 1, Some(32))
253 .map_err(|e| CryptoError::HashingError(e.to_string()))?;
254
255 let argon2 = Argon2::new(Algorithm::Argon2id, Version::V0x13, params);
256
257 let mut key_bytes = vec![0u8; 32];
258 argon2
259 .hash_password_into(password.as_bytes(), salt, &mut key_bytes)
260 .map_err(|e| CryptoError::HashingError(e.to_string()))?;
261
262 Ok(SecureKey { key: key_bytes })
263 }
264}
265
266pub mod encryption {
268 use super::*;
269
270 pub struct EncryptedData {
272 pub ciphertext: Vec<u8>,
273 pub nonce: [u8; 12],
274 }
275
276 pub fn encrypt(key: &SecureKey, plaintext: &[u8]) -> Result<EncryptedData, CryptoError> {
278 let cipher = Aes256Gcm::new_from_slice(key.as_bytes())
279 .map_err(|e| CryptoError::EncryptionError(e.to_string()))?;
280
281 let mut nonce_bytes = [0u8; 12];
282 OsRng.fill_bytes(&mut nonce_bytes);
283 let nonce = Nonce::from_slice(&nonce_bytes);
284
285 let ciphertext = cipher
286 .encrypt(nonce, plaintext)
287 .map_err(|e| CryptoError::EncryptionError(e.to_string()))?;
288
289 Ok(EncryptedData {
290 ciphertext,
291 nonce: nonce_bytes,
292 })
293 }
294
295 pub fn decrypt(key: &SecureKey, encrypted: &EncryptedData) -> Result<Vec<u8>, CryptoError> {
297 let cipher = Aes256Gcm::new_from_slice(key.as_bytes())
298 .map_err(|e| CryptoError::DecryptionError(e.to_string()))?;
299
300 let nonce = Nonce::from_slice(&encrypted.nonce);
301
302 let plaintext = cipher
303 .decrypt(nonce, encrypted.ciphertext.as_ref())
304 .map_err(|e| CryptoError::DecryptionError(e.to_string()))?;
305
306 Ok(plaintext)
307 }
308}
309
310pub mod random {
312 use super::*;
313
314 pub fn generate_random_bytes(length: usize) -> Vec<u8> {
316 let mut bytes = vec![0u8; length];
317 OsRng.fill_bytes(&mut bytes);
318 bytes
319 }
320
321 pub fn generate_random_hex(length: usize) -> String {
323 let bytes = generate_random_bytes(length);
324 hex::encode(bytes)
325 }
326
327 pub fn generate_salt() -> Vec<u8> {
329 generate_random_bytes(32)
330 }
331}
332
333pub mod hmac_ops {
335 use super::*;
336 use hmac::Mac;
337
338 pub fn compute_hmac(key: &SecureKey, message: &[u8]) -> Result<Vec<u8>, CryptoError> {
340 let mut mac = <HmacSha256 as Mac>::new_from_slice(key.as_bytes())
341 .map_err(|e| CryptoError::HmacError(e.to_string()))?;
342
343 mac.update(message);
344 Ok(mac.finalize().into_bytes().to_vec())
345 }
346
347 pub fn verify_hmac(
349 key: &SecureKey,
350 message: &[u8],
351 expected_hmac: &[u8],
352 ) -> Result<bool, CryptoError> {
353 let mut mac = <HmacSha256 as Mac>::new_from_slice(key.as_bytes())
354 .map_err(|e| CryptoError::HmacError(e.to_string()))?;
355
356 mac.update(message);
357
358 match mac.verify_slice(expected_hmac) {
360 Ok(()) => Ok(true),
361 Err(_) => Ok(false),
362 }
363 }
364}
365
366pub mod secure_compare {
368 pub fn constant_time_compare(a: &[u8], b: &[u8]) -> bool {
370 if a.len() != b.len() {
371 return false;
372 }
373
374 let mut result = 0u8;
375 for (byte_a, byte_b) in a.iter().zip(b.iter()) {
376 result |= byte_a ^ byte_b;
377 }
378
379 result == 0
380 }
381}
382
383#[cfg(test)]
384mod tests {
385 use super::*;
386
387 #[test]
388 fn test_password_hashing() {
389 let password = SecurePassword::new(b"MySecurePassword123!".to_vec());
390 let hash = password::hash_password(&password).unwrap();
391
392 assert!(password::verify_password(&password, &hash).unwrap());
393
394 let wrong_password = SecurePassword::new(b"WrongPassword".to_vec());
395 assert!(!password::verify_password(&wrong_password, &hash).unwrap());
396 }
397
398 #[test]
399 fn test_encryption_decryption() {
400 let key = SecureKey::generate();
401 let plaintext = b"Sensitive financial data: Account 123456, Balance: $50,000";
402
403 let encrypted = encryption::encrypt(&key, plaintext).unwrap();
404 let decrypted = encryption::decrypt(&key, &encrypted).unwrap();
405
406 assert_eq!(plaintext.as_slice(), decrypted.as_slice());
407 }
408
409 #[test]
410 fn test_encryption_with_wrong_key() {
411 let key1 = SecureKey::generate();
412 let key2 = SecureKey::generate();
413 let plaintext = b"Secret data";
414
415 let encrypted = encryption::encrypt(&key1, plaintext).unwrap();
416 let result = encryption::decrypt(&key2, &encrypted);
417
418 assert!(result.is_err());
419 }
420
421 #[test]
422 fn test_random_generation() {
423 let bytes1 = random::generate_random_bytes(32);
424 let bytes2 = random::generate_random_bytes(32);
425
426 assert_eq!(bytes1.len(), 32);
427 assert_eq!(bytes2.len(), 32);
428 assert_ne!(bytes1, bytes2); }
430
431 #[test]
432 fn test_random_hex() {
433 let hex = random::generate_random_hex(16);
434 assert_eq!(hex.len(), 32); }
436
437 #[test]
438 fn test_zeroization() {
439 let password_bytes = b"TestPassword123".to_vec();
440 {
441 let _secure_password = SecurePassword::new(password_bytes.clone());
442 }
444 }
447
448 #[test]
449 fn test_key_length_validation() {
450 let short_key = vec![0u8; 16]; let result = SecureKey::new(short_key);
452 assert!(result.is_err());
453
454 let valid_key = vec![0u8; 32];
455 let result = SecureKey::new(valid_key);
456 assert!(result.is_ok());
457 }
458
459 #[test]
460 fn test_password_strength_validation() {
461 let strong = SecurePassword::new(b"SecurePass123!@#".to_vec());
463 let requirements = password::PasswordStrength::default();
464 assert!(password::validate_password_strength(&strong, &requirements).is_ok());
465
466 let short = SecurePassword::new(b"Short1!".to_vec());
468 let result = password::validate_password_strength(&short, &requirements);
469 assert!(result.is_err());
470
471 let no_upper = SecurePassword::new(b"nouppercasehere123!".to_vec());
473 let result = password::validate_password_strength(&no_upper, &requirements);
474 assert!(result.is_err());
475
476 let no_special = SecurePassword::new(b"NoSpecialChars123".to_vec());
478 let result = password::validate_password_strength(&no_special, &requirements);
479 assert!(result.is_err());
480 }
481
482 #[test]
483 fn test_key_derivation_from_password() {
484 let password = SecurePassword::new(b"MyMasterPassword123!".to_vec());
485 let salt = random::generate_salt();
486
487 let key1 = password::derive_key_from_password(&password, &salt).unwrap();
488 let key2 = password::derive_key_from_password(&password, &salt).unwrap();
489
490 assert_eq!(key1.as_bytes(), key2.as_bytes());
492
493 let different_salt = random::generate_salt();
495 let key3 = password::derive_key_from_password(&password, &different_salt).unwrap();
496 assert_ne!(key1.as_bytes(), key3.as_bytes());
497 }
498
499 #[test]
500 fn test_hmac_generation_and_verification() {
501 let key = SecureKey::generate();
502 let message = b"Important financial transaction data";
503
504 let hmac_result = hmac_ops::compute_hmac(&key, message).unwrap();
505 assert_eq!(hmac_result.len(), 32); assert!(hmac_ops::verify_hmac(&key, message, &hmac_result).unwrap());
509
510 let wrong_key = SecureKey::generate();
512 assert!(!hmac_ops::verify_hmac(&wrong_key, message, &hmac_result).unwrap());
513
514 let modified_message = b"Modified transaction data";
516 assert!(!hmac_ops::verify_hmac(&key, modified_message, &hmac_result).unwrap());
517 }
518
519 #[test]
520 fn test_constant_time_compare() {
521 let data1 = b"secret_data";
522 let data2 = b"secret_data";
523 let data3 = b"different_data";
524
525 assert!(secure_compare::constant_time_compare(data1, data2));
527
528 assert!(!secure_compare::constant_time_compare(data1, data3));
530
531 let short = b"short";
533 assert!(!secure_compare::constant_time_compare(data1, short));
534 }
535
536 #[test]
537 fn test_salt_generation() {
538 let salt1 = random::generate_salt();
539 let salt2 = random::generate_salt();
540
541 assert_eq!(salt1.len(), 32);
542 assert_eq!(salt2.len(), 32);
543 assert_ne!(salt1, salt2); }
545
546 #[test]
547 fn test_password_based_encryption() {
548 let password = SecurePassword::new(b"UserMasterPassword123!".to_vec());
550 let salt = random::generate_salt();
551
552 let key = password::derive_key_from_password(&password, &salt).unwrap();
554
555 let sensitive_data = b"Social Security Number: 123-45-6789";
557 let encrypted = encryption::encrypt(&key, sensitive_data).unwrap();
558
559 let decrypted = encryption::decrypt(&key, &encrypted).unwrap();
561
562 assert_eq!(sensitive_data.as_slice(), decrypted.as_slice());
563 }
564
565 #[test]
566 fn test_multiple_hmac_computations() {
567 let key = SecureKey::generate();
568 let message1 = b"Message 1";
569 let message2 = b"Message 2";
570
571 let hmac1 = hmac_ops::compute_hmac(&key, message1).unwrap();
572 let hmac2 = hmac_ops::compute_hmac(&key, message2).unwrap();
573
574 assert_ne!(hmac1, hmac2);
576
577 assert!(hmac_ops::verify_hmac(&key, message1, &hmac1).unwrap());
579 assert!(hmac_ops::verify_hmac(&key, message2, &hmac2).unwrap());
580
581 assert!(!hmac_ops::verify_hmac(&key, message1, &hmac2).unwrap());
583 assert!(!hmac_ops::verify_hmac(&key, message2, &hmac1).unwrap());
584 }
585
586 #[test]
587 fn test_encryption_with_derived_key() {
588 let password = SecurePassword::new(b"StrongPassword789!@#".to_vec());
589 let salt = random::generate_salt();
590 let key = password::derive_key_from_password(&password, &salt).unwrap();
591
592 let data = b"Encrypted with derived key";
593 let encrypted = encryption::encrypt(&key, data).unwrap();
594
595 let decrypted = encryption::decrypt(&key, &encrypted).unwrap();
597 assert_eq!(data.as_slice(), decrypted.as_slice());
598
599 let wrong_password = SecurePassword::new(b"WrongPassword123!".to_vec());
601 let wrong_key = password::derive_key_from_password(&wrong_password, &salt).unwrap();
602 let result = encryption::decrypt(&wrong_key, &encrypted);
603 assert!(result.is_err());
604 }
605}