1use rand::rngs::OsRng;
25use rand::RngCore;
26use serde::{Deserialize, Serialize};
27use sha2::{Digest, Sha256};
28use std::collections::HashMap;
29use std::fmt;
30use std::sync::RwLock;
31use std::time::{Duration, SystemTime};
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
39pub enum KeyAlgorithm {
40 Aes256Gcm,
42 HmacSha256,
44 Rsa2048,
46 Rsa4096,
48}
49
50impl KeyAlgorithm {
51 pub fn as_str(&self) -> &'static str {
53 match self {
54 KeyAlgorithm::Aes256Gcm => "aes-256-gcm",
55 KeyAlgorithm::HmacSha256 => "hmac-sha256",
56 KeyAlgorithm::Rsa2048 => "rsa-2048",
57 KeyAlgorithm::Rsa4096 => "rsa-4096",
58 }
59 }
60
61 pub fn key_length(&self) -> usize {
63 match self {
64 KeyAlgorithm::Aes256Gcm => 32,
65 KeyAlgorithm::HmacSha256 => 32,
66 KeyAlgorithm::Rsa2048 => 256,
67 KeyAlgorithm::Rsa4096 => 512,
68 }
69 }
70
71 pub fn is_symmetric(&self) -> bool {
73 matches!(self, KeyAlgorithm::Aes256Gcm | KeyAlgorithm::HmacSha256)
74 }
75}
76
77impl fmt::Display for KeyAlgorithm {
78 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79 f.write_str(self.as_str())
80 }
81}
82
83#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
85pub enum KeyPurpose {
86 Encryption,
88 Signing,
90 EncryptionAndSigning,
92}
93
94impl KeyPurpose {
95 pub fn as_str(&self) -> &'static str {
97 match self {
98 KeyPurpose::Encryption => "encryption",
99 KeyPurpose::Signing => "signing",
100 KeyPurpose::EncryptionAndSigning => "encryption+signing",
101 }
102 }
103
104 pub fn can_encrypt(&self) -> bool {
106 matches!(
107 self,
108 KeyPurpose::Encryption | KeyPurpose::EncryptionAndSigning
109 )
110 }
111
112 pub fn can_sign(&self) -> bool {
114 matches!(self, KeyPurpose::Signing | KeyPurpose::EncryptionAndSigning)
115 }
116}
117
118impl fmt::Display for KeyPurpose {
119 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120 f.write_str(self.as_str())
121 }
122}
123
124#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
130pub enum KeyStatus {
131 Active,
133 Deprecated,
135 Revoked,
137 Expired,
139}
140
141impl KeyStatus {
142 pub fn as_str(&self) -> &'static str {
144 match self {
145 KeyStatus::Active => "active",
146 KeyStatus::Deprecated => "deprecated",
147 KeyStatus::Revoked => "revoked",
148 KeyStatus::Expired => "expired",
149 }
150 }
151
152 pub fn is_usable_for_new(&self) -> bool {
154 matches!(self, KeyStatus::Active)
155 }
156
157 pub fn is_usable_for_old(&self) -> bool {
159 matches!(
160 self,
161 KeyStatus::Active | KeyStatus::Deprecated | KeyStatus::Expired
162 )
163 }
164
165 pub fn is_dead(&self) -> bool {
167 matches!(self, KeyStatus::Revoked)
168 }
169}
170
171impl fmt::Display for KeyStatus {
172 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173 f.write_str(self.as_str())
174 }
175}
176
177#[derive(Debug, Clone, Serialize, Deserialize)]
183pub struct KeyMetadata {
184 pub key_id: String,
186 pub name: String,
188 pub algorithm: KeyAlgorithm,
190 pub purpose: KeyPurpose,
192 pub version: u32,
194 pub created_at: SystemTime,
196 pub expires_at: Option<SystemTime>,
198 pub status: KeyStatus,
200 pub description: String,
202 pub tags: Vec<String>,
204}
205
206impl KeyMetadata {
207 fn new(
209 key_id: String,
210 name: String,
211 algorithm: KeyAlgorithm,
212 purpose: KeyPurpose,
213 version: u32,
214 ) -> Self {
215 Self {
216 key_id,
217 name,
218 algorithm,
219 purpose,
220 version,
221 created_at: SystemTime::now(),
222 expires_at: None,
223 status: KeyStatus::Active,
224 description: String::new(),
225 tags: Vec::new(),
226 }
227 }
228
229 pub fn with_expiry(mut self, expires_at: SystemTime) -> Self {
231 self.expires_at = Some(expires_at);
232 self
233 }
234
235 pub fn with_description(mut self, description: impl Into<String>) -> Self {
237 self.description = description.into();
238 self
239 }
240
241 pub fn with_tag(mut self, tag: impl Into<String>) -> Self {
243 self.tags.push(tag.into());
244 self
245 }
246
247 pub fn is_expired(&self) -> bool {
249 match self.expires_at {
250 Some(expiry) => SystemTime::now() >= expiry,
251 None => false,
252 }
253 }
254
255 pub fn age(&self) -> Duration {
257 SystemTime::now()
258 .duration_since(self.created_at)
259 .unwrap_or_default()
260 }
261}
262
263#[derive(Debug, Clone)]
265pub struct KeyEntry {
266 pub metadata: KeyMetadata,
268 pub material: Vec<u8>,
270 pub fingerprint: String,
272}
273
274impl KeyEntry {
275 pub fn compute_fingerprint(material: &[u8]) -> String {
277 let mut hasher = Sha256::new();
278 hasher.update(material);
279 let result = hasher.finalize();
280 result.iter().map(|b| format!("{:02x}", b)).collect()
281 }
282
283 pub fn verify_fingerprint(&self) -> bool {
285 Self::compute_fingerprint(&self.material) == self.fingerprint
286 }
287}
288
289#[derive(Debug, Default)]
295pub struct KeyGenerator;
296
297impl KeyGenerator {
298 pub fn new() -> Self {
300 Self
301 }
302
303 pub fn generate_material(&self, algorithm: KeyAlgorithm) -> Vec<u8> {
305 let mut material = vec![0u8; algorithm.key_length()];
306 OsRng.fill_bytes(&mut material);
307 material
308 }
309
310 pub fn generate(
312 &self,
313 name: impl Into<String>,
314 algorithm: KeyAlgorithm,
315 purpose: KeyPurpose,
316 version: u32,
317 ) -> KeyEntry {
318 let material = self.generate_material(algorithm);
319 let fingerprint = KeyEntry::compute_fingerprint(&material);
320 let key_id = Self::generate_key_id();
321 let metadata = KeyMetadata::new(key_id, name.into(), algorithm, purpose, version);
322 KeyEntry {
323 metadata,
324 material,
325 fingerprint,
326 }
327 }
328
329 pub fn generate_key_id() -> String {
331 let mut bytes = [0u8; 16];
332 OsRng.fill_bytes(&mut bytes);
333 bytes.iter().map(|b| format!("{:02x}", b)).collect()
334 }
335}
336
337#[derive(Debug, Clone, Default)]
343pub enum RotationPolicy {
344 TimeInterval(Duration),
346 UsageCount(u64),
348 TimeIntervalOrUsage(Duration, u64),
350 #[default]
352 Never,
353}
354
355impl RotationPolicy {
356 pub fn needs_rotation(&self, age: Duration, usage: u64) -> bool {
362 match self {
363 RotationPolicy::TimeInterval(interval) => age >= *interval,
364 RotationPolicy::UsageCount(count) => usage >= *count,
365 RotationPolicy::TimeIntervalOrUsage(interval, count) => {
366 age >= *interval || usage >= *count
367 }
368 RotationPolicy::Never => false,
369 }
370 }
371
372 pub fn as_str(&self) -> &'static str {
374 match self {
375 RotationPolicy::TimeInterval(_) => "time-interval",
376 RotationPolicy::UsageCount(_) => "usage-count",
377 RotationPolicy::TimeIntervalOrUsage(_, _) => "time-or-usage",
378 RotationPolicy::Never => "never",
379 }
380 }
381}
382
383#[derive(Debug, Default)]
392pub struct KeyStore {
393 keys: HashMap<String, KeyEntry>,
395 name_index: HashMap<String, Vec<String>>,
397}
398
399impl KeyStore {
400 pub fn new() -> Self {
402 Self::default()
403 }
404
405 pub fn put(&mut self, entry: KeyEntry) -> String {
407 let key_id = entry.metadata.key_id.clone();
408 let name = entry.metadata.name.clone();
409 self.keys.insert(key_id.clone(), entry);
410 let list = self.name_index.entry(name).or_default();
411 list.push(key_id.clone());
412 list.sort_by_key(|id| {
414 std::cmp::Reverse(self.keys.get(id).map(|e| e.metadata.version).unwrap_or(0))
415 });
416 key_id
417 }
418
419 pub fn get(&self, key_id: &str) -> Option<&KeyEntry> {
421 self.keys.get(key_id)
422 }
423
424 pub fn get_mut(&mut self, key_id: &str) -> Option<&mut KeyEntry> {
426 self.keys.get_mut(key_id)
427 }
428
429 pub fn get_latest_by_name(&self, name: &str) -> Option<&KeyEntry> {
431 let list = self.name_index.get(name)?;
432 let latest_id = list.first()?;
433 self.keys.get(latest_id)
434 }
435
436 pub fn get_by_name_and_version(&self, name: &str, version: u32) -> Option<&KeyEntry> {
438 let list = self.name_index.get(name)?;
439 for id in list {
440 if let Some(entry) = self.keys.get(id) {
441 if entry.metadata.version == version {
442 return Some(entry);
443 }
444 }
445 }
446 None
447 }
448
449 pub fn get_all_versions(&self, name: &str) -> Vec<&KeyEntry> {
451 let list = match self.name_index.get(name) {
452 Some(l) => l,
453 None => return Vec::new(),
454 };
455 list.iter().filter_map(|id| self.keys.get(id)).collect()
456 }
457
458 pub fn get_by_status(&self, status: KeyStatus) -> Vec<&KeyEntry> {
460 self.keys
461 .values()
462 .filter(|e| e.metadata.status == status)
463 .collect()
464 }
465
466 pub fn get_by_tag(&self, tag: &str) -> Vec<&KeyEntry> {
468 self.keys
469 .values()
470 .filter(|e| e.metadata.tags.iter().any(|t| t == tag))
471 .collect()
472 }
473
474 pub fn remove(&mut self, key_id: &str) -> Option<KeyEntry> {
476 let entry = self.keys.remove(key_id)?;
477 let list = self.name_index.get_mut(&entry.metadata.name)?;
478 list.retain(|id| id != key_id);
479 if list.is_empty() {
480 self.name_index.remove(&entry.metadata.name);
481 }
482 Some(entry)
483 }
484
485 pub fn count(&self) -> usize {
487 self.keys.len()
488 }
489
490 pub fn version_count(&self, name: &str) -> usize {
492 self.name_index.get(name).map_or(0, |l| l.len())
493 }
494
495 pub fn names(&self) -> Vec<String> {
497 self.name_index.keys().cloned().collect()
498 }
499
500 pub fn set_status(&mut self, key_id: &str, status: KeyStatus) -> bool {
502 if let Some(entry) = self.keys.get_mut(key_id) {
503 entry.metadata.status = status;
504 true
505 } else {
506 false
507 }
508 }
509}
510
511#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
517pub enum KeyEvent {
518 Created,
520 Rotated,
522 Deprecated,
524 Revoked,
526 Expired,
528 Retrieved,
530 Deleted,
532}
533
534impl KeyEvent {
535 pub fn as_str(&self) -> &'static str {
537 match self {
538 KeyEvent::Created => "created",
539 KeyEvent::Rotated => "rotated",
540 KeyEvent::Deprecated => "deprecated",
541 KeyEvent::Revoked => "revoked",
542 KeyEvent::Expired => "expired",
543 KeyEvent::Retrieved => "retrieved",
544 KeyEvent::Deleted => "deleted",
545 }
546 }
547}
548
549#[derive(Debug, Clone, Serialize, Deserialize)]
551pub struct KeyAuditEntry {
552 pub timestamp: SystemTime,
554 pub event: KeyEvent,
556 pub key_id: String,
558 pub key_name: String,
560 pub details: String,
562}
563
564impl KeyAuditEntry {
565 fn new(event: KeyEvent, key_id: String, key_name: String, details: impl Into<String>) -> Self {
567 Self {
568 timestamp: SystemTime::now(),
569 event,
570 key_id,
571 key_name,
572 details: details.into(),
573 }
574 }
575}
576
577#[derive(Debug, Clone, Default)]
579pub struct KeyAuditLog {
580 entries: Vec<KeyAuditEntry>,
581}
582
583impl KeyAuditLog {
584 pub fn new() -> Self {
586 Self::default()
587 }
588
589 pub fn record(
591 &mut self,
592 event: KeyEvent,
593 key_id: String,
594 key_name: String,
595 details: impl Into<String>,
596 ) {
597 self.entries
598 .push(KeyAuditEntry::new(event, key_id, key_name, details));
599 }
600
601 pub fn entries(&self) -> &[KeyAuditEntry] {
603 &self.entries
604 }
605
606 pub fn by_event(&self, event: KeyEvent) -> Vec<&KeyAuditEntry> {
608 self.entries.iter().filter(|e| e.event == event).collect()
609 }
610
611 pub fn by_key_name(&self, name: &str) -> Vec<&KeyAuditEntry> {
613 self.entries.iter().filter(|e| e.key_name == name).collect()
614 }
615
616 pub fn count(&self) -> usize {
618 self.entries.len()
619 }
620}
621
622pub struct KeyVault {
630 store: RwLock<KeyStore>,
631 rotation_policy: RotationPolicy,
632 usage_counters: RwLock<HashMap<String, u64>>,
633 audit_log: RwLock<KeyAuditLog>,
634 generator: KeyGenerator,
635}
636
637impl KeyVault {
638 pub fn new(rotation_policy: RotationPolicy) -> Self {
640 Self {
641 store: RwLock::new(KeyStore::new()),
642 rotation_policy,
643 usage_counters: RwLock::new(HashMap::new()),
644 audit_log: RwLock::new(KeyAuditLog::new()),
645 generator: KeyGenerator::new(),
646 }
647 }
648
649 pub fn generate_key(
651 &self,
652 name: &str,
653 algorithm: KeyAlgorithm,
654 purpose: KeyPurpose,
655 ) -> Result<String, KeyError> {
656 let store = self.store.read().expect("store lock");
657 let version = store.version_count(name) as u32 + 1;
658 drop(store);
659
660 let entry = self.generator.generate(name, algorithm, purpose, version);
661 let key_id = entry.metadata.key_id.clone();
662 let fingerprint = entry.fingerprint.clone();
663
664 let mut store = self.store.write().expect("store lock");
665 store.put(entry);
666
667 self.audit_log.write().expect("audit lock").record(
668 KeyEvent::Created,
669 key_id.clone(),
670 name.to_string(),
671 format!(
672 "algorithm={}, version={}, fingerprint={}",
673 algorithm, version, fingerprint
674 ),
675 );
676
677 Ok(key_id)
678 }
679
680 pub fn rotate_key(&self, name: &str) -> Result<String, KeyError> {
682 let mut store = self.store.write().expect("store lock");
683 let current = store
684 .get_latest_by_name(name)
685 .ok_or(KeyError::KeyNotFound {
686 name: name.to_string(),
687 })?;
688
689 if !current.metadata.status.is_usable_for_new() {
690 return Err(KeyError::KeyNotActive {
691 name: name.to_string(),
692 status: current.metadata.status,
693 });
694 }
695
696 let algorithm = current.metadata.algorithm;
697 let purpose = current.metadata.purpose;
698 let old_id = current.metadata.key_id.clone();
699 let old_version = current.metadata.version;
700
701 store.set_status(&old_id, KeyStatus::Deprecated);
703 drop(store);
704
705 let new_id = self.generate_key(name, algorithm, purpose)?;
707
708 self.audit_log.write().expect("audit lock").record(
709 KeyEvent::Rotated,
710 new_id.clone(),
711 name.to_string(),
712 format!(
713 "rotated from version {} to {}",
714 old_version,
715 old_version + 1
716 ),
717 );
718 self.audit_log.write().expect("audit lock").record(
719 KeyEvent::Deprecated,
720 old_id,
721 name.to_string(),
722 format!("deprecated by rotation to version {}", old_version + 1),
723 );
724
725 Ok(new_id)
726 }
727
728 pub fn get_key(&self, key_id: &str) -> Option<KeyEntry> {
730 let entry = self
731 .store
732 .read()
733 .expect("store lock")
734 .get(key_id)
735 .cloned()?;
736 *self
737 .usage_counters
738 .write()
739 .expect("counters lock")
740 .entry(key_id.to_string())
741 .or_insert(0) += 1;
742 self.audit_log.write().expect("audit lock").record(
743 KeyEvent::Retrieved,
744 key_id.to_string(),
745 entry.metadata.name.clone(),
746 "retrieved by id",
747 );
748 Some(entry)
749 }
750
751 pub fn get_latest_key(&self, name: &str) -> Option<KeyEntry> {
753 let entry = self
754 .store
755 .read()
756 .expect("store lock")
757 .get_latest_by_name(name)
758 .cloned()?;
759 let key_id = entry.metadata.key_id.clone();
760 *self
761 .usage_counters
762 .write()
763 .expect("counters lock")
764 .entry(key_id)
765 .or_insert(0) += 1;
766 self.audit_log.write().expect("audit lock").record(
767 KeyEvent::Retrieved,
768 entry.metadata.key_id.clone(),
769 name.to_string(),
770 "retrieved latest by name",
771 );
772 Some(entry)
773 }
774
775 pub fn get_key_by_version(&self, name: &str, version: u32) -> Option<KeyEntry> {
777 self.store
778 .read()
779 .expect("store lock")
780 .get_by_name_and_version(name, version)
781 .cloned()
782 }
783
784 pub fn get_all_versions(&self, name: &str) -> Vec<KeyEntry> {
786 self.store
787 .read()
788 .expect("store lock")
789 .get_all_versions(name)
790 .into_iter()
791 .cloned()
792 .collect()
793 }
794
795 pub fn revoke_key(&self, key_id: &str) -> Result<(), KeyError> {
797 let mut store = self.store.write().expect("store lock");
798 let entry = store.get(key_id).ok_or(KeyError::KeyIdNotFound {
799 key_id: key_id.to_string(),
800 })?;
801 let name = entry.metadata.name.clone();
802 store.set_status(key_id, KeyStatus::Revoked);
803 drop(store);
804
805 self.audit_log.write().expect("audit lock").record(
806 KeyEvent::Revoked,
807 key_id.to_string(),
808 name,
809 "key revoked",
810 );
811 Ok(())
812 }
813
814 pub fn deprecate_key(&self, key_id: &str) -> Result<(), KeyError> {
816 let mut store = self.store.write().expect("store lock");
817 let entry = store.get(key_id).ok_or(KeyError::KeyIdNotFound {
818 key_id: key_id.to_string(),
819 })?;
820 let name = entry.metadata.name.clone();
821 store.set_status(key_id, KeyStatus::Deprecated);
822 drop(store);
823
824 self.audit_log.write().expect("audit lock").record(
825 KeyEvent::Deprecated,
826 key_id.to_string(),
827 name,
828 "key deprecated",
829 );
830 Ok(())
831 }
832
833 pub fn needs_rotation(&self, name: &str) -> bool {
835 let store = self.store.read().expect("store lock");
836 let entry = match store.get_latest_by_name(name) {
837 Some(e) => e,
838 None => return false,
839 };
840 let key_id = &entry.metadata.key_id;
841 let age = entry.metadata.age();
842 let usage = self
843 .usage_counters
844 .read()
845 .expect("counters lock")
846 .get(key_id)
847 .copied()
848 .unwrap_or(0);
849 self.rotation_policy.needs_rotation(age, usage)
850 }
851
852 pub fn auto_rotate(&self, name: &str) -> Option<String> {
854 if self.needs_rotation(name) {
855 self.rotate_key(name).ok()
856 } else {
857 None
858 }
859 }
860
861 pub fn key_count(&self) -> usize {
863 self.store.read().expect("store lock").count()
864 }
865
866 pub fn version_count(&self, name: &str) -> usize {
868 self.store.read().expect("store lock").version_count(name)
869 }
870
871 pub fn key_names(&self) -> Vec<String> {
873 self.store.read().expect("store lock").names()
874 }
875
876 pub fn audit_log(&self) -> KeyAuditLog {
878 self.audit_log.read().expect("audit lock").clone()
879 }
880
881 pub fn usage_count(&self, key_id: &str) -> u64 {
883 self.usage_counters
884 .read()
885 .expect("counters lock")
886 .get(key_id)
887 .copied()
888 .unwrap_or(0)
889 }
890
891 pub fn get_by_tag(&self, tag: &str) -> Vec<KeyEntry> {
893 self.store
894 .read()
895 .expect("store lock")
896 .get_by_tag(tag)
897 .into_iter()
898 .cloned()
899 .collect()
900 }
901
902 pub fn get_by_status(&self, status: KeyStatus) -> Vec<KeyEntry> {
904 self.store
905 .read()
906 .expect("store lock")
907 .get_by_status(status)
908 .into_iter()
909 .cloned()
910 .collect()
911 }
912
913 pub fn delete_key(&self, key_id: &str) -> Result<KeyEntry, KeyError> {
915 let mut store = self.store.write().expect("store lock");
916 let entry = store.remove(key_id).ok_or(KeyError::KeyIdNotFound {
917 key_id: key_id.to_string(),
918 })?;
919 let name = entry.metadata.name.clone();
920 drop(store);
921
922 self.audit_log.write().expect("audit lock").record(
923 KeyEvent::Deleted,
924 key_id.to_string(),
925 name,
926 "key deleted",
927 );
928 Ok(entry)
929 }
930}
931
932impl fmt::Debug for KeyVault {
933 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
934 f.debug_struct("KeyVault")
935 .field("key_count", &self.key_count())
936 .field("rotation_policy", &self.rotation_policy.as_str())
937 .finish()
938 }
939}
940
941#[derive(Debug, Clone, PartialEq, Eq)]
947pub enum KeyError {
948 KeyNotFound { name: String },
950 KeyIdNotFound { key_id: String },
952 KeyNotActive { name: String, status: KeyStatus },
954 PurposeMismatch {
956 expected: KeyPurpose,
957 actual: KeyPurpose,
958 },
959 KeyExpired { key_id: String },
961 KeyRevoked { key_id: String },
963}
964
965impl fmt::Display for KeyError {
966 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
967 match self {
968 KeyError::KeyNotFound { name } => write!(f, "key '{}' not found", name),
969 KeyError::KeyIdNotFound { key_id } => write!(f, "key id '{}' not found", key_id),
970 KeyError::KeyNotActive { name, status } => {
971 write!(f, "key '{}' is not active (status: {})", name, status)
972 }
973 KeyError::PurposeMismatch { expected, actual } => {
974 write!(
975 f,
976 "key purpose mismatch: expected {}, actual {}",
977 expected, actual
978 )
979 }
980 KeyError::KeyExpired { key_id } => write!(f, "key '{}' is expired", key_id),
981 KeyError::KeyRevoked { key_id } => write!(f, "key '{}' is revoked", key_id),
982 }
983 }
984}
985
986impl std::error::Error for KeyError {}
987
988#[derive(Debug, Clone, Serialize, Deserialize)]
994pub struct KeyDerivationConfig {
995 pub algorithm: String,
997 pub iterations: u32,
999 pub salt_len: usize,
1001 pub key_len: usize,
1003 pub memory_kb: Option<u32>,
1005 pub parallelism: Option<u32>,
1007}
1008
1009impl Default for KeyDerivationConfig {
1010 fn default() -> Self {
1011 Self {
1012 algorithm: "pbkdf2".to_string(),
1013 iterations: 600_000,
1014 salt_len: 32,
1015 key_len: 32,
1016 memory_kb: None,
1017 parallelism: None,
1018 }
1019 }
1020}
1021
1022impl KeyDerivationConfig {
1023 pub fn pbkdf2(iterations: u32) -> Self {
1025 Self {
1026 algorithm: "pbkdf2".to_string(),
1027 iterations,
1028 ..Default::default()
1029 }
1030 }
1031
1032 pub fn argon2id(iterations: u32, memory_kb: u32, parallelism: u32) -> Self {
1034 Self {
1035 algorithm: "argon2id".to_string(),
1036 iterations,
1037 memory_kb: Some(memory_kb),
1038 parallelism: Some(parallelism),
1039 ..Default::default()
1040 }
1041 }
1042
1043 pub fn scrypt(iterations: u32) -> Self {
1045 Self {
1046 algorithm: "scrypt".to_string(),
1047 iterations,
1048 ..Default::default()
1049 }
1050 }
1051
1052 pub fn is_argon2(&self) -> bool {
1054 self.algorithm == "argon2id"
1055 }
1056
1057 pub fn is_pbkdf2(&self) -> bool {
1059 self.algorithm == "pbkdf2"
1060 }
1061
1062 pub fn generate_salt(&self) -> Vec<u8> {
1064 let mut salt = vec![0u8; self.salt_len];
1065 OsRng.fill_bytes(&mut salt);
1066 salt
1067 }
1068}
1069
1070pub struct NonceGenerator {
1076 nonce_len: usize,
1078}
1079
1080impl NonceGenerator {
1081 pub fn for_gcm() -> Self {
1083 Self { nonce_len: 12 }
1084 }
1085
1086 pub fn for_chacha20() -> Self {
1088 Self { nonce_len: 16 }
1089 }
1090
1091 pub fn new(nonce_len: usize) -> Self {
1093 Self { nonce_len }
1094 }
1095
1096 pub fn generate(&self) -> Vec<u8> {
1098 let mut nonce = vec![0u8; self.nonce_len];
1099 OsRng.fill_bytes(&mut nonce);
1100 nonce
1101 }
1102
1103 pub fn len(&self) -> usize {
1105 self.nonce_len
1106 }
1107}
1108
1109#[derive(Debug, Clone, Serialize, Deserialize)]
1115pub struct EncryptionContext {
1116 pub aad: Vec<u8>,
1118 pub label: String,
1120 pub tenant_id: Option<String>,
1122}
1123
1124impl Default for EncryptionContext {
1125 fn default() -> Self {
1126 Self {
1127 aad: Vec::new(),
1128 label: String::new(),
1129 tenant_id: None,
1130 }
1131 }
1132}
1133
1134impl EncryptionContext {
1135 pub fn new() -> Self {
1137 Self::default()
1138 }
1139
1140 pub fn with_aad(mut self, aad: Vec<u8>) -> Self {
1142 self.aad = aad;
1143 self
1144 }
1145
1146 pub fn with_label(mut self, label: &str) -> Self {
1148 self.label = label.to_string();
1149 self
1150 }
1151
1152 pub fn with_tenant(mut self, tenant_id: &str) -> Self {
1154 self.tenant_id = Some(tenant_id.to_string());
1155 self
1156 }
1157
1158 pub fn has_aad(&self) -> bool {
1160 !self.aad.is_empty()
1161 }
1162
1163 pub fn has_tenant(&self) -> bool {
1165 self.tenant_id.is_some()
1166 }
1167}
1168
1169#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
1175pub struct KeyFingerprint {
1176 pub sha256_hex: String,
1178 pub algorithm: KeyAlgorithm,
1180}
1181
1182impl KeyFingerprint {
1183 pub fn from_key_material(key: &[u8], algorithm: KeyAlgorithm) -> Self {
1185 let mut hasher = Sha256::new();
1186 hasher.update(key);
1187 let hash = hasher.finalize();
1188 let hex: String = hash.iter().map(|b| format!("{:02x}", b)).collect();
1189 Self {
1190 sha256_hex: hex,
1191 algorithm,
1192 }
1193 }
1194
1195 pub fn short(&self) -> &str {
1197 &self.sha256_hex[..8.min(self.sha256_hex.len())]
1198 }
1199
1200 pub fn matches(&self, other: &Self) -> bool {
1202 self.sha256_hex == other.sha256_hex && self.algorithm == other.algorithm
1203 }
1204}
1205
1206impl fmt::Display for KeyFingerprint {
1207 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1208 write!(f, "{}:{}", self.algorithm.as_str(), self.short())
1209 }
1210}
1211
1212#[derive(Debug, Clone, Serialize, Deserialize)]
1218pub struct SecurityPolicy {
1219 pub min_key_length: usize,
1221 pub max_key_usage: u64,
1223 pub max_key_age_secs: u64,
1225 pub require_encryption_at_rest: bool,
1227 pub require_key_rotation: bool,
1229 pub allowed_algorithms: Vec<KeyAlgorithm>,
1231}
1232
1233impl Default for SecurityPolicy {
1234 fn default() -> Self {
1235 Self {
1236 min_key_length: 32,
1237 max_key_usage: 1_000_000,
1238 max_key_age_secs: 86400 * 90,
1239 require_encryption_at_rest: true,
1240 require_key_rotation: true,
1241 allowed_algorithms: vec![KeyAlgorithm::Aes256Gcm, KeyAlgorithm::HmacSha256],
1242 }
1243 }
1244}
1245
1246impl SecurityPolicy {
1247 pub fn strict() -> Self {
1249 Self {
1250 min_key_length: 32,
1251 max_key_usage: 100_000,
1252 max_key_age_secs: 86400 * 30,
1253 require_encryption_at_rest: true,
1254 require_key_rotation: true,
1255 allowed_algorithms: vec![KeyAlgorithm::Aes256Gcm],
1256 }
1257 }
1258
1259 pub fn is_algorithm_allowed(&self, alg: KeyAlgorithm) -> bool {
1261 self.allowed_algorithms.contains(&alg)
1262 }
1263
1264 pub fn is_key_length_ok(&self, key_len: usize) -> bool {
1266 key_len >= self.min_key_length
1267 }
1268}
1269
1270#[cfg(test)]
1275mod tests {
1276 use super::*;
1277
1278 #[test]
1281 fn test_key_algorithm_as_str() {
1282 assert_eq!(KeyAlgorithm::Aes256Gcm.as_str(), "aes-256-gcm");
1283 assert_eq!(KeyAlgorithm::HmacSha256.as_str(), "hmac-sha256");
1284 assert_eq!(KeyAlgorithm::Rsa2048.as_str(), "rsa-2048");
1285 assert_eq!(KeyAlgorithm::Rsa4096.as_str(), "rsa-4096");
1286 }
1287
1288 #[test]
1289 fn test_key_algorithm_key_length() {
1290 assert_eq!(KeyAlgorithm::Aes256Gcm.key_length(), 32);
1291 assert_eq!(KeyAlgorithm::HmacSha256.key_length(), 32);
1292 assert_eq!(KeyAlgorithm::Rsa2048.key_length(), 256);
1293 assert_eq!(KeyAlgorithm::Rsa4096.key_length(), 512);
1294 }
1295
1296 #[test]
1297 fn test_key_algorithm_is_symmetric() {
1298 assert!(KeyAlgorithm::Aes256Gcm.is_symmetric());
1299 assert!(KeyAlgorithm::HmacSha256.is_symmetric());
1300 assert!(!KeyAlgorithm::Rsa2048.is_symmetric());
1301 assert!(!KeyAlgorithm::Rsa4096.is_symmetric());
1302 }
1303
1304 #[test]
1307 fn test_key_purpose_can_encrypt() {
1308 assert!(KeyPurpose::Encryption.can_encrypt());
1309 assert!(!KeyPurpose::Signing.can_encrypt());
1310 assert!(KeyPurpose::EncryptionAndSigning.can_encrypt());
1311 }
1312
1313 #[test]
1314 fn test_key_purpose_can_sign() {
1315 assert!(!KeyPurpose::Encryption.can_sign());
1316 assert!(KeyPurpose::Signing.can_sign());
1317 assert!(KeyPurpose::EncryptionAndSigning.can_sign());
1318 }
1319
1320 #[test]
1323 fn test_key_status_is_usable_for_new() {
1324 assert!(KeyStatus::Active.is_usable_for_new());
1325 assert!(!KeyStatus::Deprecated.is_usable_for_new());
1326 assert!(!KeyStatus::Revoked.is_usable_for_new());
1327 assert!(!KeyStatus::Expired.is_usable_for_new());
1328 }
1329
1330 #[test]
1331 fn test_key_status_is_usable_for_old() {
1332 assert!(KeyStatus::Active.is_usable_for_old());
1333 assert!(KeyStatus::Deprecated.is_usable_for_old());
1334 assert!(!KeyStatus::Revoked.is_usable_for_old());
1335 assert!(KeyStatus::Expired.is_usable_for_old());
1336 }
1337
1338 #[test]
1339 fn test_key_status_is_dead() {
1340 assert!(!KeyStatus::Active.is_dead());
1341 assert!(KeyStatus::Revoked.is_dead());
1342 }
1343
1344 #[test]
1347 fn test_key_metadata_with_expiry() {
1348 let now = SystemTime::now();
1349 let meta = KeyMetadata::new(
1350 "id1".to_string(),
1351 "test".to_string(),
1352 KeyAlgorithm::Aes256Gcm,
1353 KeyPurpose::Encryption,
1354 1,
1355 )
1356 .with_expiry(now + Duration::from_secs(3600));
1357 assert!(!meta.is_expired());
1358 assert_eq!(meta.expires_at, Some(now + Duration::from_secs(3600)));
1359 }
1360
1361 #[test]
1362 fn test_key_metadata_is_expired() {
1363 let now = SystemTime::now();
1364 let meta = KeyMetadata::new(
1365 "id1".to_string(),
1366 "test".to_string(),
1367 KeyAlgorithm::Aes256Gcm,
1368 KeyPurpose::Encryption,
1369 1,
1370 )
1371 .with_expiry(now - Duration::from_secs(1));
1372 assert!(meta.is_expired());
1373 }
1374
1375 #[test]
1376 fn test_key_metadata_with_tag_and_description() {
1377 let meta = KeyMetadata::new(
1378 "id1".to_string(),
1379 "test".to_string(),
1380 KeyAlgorithm::Aes256Gcm,
1381 KeyPurpose::Encryption,
1382 1,
1383 )
1384 .with_description("test key")
1385 .with_tag("production")
1386 .with_tag("critical");
1387 assert_eq!(meta.description, "test key");
1388 assert_eq!(meta.tags, vec!["production", "critical"]);
1389 }
1390
1391 #[test]
1394 fn test_key_entry_compute_fingerprint() {
1395 let material = b"test-key-material";
1396 let fp = KeyEntry::compute_fingerprint(material);
1397 assert_eq!(fp.len(), 64); }
1399
1400 #[test]
1401 fn test_key_entry_verify_fingerprint() {
1402 let material = b"test-key-material";
1403 let entry = KeyEntry {
1404 metadata: KeyMetadata::new(
1405 "id1".to_string(),
1406 "test".to_string(),
1407 KeyAlgorithm::Aes256Gcm,
1408 KeyPurpose::Encryption,
1409 1,
1410 ),
1411 material: material.to_vec(),
1412 fingerprint: KeyEntry::compute_fingerprint(material),
1413 };
1414 assert!(entry.verify_fingerprint());
1415 }
1416
1417 #[test]
1418 fn test_key_entry_verify_fingerprint_mismatch() {
1419 let entry = KeyEntry {
1420 metadata: KeyMetadata::new(
1421 "id1".to_string(),
1422 "test".to_string(),
1423 KeyAlgorithm::Aes256Gcm,
1424 KeyPurpose::Encryption,
1425 1,
1426 ),
1427 material: b"actual-material".to_vec(),
1428 fingerprint: "0000000000000000000000000000000000000000000000000000000000000000"
1429 .to_string(),
1430 };
1431 assert!(!entry.verify_fingerprint());
1432 }
1433
1434 #[test]
1437 fn test_key_generator_generate_material_length() {
1438 let gen = KeyGenerator::new();
1439 let material = gen.generate_material(KeyAlgorithm::Aes256Gcm);
1440 assert_eq!(material.len(), 32);
1441 }
1442
1443 #[test]
1444 fn test_key_generator_generate_material_random() {
1445 let gen = KeyGenerator::new();
1446 let a = gen.generate_material(KeyAlgorithm::Aes256Gcm);
1447 let b = gen.generate_material(KeyAlgorithm::Aes256Gcm);
1448 assert_ne!(a, b, "随机生成的密钥应不同");
1449 }
1450
1451 #[test]
1452 fn test_key_generator_generate_key_id() {
1453 let id1 = KeyGenerator::generate_key_id();
1454 let id2 = KeyGenerator::generate_key_id();
1455 assert_eq!(id1.len(), 32); assert_ne!(id1, id2);
1457 }
1458
1459 #[test]
1460 fn test_key_generator_generate_full_entry() {
1461 let gen = KeyGenerator::new();
1462 let entry = gen.generate("test-key", KeyAlgorithm::HmacSha256, KeyPurpose::Signing, 1);
1463 assert_eq!(entry.metadata.name, "test-key");
1464 assert_eq!(entry.metadata.algorithm, KeyAlgorithm::HmacSha256);
1465 assert_eq!(entry.metadata.version, 1);
1466 assert_eq!(entry.material.len(), 32);
1467 assert!(entry.verify_fingerprint());
1468 }
1469
1470 #[test]
1473 fn test_rotation_policy_time_interval() {
1474 let policy = RotationPolicy::TimeInterval(Duration::from_secs(100));
1475 assert!(!policy.needs_rotation(Duration::from_secs(50), 0));
1476 assert!(policy.needs_rotation(Duration::from_secs(100), 0));
1477 assert!(policy.needs_rotation(Duration::from_secs(150), 0));
1478 }
1479
1480 #[test]
1481 fn test_rotation_policy_usage_count() {
1482 let policy = RotationPolicy::UsageCount(1000);
1483 assert!(!policy.needs_rotation(Duration::ZERO, 500));
1484 assert!(policy.needs_rotation(Duration::ZERO, 1000));
1485 assert!(policy.needs_rotation(Duration::ZERO, 1500));
1486 }
1487
1488 #[test]
1489 fn test_rotation_policy_time_or_usage() {
1490 let policy = RotationPolicy::TimeIntervalOrUsage(Duration::from_secs(100), 1000);
1491 assert!(!policy.needs_rotation(Duration::from_secs(50), 500));
1492 assert!(policy.needs_rotation(Duration::from_secs(100), 500));
1493 assert!(policy.needs_rotation(Duration::from_secs(50), 1000));
1494 }
1495
1496 #[test]
1497 fn test_rotation_policy_never() {
1498 let policy = RotationPolicy::Never;
1499 assert!(!policy.needs_rotation(Duration::from_secs(999999), 999999));
1500 }
1501
1502 #[test]
1505 fn test_key_store_put_and_get() {
1506 let mut store = KeyStore::new();
1507 let gen = KeyGenerator::new();
1508 let entry = gen.generate("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption, 1);
1509 let key_id = store.put(entry);
1510 assert!(store.get(&key_id).is_some());
1511 assert_eq!(store.count(), 1);
1512 }
1513
1514 #[test]
1515 fn test_key_store_get_latest_by_name() {
1516 let mut store = KeyStore::new();
1517 let gen = KeyGenerator::new();
1518 let e1 = gen.generate("key", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption, 1);
1519 let e2 = gen.generate("key", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption, 2);
1520 store.put(e1);
1521 store.put(e2);
1522 let latest = store.get_latest_by_name("key").unwrap();
1523 assert_eq!(latest.metadata.version, 2);
1524 }
1525
1526 #[test]
1527 fn test_key_store_get_by_name_and_version() {
1528 let mut store = KeyStore::new();
1529 let gen = KeyGenerator::new();
1530 let e1 = gen.generate("key", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption, 1);
1531 let e2 = gen.generate("key", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption, 2);
1532 store.put(e1);
1533 store.put(e2);
1534 assert!(store.get_by_name_and_version("key", 1).is_some());
1535 assert!(store.get_by_name_and_version("key", 2).is_some());
1536 assert!(store.get_by_name_and_version("key", 3).is_none());
1537 }
1538
1539 #[test]
1540 fn test_key_store_get_all_versions() {
1541 let mut store = KeyStore::new();
1542 let gen = KeyGenerator::new();
1543 for v in 1..=3 {
1544 let entry = gen.generate("key", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption, v);
1545 store.put(entry);
1546 }
1547 let versions = store.get_all_versions("key");
1548 assert_eq!(versions.len(), 3);
1549 }
1550
1551 #[test]
1552 fn test_key_store_remove() {
1553 let mut store = KeyStore::new();
1554 let gen = KeyGenerator::new();
1555 let entry = gen.generate("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption, 1);
1556 let key_id = store.put(entry);
1557 assert_eq!(store.count(), 1);
1558 let removed = store.remove(&key_id);
1559 assert!(removed.is_some());
1560 assert_eq!(store.count(), 0);
1561 }
1562
1563 #[test]
1564 fn test_key_store_set_status() {
1565 let mut store = KeyStore::new();
1566 let gen = KeyGenerator::new();
1567 let entry = gen.generate("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption, 1);
1568 let key_id = store.put(entry);
1569 assert!(store.set_status(&key_id, KeyStatus::Revoked));
1570 assert_eq!(
1571 store.get(&key_id).unwrap().metadata.status,
1572 KeyStatus::Revoked
1573 );
1574 }
1575
1576 #[test]
1577 fn test_key_store_get_by_tag() {
1578 let mut store = KeyStore::new();
1579 let gen = KeyGenerator::new();
1580 let mut entry = gen.generate("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption, 1);
1581 entry.metadata.tags = vec!["production".to_string()];
1582 store.put(entry);
1583 let results = store.get_by_tag("production");
1584 assert_eq!(results.len(), 1);
1585 assert_eq!(store.get_by_tag("staging").len(), 0);
1586 }
1587
1588 #[test]
1591 fn test_key_audit_log_record_and_query() {
1592 let mut log = KeyAuditLog::new();
1593 log.record(
1594 KeyEvent::Created,
1595 "id1".to_string(),
1596 "key1".to_string(),
1597 "created",
1598 );
1599 log.record(
1600 KeyEvent::Rotated,
1601 "id2".to_string(),
1602 "key1".to_string(),
1603 "rotated",
1604 );
1605 assert_eq!(log.count(), 2);
1606 assert_eq!(log.by_event(KeyEvent::Created).len(), 1);
1607 assert_eq!(log.by_key_name("key1").len(), 2);
1608 }
1609
1610 #[test]
1613 fn test_key_vault_generate_key() {
1614 let vault = KeyVault::new(RotationPolicy::Never);
1615 let key_id = vault
1616 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1617 .unwrap();
1618 assert!(vault.get_key(&key_id).is_some());
1619 assert_eq!(vault.key_count(), 1);
1620 assert_eq!(vault.version_count("test"), 1);
1621 }
1622
1623 #[test]
1624 fn test_key_vault_rotate_key() {
1625 let vault = KeyVault::new(RotationPolicy::Never);
1626 let old_id = vault
1627 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1628 .unwrap();
1629 let new_id = vault.rotate_key("test").unwrap();
1630 assert_ne!(old_id, new_id);
1631 assert_eq!(vault.version_count("test"), 2);
1632 let old = vault.get_key(&old_id).unwrap();
1634 assert_eq!(old.metadata.status, KeyStatus::Deprecated);
1635 let new_key = vault.get_key(&new_id).unwrap();
1637 assert_eq!(new_key.metadata.status, KeyStatus::Active);
1638 }
1639
1640 #[test]
1641 fn test_key_vault_rotate_nonexistent_key() {
1642 let vault = KeyVault::new(RotationPolicy::Never);
1643 let result = vault.rotate_key("nonexistent");
1644 assert!(result.is_err());
1645 }
1646
1647 #[test]
1648 fn test_key_vault_get_latest_key() {
1649 let vault = KeyVault::new(RotationPolicy::Never);
1650 vault
1651 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1652 .unwrap();
1653 vault.rotate_key("test").unwrap();
1654 let latest = vault.get_latest_key("test").unwrap();
1655 assert_eq!(latest.metadata.version, 2);
1656 }
1657
1658 #[test]
1659 fn test_key_vault_revoke_key() {
1660 let vault = KeyVault::new(RotationPolicy::Never);
1661 let key_id = vault
1662 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1663 .unwrap();
1664 vault.revoke_key(&key_id).unwrap();
1665 let entry = vault.get_key(&key_id).unwrap();
1666 assert_eq!(entry.metadata.status, KeyStatus::Revoked);
1667 }
1668
1669 #[test]
1670 fn test_key_vault_deprecate_key() {
1671 let vault = KeyVault::new(RotationPolicy::Never);
1672 let key_id = vault
1673 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1674 .unwrap();
1675 vault.deprecate_key(&key_id).unwrap();
1676 let entry = vault.get_key(&key_id).unwrap();
1677 assert_eq!(entry.metadata.status, KeyStatus::Deprecated);
1678 }
1679
1680 #[test]
1681 fn test_key_vault_audit_log() {
1682 let vault = KeyVault::new(RotationPolicy::Never);
1683 vault
1684 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1685 .unwrap();
1686 let log = vault.audit_log();
1687 assert!(log.count() >= 1);
1688 assert_eq!(log.by_event(KeyEvent::Created).len(), 1);
1689 }
1690
1691 #[test]
1692 fn test_key_vault_usage_count() {
1693 let vault = KeyVault::new(RotationPolicy::Never);
1694 let key_id = vault
1695 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1696 .unwrap();
1697 assert_eq!(vault.usage_count(&key_id), 0);
1698 vault.get_key(&key_id);
1699 vault.get_key(&key_id);
1700 assert_eq!(vault.usage_count(&key_id), 2);
1701 }
1702
1703 #[test]
1704 fn test_key_vault_needs_rotation_time() {
1705 let vault = KeyVault::new(RotationPolicy::TimeInterval(Duration::from_millis(0)));
1706 vault
1707 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1708 .unwrap();
1709 std::thread::sleep(Duration::from_millis(1));
1710 assert!(vault.needs_rotation("test"));
1711 }
1712
1713 #[test]
1714 fn test_key_vault_needs_rotation_never() {
1715 let vault = KeyVault::new(RotationPolicy::Never);
1716 vault
1717 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1718 .unwrap();
1719 assert!(!vault.needs_rotation("test"));
1720 }
1721
1722 #[test]
1723 fn test_key_vault_auto_rotate() {
1724 let vault = KeyVault::new(RotationPolicy::TimeInterval(Duration::from_millis(0)));
1725 vault
1726 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1727 .unwrap();
1728 std::thread::sleep(Duration::from_millis(1));
1729 let new_id = vault.auto_rotate("test");
1730 assert!(new_id.is_some());
1731 assert_eq!(vault.version_count("test"), 2);
1732 }
1733
1734 #[test]
1735 fn test_key_vault_auto_rotate_no_rotation_needed() {
1736 let vault = KeyVault::new(RotationPolicy::Never);
1737 vault
1738 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1739 .unwrap();
1740 let result = vault.auto_rotate("test");
1741 assert!(result.is_none());
1742 }
1743
1744 #[test]
1745 fn test_key_vault_delete_key() {
1746 let vault = KeyVault::new(RotationPolicy::Never);
1747 let key_id = vault
1748 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1749 .unwrap();
1750 assert_eq!(vault.key_count(), 1);
1751 vault.delete_key(&key_id).unwrap();
1752 assert_eq!(vault.key_count(), 0);
1753 }
1754
1755 #[test]
1756 fn test_key_vault_get_by_status() {
1757 let vault = KeyVault::new(RotationPolicy::Never);
1758 let id1 = vault
1759 .generate_key("k1", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1760 .unwrap();
1761 vault
1762 .generate_key("k2", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1763 .unwrap();
1764 vault.revoke_key(&id1).unwrap();
1765 let active = vault.get_by_status(KeyStatus::Active);
1766 let revoked = vault.get_by_status(KeyStatus::Revoked);
1767 assert_eq!(active.len(), 1);
1768 assert_eq!(revoked.len(), 1);
1769 }
1770
1771 #[test]
1772 fn test_key_vault_concurrent_access() {
1773 use std::sync::Arc;
1774 use std::thread;
1775 let vault = Arc::new(KeyVault::new(RotationPolicy::Never));
1776 let id = vault
1777 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1778 .unwrap();
1779 let mut handles = vec![];
1780 for _ in 0..4 {
1781 let v = vault.clone();
1782 let kid = id.clone();
1783 handles.push(thread::spawn(move || {
1784 v.get_key(&kid);
1785 }));
1786 }
1787 for h in handles {
1788 h.join().expect("thread panicked");
1789 }
1790 assert_eq!(vault.usage_count(&id), 4);
1791 }
1792
1793 #[test]
1796 fn test_key_error_display() {
1797 let err = KeyError::KeyNotFound {
1798 name: "test".to_string(),
1799 };
1800 assert!(err.to_string().contains("test"));
1801 let err2 = KeyError::KeyRevoked {
1802 key_id: "id1".to_string(),
1803 };
1804 assert!(err2.to_string().contains("id1"));
1805 }
1806
1807 #[test]
1810 fn test_kdf_default() {
1811 let cfg = KeyDerivationConfig::default();
1812 assert_eq!(cfg.algorithm, "pbkdf2");
1813 assert_eq!(cfg.key_len, 32);
1814 }
1815
1816 #[test]
1817 fn test_kdf_pbkdf2() {
1818 let cfg = KeyDerivationConfig::pbkdf2(100_000);
1819 assert!(cfg.is_pbkdf2());
1820 assert!(!cfg.is_argon2());
1821 assert_eq!(cfg.iterations, 100_000);
1822 }
1823
1824 #[test]
1825 fn test_kdf_argon2id() {
1826 let cfg = KeyDerivationConfig::argon2id(3, 65536, 4);
1827 assert!(cfg.is_argon2());
1828 assert!(!cfg.is_pbkdf2());
1829 assert_eq!(cfg.memory_kb, Some(65536));
1830 assert_eq!(cfg.parallelism, Some(4));
1831 }
1832
1833 #[test]
1834 fn test_kdf_scrypt() {
1835 let cfg = KeyDerivationConfig::scrypt(1024);
1836 assert_eq!(cfg.algorithm, "scrypt");
1837 assert_eq!(cfg.iterations, 1024);
1838 }
1839
1840 #[test]
1841 fn test_kdf_generate_salt() {
1842 let cfg = KeyDerivationConfig::default();
1843 let salt = cfg.generate_salt();
1844 assert_eq!(salt.len(), cfg.salt_len);
1845 }
1846
1847 #[test]
1850 fn test_nonce_generator_gcm() {
1851 let gen = NonceGenerator::for_gcm();
1852 let nonce = gen.generate();
1853 assert_eq!(nonce.len(), 12);
1854 }
1855
1856 #[test]
1857 fn test_nonce_generator_chacha20() {
1858 let gen = NonceGenerator::for_chacha20();
1859 let nonce = gen.generate();
1860 assert_eq!(nonce.len(), 16);
1861 }
1862
1863 #[test]
1864 fn test_nonce_generator_custom() {
1865 let gen = NonceGenerator::new(32);
1866 assert_eq!(gen.len(), 32);
1867 let nonce = gen.generate();
1868 assert_eq!(nonce.len(), 32);
1869 }
1870
1871 #[test]
1872 fn test_nonce_generator_unique() {
1873 let gen = NonceGenerator::for_gcm();
1874 let n1 = gen.generate();
1875 let n2 = gen.generate();
1876 assert_ne!(n1, n2);
1877 }
1878
1879 #[test]
1882 fn test_encryption_context_default() {
1883 let ctx = EncryptionContext::default();
1884 assert!(!ctx.has_aad());
1885 assert!(!ctx.has_tenant());
1886 }
1887
1888 #[test]
1889 fn test_encryption_context_builder() {
1890 let ctx = EncryptionContext::new()
1891 .with_aad(b"associated".to_vec())
1892 .with_label("db")
1893 .with_tenant("tenant1");
1894 assert!(ctx.has_aad());
1895 assert!(ctx.has_tenant());
1896 assert_eq!(ctx.label, "db");
1897 assert_eq!(ctx.tenant_id, Some("tenant1".to_string()));
1898 }
1899
1900 #[test]
1903 fn test_key_fingerprint() {
1904 let key = b"my-secret-key-1234567890123456";
1905 let fp = KeyFingerprint::from_key_material(key, KeyAlgorithm::Aes256Gcm);
1906 assert_eq!(fp.sha256_hex.len(), 64);
1907 assert_eq!(fp.short().len(), 8);
1908 }
1909
1910 #[test]
1911 fn test_key_fingerprint_matches() {
1912 let key = b"my-secret-key-1234567890123456";
1913 let fp1 = KeyFingerprint::from_key_material(key, KeyAlgorithm::Aes256Gcm);
1914 let fp2 = KeyFingerprint::from_key_material(key, KeyAlgorithm::Aes256Gcm);
1915 assert!(fp1.matches(&fp2));
1916 }
1917
1918 #[test]
1919 fn test_key_fingerprint_not_matches() {
1920 let fp1 = KeyFingerprint::from_key_material(b"key1", KeyAlgorithm::Aes256Gcm);
1921 let fp2 = KeyFingerprint::from_key_material(b"key2", KeyAlgorithm::Aes256Gcm);
1922 assert!(!fp1.matches(&fp2));
1923 }
1924
1925 #[test]
1926 fn test_key_fingerprint_display() {
1927 let fp = KeyFingerprint::from_key_material(b"key", KeyAlgorithm::Aes256Gcm);
1928 let s = format!("{}", fp);
1929 assert!(s.contains("aes-256-gcm"));
1930 }
1931
1932 #[test]
1935 fn test_security_policy_default() {
1936 let policy = SecurityPolicy::default();
1937 assert!(policy.require_encryption_at_rest);
1938 assert!(policy.require_key_rotation);
1939 assert!(policy.is_algorithm_allowed(KeyAlgorithm::Aes256Gcm));
1940 }
1941
1942 #[test]
1943 fn test_security_policy_strict() {
1944 let policy = SecurityPolicy::strict();
1945 assert!(policy.is_algorithm_allowed(KeyAlgorithm::Aes256Gcm));
1946 assert!(!policy.is_algorithm_allowed(KeyAlgorithm::HmacSha256));
1947 }
1948
1949 #[test]
1950 fn test_security_policy_key_length() {
1951 let policy = SecurityPolicy::default();
1952 assert!(policy.is_key_length_ok(32));
1953 assert!(!policy.is_key_length_ok(16));
1954 }
1955}