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