1use std::collections::HashMap;
13
14use aes_gcm::aead::{Aead, KeyInit};
15use aes_gcm::{Aes256Gcm, Key, Nonce};
16use hmac::{Hmac, Mac};
17use pbkdf2::pbkdf2_hmac;
18use rand::rngs::OsRng;
19use rand::RngCore;
20use sha2::{Digest, Sha256};
21use subtle::ConstantTimeEq;
22
23type HmacSha256 = Hmac<Sha256>;
24
25pub fn sha256(data: &[u8]) -> [u8; 32] {
31 let mut hasher = Sha256::new();
32 hasher.update(data);
33 let result = hasher.finalize();
34 let mut out = [0u8; 32];
35 out.copy_from_slice(&result);
36 out
37}
38
39pub fn sha256_hex(data: &[u8]) -> String {
41 sha256(data).iter().map(|b| format!("{:02x}", b)).collect()
42}
43
44pub fn hmac_sha256(key: &[u8], message: &[u8]) -> [u8; 32] {
46 let mut mac = match <HmacSha256 as Mac>::new_from_slice(key) {
49 Ok(m) => m,
50 Err(_) => {
51 return [0u8; 32];
54 }
55 };
56 mac.update(message);
57 let result = mac.finalize().into_bytes();
58 let mut out = [0u8; 32];
59 out.copy_from_slice(&result);
60 out
61}
62
63pub fn hmac_sha256_hex(key: &[u8], message: &[u8]) -> String {
65 hmac_sha256(key, message)
66 .iter()
67 .map(|b| format!("{:02x}", b))
68 .collect()
69}
70
71fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
73 a.ct_eq(b).into()
74}
75
76pub trait Crypter: Send + Sync {
81 fn encrypt(&self, plaintext: &[u8]) -> Result<Vec<u8>, CryptoError>;
82 fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>, CryptoError>;
83}
84
85pub struct AesGcmCrypter {
90 cipher: Aes256Gcm,
91}
92
93impl AesGcmCrypter {
94 pub fn new(key: &[u8; 32]) -> Self {
96 let key = Key::<Aes256Gcm>::from_slice(key);
97 Self {
98 cipher: Aes256Gcm::new(key),
99 }
100 }
101
102 pub fn from_key_str(key: &str) -> Self {
104 let hash = sha256(key.as_bytes());
105 Self::new(&hash)
106 }
107
108 fn random_nonce() -> [u8; 12] {
109 let mut nonce = [0u8; 12];
110 OsRng.fill_bytes(&mut nonce);
111 nonce
112 }
113}
114
115impl Crypter for AesGcmCrypter {
116 fn encrypt(&self, plaintext: &[u8]) -> Result<Vec<u8>, CryptoError> {
117 let nonce_bytes = Self::random_nonce();
118 let nonce = Nonce::from_slice(&nonce_bytes);
119 let ciphertext = self
120 .cipher
121 .encrypt(nonce, plaintext)
122 .map_err(|e| CryptoError::EncryptionFailed(e.to_string()))?;
123 let mut result = Vec::with_capacity(12 + ciphertext.len());
124 result.extend_from_slice(&nonce_bytes);
125 result.extend_from_slice(&ciphertext);
126 Ok(result)
127 }
128
129 fn decrypt(&self, ciphertext: &[u8]) -> Result<Vec<u8>, CryptoError> {
130 if ciphertext.len() < 12 {
131 return Err(CryptoError::DecryptionFailed(
132 "Ciphertext too short".to_string(),
133 ));
134 }
135 let nonce = Nonce::from_slice(&ciphertext[..12]);
136 let encrypted = &ciphertext[12..];
137 self.cipher
138 .decrypt(nonce, encrypted)
139 .map_err(|e| CryptoError::DecryptionFailed(e.to_string()))
140 }
141}
142
143pub trait PasswordHasher: Send + Sync {
148 fn hash(&self, password: &str) -> Result<String, CryptoError>;
149 fn verify(&self, password: &str, hash: &str) -> Result<bool, CryptoError>;
150}
151
152pub struct Pbkdf2Hasher {
157 iterations: u32,
158}
159
160impl Pbkdf2Hasher {
161 const DEFAULT_ITERATIONS: u32 = 100_000;
162 const SALT_LEN: usize = 16;
163 const HASH_LEN: usize = 32;
164
165 pub fn new() -> Self {
166 Self {
167 iterations: Self::DEFAULT_ITERATIONS,
168 }
169 }
170
171 pub fn with_iterations(iterations: u32) -> Self {
172 Self {
173 iterations: iterations.max(1),
174 }
175 }
176
177 fn compute_hash(password: &str, salt: &[u8], iterations: u32) -> [u8; Self::HASH_LEN] {
178 let mut out = [0u8; Self::HASH_LEN];
179 pbkdf2_hmac::<Sha256>(password.as_bytes(), salt, iterations, &mut out);
180 out
181 }
182}
183
184impl Default for Pbkdf2Hasher {
185 fn default() -> Self {
186 Self::new()
187 }
188}
189
190impl PasswordHasher for Pbkdf2Hasher {
191 fn hash(&self, password: &str) -> Result<String, CryptoError> {
192 if password.is_empty() {
193 return Err(CryptoError::InvalidHash(
194 "Password cannot be empty".to_string(),
195 ));
196 }
197 let salt = random_bytes(Self::SALT_LEN);
198 let hash = Self::compute_hash(password, &salt, self.iterations);
199 Ok(format!(
200 "${}${}${}",
201 self.iterations,
202 hex_encode(&salt),
203 hex_encode(&hash)
204 ))
205 }
206
207 fn verify(&self, password: &str, hash: &str) -> Result<bool, CryptoError> {
208 if !hash.starts_with('$') {
209 return Err(CryptoError::InvalidHash("Invalid hash format".to_string()));
210 }
211 let parts: Vec<&str> = hash[1..].splitn(3, '$').collect();
212 if parts.len() != 3 {
213 return Err(CryptoError::InvalidHash("Invalid hash format".to_string()));
214 }
215 let iterations: u32 = parts[0]
216 .parse()
217 .map_err(|_| CryptoError::InvalidHash("Invalid iterations".to_string()))?;
218 let salt = hex_decode(parts[1])
219 .map_err(|_| CryptoError::InvalidHash("Invalid salt hex".to_string()))?;
220 let expected_hash = hex_decode(parts[2])
221 .map_err(|_| CryptoError::InvalidHash("Invalid hash hex".to_string()))?;
222 let computed = Self::compute_hash(password, &salt, iterations);
223 Ok(constant_time_eq(&computed, &expected_hash))
224 }
225}
226
227pub trait ApiSigner: Send + Sync {
232 fn sign(&self, params: &HashMap<String, String>, secret: &str) -> String;
233 fn verify(&self, params: &HashMap<String, String>, secret: &str, signature: &str) -> bool;
234}
235
236pub struct HmacSigner;
240
241impl HmacSigner {
242 pub fn new() -> Self {
243 Self
244 }
245
246 fn compute_signature(params: &HashMap<String, String>, secret: &str) -> String {
247 let mut sorted: Vec<_> = params.iter().collect();
248 sorted.sort_by(|a, b| a.0.cmp(b.0));
249
250 let query_string: String = sorted
251 .iter()
252 .map(|(k, v)| format!("{}={}", k, v))
253 .collect::<Vec<_>>()
254 .join("&");
255
256 hmac_sha256_hex(secret.as_bytes(), query_string.as_bytes())
257 }
258}
259
260impl Default for HmacSigner {
261 fn default() -> Self {
262 Self::new()
263 }
264}
265
266impl ApiSigner for HmacSigner {
267 fn sign(&self, params: &HashMap<String, String>, secret: &str) -> String {
268 Self::compute_signature(params, secret)
269 }
270
271 fn verify(&self, params: &HashMap<String, String>, secret: &str, signature: &str) -> bool {
272 let computed = Self::compute_signature(params, secret);
273 constant_time_eq(computed.as_bytes(), signature.as_bytes())
274 }
275}
276
277fn hex_encode(bytes: &[u8]) -> String {
282 bytes.iter().map(|b| format!("{:02x}", b)).collect()
283}
284
285fn hex_decode(hex: &str) -> Result<Vec<u8>, ()> {
286 if !hex.len().is_multiple_of(2) {
287 return Err(());
288 }
289 (0..hex.len())
290 .step_by(2)
291 .map(|i| u8::from_str_radix(&hex[i..i + 2], 16).map_err(|_| ()))
292 .collect()
293}
294
295fn random_bytes(len: usize) -> Vec<u8> {
296 let mut result = vec![0u8; len];
297 OsRng.fill_bytes(&mut result);
298 result
299}
300
301#[derive(Debug)]
306pub enum CryptoError {
307 EncryptionFailed(String),
308 DecryptionFailed(String),
309 InvalidKey(String),
310 InvalidNonce(String),
311 InvalidHash(String),
312 SigningFailed(String),
313}
314
315impl std::fmt::Display for CryptoError {
316 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
317 match self {
318 CryptoError::EncryptionFailed(msg) => write!(f, "Encryption failed: {}", msg),
319 CryptoError::DecryptionFailed(msg) => write!(f, "Decryption failed: {}", msg),
320 CryptoError::InvalidKey(msg) => write!(f, "Invalid key: {}", msg),
321 CryptoError::InvalidNonce(msg) => write!(f, "Invalid nonce: {}", msg),
322 CryptoError::InvalidHash(msg) => write!(f, "Invalid hash: {}", msg),
323 CryptoError::SigningFailed(msg) => write!(f, "Signing failed: {}", msg),
324 }
325 }
326}
327
328impl std::error::Error for CryptoError {}
329
330impl serde::Serialize for CryptoError {
331 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
332 where
333 S: serde::Serializer,
334 {
335 serializer.serialize_str(&self.to_string())
336 }
337}
338
339#[cfg(test)]
344mod tests {
345 use super::*;
346
347 #[test]
350 fn test_sha256_empty() {
351 assert_eq!(
352 sha256_hex(b""),
353 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
354 );
355 }
356
357 #[test]
358 fn test_sha256_abc() {
359 assert_eq!(
360 sha256_hex(b"abc"),
361 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
362 );
363 }
364
365 #[test]
366 fn test_sha256_hello() {
367 assert_eq!(
368 sha256_hex(b"hello"),
369 "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
370 );
371 }
372
373 #[test]
374 fn test_sha256_long_message() {
375 assert_eq!(
376 sha256_hex(b"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"),
377 "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1"
378 );
379 }
380
381 #[test]
382 fn test_sha256_deterministic() {
383 assert_eq!(sha256_hex(b"test"), sha256_hex(b"test"));
384 assert_ne!(sha256_hex(b"test"), sha256_hex(b"Test"));
385 }
386
387 #[test]
390 fn test_hmac_sha256_rfc4231_case1() {
391 let key = vec![0x0bu8; 20];
392 let result = hmac_sha256_hex(&key, b"Hi There");
393 assert_eq!(
394 result,
395 "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"
396 );
397 }
398
399 #[test]
400 fn test_hmac_sha256_rfc4231_case2() {
401 let result = hmac_sha256_hex(b"Jefe", b"what do ya want for nothing?");
402 assert_eq!(
403 result,
404 "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843"
405 );
406 }
407
408 #[test]
409 fn test_hmac_sha256_long_key() {
410 let key = vec![0xaau8; 130];
411 let result = hmac_sha256_hex(&key, b"test message");
412 assert_eq!(result.len(), 64);
413 let short_key = vec![0xaau8; 32];
414 let result_short = hmac_sha256_hex(&short_key, b"test message");
415 assert_ne!(result, result_short);
416 }
417
418 #[test]
419 fn test_hmac_sha256_different_messages() {
420 let key = b"secret";
421 assert_ne!(hmac_sha256_hex(key, b"msg1"), hmac_sha256_hex(key, b"msg2"));
422 }
423
424 #[test]
427 fn test_aes_gcm_roundtrip() {
428 let key = [0x42u8; 32];
429 let crypter = AesGcmCrypter::new(&key);
430 let plaintext = b"Hello, World!";
431 let encrypted = crypter.encrypt(plaintext).unwrap();
432 let decrypted = crypter.decrypt(&encrypted).unwrap();
433 assert_eq!(decrypted, plaintext);
434 }
435
436 #[test]
437 fn test_aes_gcm_random_nonce_per_encryption() {
438 let key = [0x42u8; 32];
439 let crypter = AesGcmCrypter::new(&key);
440 let plaintext = b"same plaintext";
441 let encrypted1 = crypter.encrypt(plaintext).unwrap();
442 let encrypted2 = crypter.encrypt(plaintext).unwrap();
443 assert_ne!(encrypted1, encrypted2, "随机 nonce 应使密文不同");
444 assert_eq!(crypter.decrypt(&encrypted1).unwrap(), plaintext);
445 assert_eq!(crypter.decrypt(&encrypted2).unwrap(), plaintext);
446 }
447
448 #[test]
449 fn test_aes_gcm_from_key_str() {
450 let crypter = AesGcmCrypter::from_key_str("my-secret-key");
451 let plaintext = b"data to encrypt";
452 let encrypted = crypter.encrypt(plaintext).unwrap();
453 let decrypted = crypter.decrypt(&encrypted).unwrap();
454 assert_eq!(decrypted, plaintext);
455 }
456
457 #[test]
458 fn test_aes_gcm_short_ciphertext() {
459 let key = [0x42u8; 32];
460 let crypter = AesGcmCrypter::new(&key);
461 assert!(crypter.decrypt(&[0u8; 8]).is_err());
462 }
463
464 #[test]
465 fn test_aes_gcm_empty_plaintext() {
466 let key = [0x42u8; 32];
467 let crypter = AesGcmCrypter::new(&key);
468 let encrypted = crypter.encrypt(b"").unwrap();
469 assert_eq!(encrypted.len(), 28);
471 let decrypted = crypter.decrypt(&encrypted).unwrap();
472 assert_eq!(decrypted, b"");
473 }
474
475 #[test]
476 fn test_aes_gcm_tampered_ciphertext() {
477 let key = [0x42u8; 32];
478 let crypter = AesGcmCrypter::new(&key);
479 let encrypted = crypter.encrypt(b"sensitive data").unwrap();
480 let mut tampered = encrypted.clone();
481 tampered[15] ^= 0x01;
482 assert!(crypter.decrypt(&tampered).is_err());
483 }
484
485 #[test]
488 fn test_pbkdf2_hasher_hash_format() {
489 let hasher = Pbkdf2Hasher::new();
490 let hash = hasher.hash("password123").unwrap();
491 assert!(hash.starts_with('$'));
492 let parts: Vec<&str> = hash[1..].splitn(3, '$').collect();
493 assert_eq!(parts.len(), 3);
494 assert_eq!(parts[0].parse::<u32>().unwrap(), 100_000);
495 assert_eq!(parts[1].len(), 32);
497 assert_eq!(parts[2].len(), 64);
499 }
500
501 #[test]
502 fn test_pbkdf2_hasher_verify_correct() {
503 let hasher = Pbkdf2Hasher::new();
504 let hash = hasher.hash("password123").unwrap();
505 assert!(hasher.verify("password123", &hash).unwrap());
506 }
507
508 #[test]
509 fn test_pbkdf2_hasher_verify_wrong() {
510 let hasher = Pbkdf2Hasher::new();
511 let hash = hasher.hash("password123").unwrap();
512 assert!(!hasher.verify("wrongpassword", &hash).unwrap());
513 }
514
515 #[test]
516 fn test_pbkdf2_hasher_different_passwords_different_hashes() {
517 let hasher = Pbkdf2Hasher::new();
518 let h1 = hasher.hash("pass1").unwrap();
519 let h2 = hasher.hash("pass2").unwrap();
520 assert_ne!(h1, h2);
521 }
522
523 #[test]
524 fn test_pbkdf2_hasher_same_password_different_salts() {
525 let hasher = Pbkdf2Hasher::new();
526 let h1 = hasher.hash("same").unwrap();
527 let h2 = hasher.hash("same").unwrap();
528 assert_ne!(h1, h2);
529 assert!(hasher.verify("same", &h1).unwrap());
530 assert!(hasher.verify("same", &h2).unwrap());
531 }
532
533 #[test]
534 fn test_pbkdf2_hasher_invalid_format() {
535 let hasher = Pbkdf2Hasher::new();
536 assert!(hasher.verify("password", "invalid-hash").is_err());
537 assert!(hasher.verify("password", "$abc").is_err());
538 assert!(hasher.verify("password", "$abc$def").is_err());
539 }
540
541 #[test]
542 fn test_pbkdf2_hasher_with_iterations() {
543 let hasher = Pbkdf2Hasher::with_iterations(1000);
544 let hash = hasher.hash("secret").unwrap();
545 let parts: Vec<&str> = hash[1..].splitn(3, '$').collect();
546 assert_eq!(parts[0], "1000");
547 assert!(hasher.verify("secret", &hash).unwrap());
548 }
549
550 #[test]
551 fn test_pbkdf2_hasher_empty_password() {
552 let hasher = Pbkdf2Hasher::new();
553 assert!(hasher.hash("").is_err());
554 }
555
556 #[test]
559 fn test_hmac_signer_sign_not_empty() {
560 let signer = HmacSigner::new();
561 let mut params = HashMap::new();
562 params.insert("name".to_string(), "test".to_string());
563 let signature = signer.sign(¶ms, "secret123");
564 assert_eq!(signature.len(), 64);
565 }
566
567 #[test]
568 fn test_hmac_signer_verify_correct() {
569 let signer = HmacSigner::new();
570 let mut params = HashMap::new();
571 params.insert("name".to_string(), "test".to_string());
572 params.insert("age".to_string(), "25".to_string());
573
574 let signature = signer.sign(¶ms, "mysecret");
575 assert!(signer.verify(¶ms, "mysecret", &signature));
576 }
577
578 #[test]
579 fn test_hmac_signer_verify_wrong_secret() {
580 let signer = HmacSigner::new();
581 let mut params = HashMap::new();
582 params.insert("name".to_string(), "test".to_string());
583 let signature = signer.sign(¶ms, "correctsecret");
584 assert!(!signer.verify(¶ms, "wrongsecret", &signature));
585 }
586
587 #[test]
588 fn test_hmac_signer_verify_wrong_signature() {
589 let signer = HmacSigner::new();
590 let mut params = HashMap::new();
591 params.insert("name".to_string(), "test".to_string());
592 let valid_sig = signer.sign(¶ms, "secret");
593 let tampered = if let Some(stripped) = valid_sig.strip_prefix('0') {
594 format!("1{}", stripped)
595 } else {
596 format!("0{}", &valid_sig[1..])
597 };
598 assert!(!signer.verify(¶ms, "secret", &tampered));
599 }
600
601 #[test]
602 fn test_hmac_signer_different_params_different_signatures() {
603 let signer = HmacSigner::new();
604 let mut params1 = HashMap::new();
605 params1.insert("a".to_string(), "1".to_string());
606
607 let mut params2 = HashMap::new();
608 params2.insert("b".to_string(), "2".to_string());
609
610 let sig1 = signer.sign(¶ms1, "secret");
611 let sig2 = signer.sign(¶ms2, "secret");
612 assert_ne!(sig1, sig2);
613 }
614
615 #[test]
616 fn test_hmac_signer_param_order_independent() {
617 let signer = HmacSigner::new();
618 let mut params1 = HashMap::new();
619 params1.insert("b".to_string(), "2".to_string());
620 params1.insert("a".to_string(), "1".to_string());
621
622 let mut params2 = HashMap::new();
623 params2.insert("a".to_string(), "1".to_string());
624 params2.insert("b".to_string(), "2".to_string());
625
626 let sig1 = signer.sign(¶ms1, "secret");
627 let sig2 = signer.sign(¶ms2, "secret");
628 assert_eq!(sig1, sig2);
629 }
630
631 #[test]
632 fn test_hmac_signer_empty_params() {
633 let signer = HmacSigner::new();
634 let params = HashMap::new();
635 let sig = signer.sign(¶ms, "secret");
636 assert_eq!(sig.len(), 64);
637 assert!(signer.verify(¶ms, "secret", &sig));
638 }
639
640 #[test]
643 fn test_random_bytes_length() {
644 assert_eq!(random_bytes(0).len(), 0);
645 assert_eq!(random_bytes(16).len(), 16);
646 assert_eq!(random_bytes(100).len(), 100);
647 }
648
649 #[test]
650 fn test_random_bytes_random() {
651 let a = random_bytes(32);
652 let b = random_bytes(32);
653 assert_ne!(a, b, "随机字节序列应不同");
654 }
655
656 #[test]
657 fn test_constant_time_eq() {
658 assert!(constant_time_eq(b"abc", b"abc"));
659 assert!(!constant_time_eq(b"abc", b"abd"));
660 assert!(!constant_time_eq(b"abc", b"ab"));
661 assert!(!constant_time_eq(b"abc", b"abcd"));
662 assert!(constant_time_eq(b"", b""));
663 }
664
665 #[test]
666 fn test_hex_encode_decode_roundtrip() {
667 let original = vec![0x00, 0xff, 0xab, 0x42];
668 let encoded = hex_encode(&original);
669 let decoded = hex_decode(&encoded).unwrap();
670 assert_eq!(decoded, original);
671 }
672
673 #[test]
674 fn test_hex_decode_invalid() {
675 assert!(hex_decode("abc").is_err());
676 assert!(hex_decode("xy").is_err());
677 }
678}