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 pub fn is_empty(&self) -> bool {
1110 self.nonce_len == 0
1111 }
1112}
1113
1114#[derive(Debug, Clone, Serialize, Deserialize)]
1120#[derive(Default)]
1121pub struct EncryptionContext {
1122 pub aad: Vec<u8>,
1124 pub label: String,
1126 pub tenant_id: Option<String>,
1128}
1129
1130
1131impl EncryptionContext {
1132 pub fn new() -> Self {
1134 Self::default()
1135 }
1136
1137 pub fn with_aad(mut self, aad: Vec<u8>) -> Self {
1139 self.aad = aad;
1140 self
1141 }
1142
1143 pub fn with_label(mut self, label: &str) -> Self {
1145 self.label = label.to_string();
1146 self
1147 }
1148
1149 pub fn with_tenant(mut self, tenant_id: &str) -> Self {
1151 self.tenant_id = Some(tenant_id.to_string());
1152 self
1153 }
1154
1155 pub fn has_aad(&self) -> bool {
1157 !self.aad.is_empty()
1158 }
1159
1160 pub fn has_tenant(&self) -> bool {
1162 self.tenant_id.is_some()
1163 }
1164}
1165
1166#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
1172pub struct KeyFingerprint {
1173 pub sha256_hex: String,
1175 pub algorithm: KeyAlgorithm,
1177}
1178
1179impl KeyFingerprint {
1180 pub fn from_key_material(key: &[u8], algorithm: KeyAlgorithm) -> Self {
1182 let mut hasher = Sha256::new();
1183 hasher.update(key);
1184 let hash = hasher.finalize();
1185 let hex: String = hash.iter().map(|b| format!("{:02x}", b)).collect();
1186 Self {
1187 sha256_hex: hex,
1188 algorithm,
1189 }
1190 }
1191
1192 pub fn short(&self) -> &str {
1194 &self.sha256_hex[..8.min(self.sha256_hex.len())]
1195 }
1196
1197 pub fn matches(&self, other: &Self) -> bool {
1199 self.sha256_hex == other.sha256_hex && self.algorithm == other.algorithm
1200 }
1201}
1202
1203impl fmt::Display for KeyFingerprint {
1204 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1205 write!(f, "{}:{}", self.algorithm.as_str(), self.short())
1206 }
1207}
1208
1209#[derive(Debug, Clone, Serialize, Deserialize)]
1215pub struct SecurityPolicy {
1216 pub min_key_length: usize,
1218 pub max_key_usage: u64,
1220 pub max_key_age_secs: u64,
1222 pub require_encryption_at_rest: bool,
1224 pub require_key_rotation: bool,
1226 pub allowed_algorithms: Vec<KeyAlgorithm>,
1228}
1229
1230impl Default for SecurityPolicy {
1231 fn default() -> Self {
1232 Self {
1233 min_key_length: 32,
1234 max_key_usage: 1_000_000,
1235 max_key_age_secs: 86400 * 90,
1236 require_encryption_at_rest: true,
1237 require_key_rotation: true,
1238 allowed_algorithms: vec![KeyAlgorithm::Aes256Gcm, KeyAlgorithm::HmacSha256],
1239 }
1240 }
1241}
1242
1243impl SecurityPolicy {
1244 pub fn strict() -> Self {
1246 Self {
1247 min_key_length: 32,
1248 max_key_usage: 100_000,
1249 max_key_age_secs: 86400 * 30,
1250 require_encryption_at_rest: true,
1251 require_key_rotation: true,
1252 allowed_algorithms: vec![KeyAlgorithm::Aes256Gcm],
1253 }
1254 }
1255
1256 pub fn is_algorithm_allowed(&self, alg: KeyAlgorithm) -> bool {
1258 self.allowed_algorithms.contains(&alg)
1259 }
1260
1261 pub fn is_key_length_ok(&self, key_len: usize) -> bool {
1263 key_len >= self.min_key_length
1264 }
1265}
1266
1267#[cfg(test)]
1272mod tests {
1273 use super::*;
1274
1275 #[test]
1278 fn test_key_algorithm_as_str() {
1279 assert_eq!(KeyAlgorithm::Aes256Gcm.as_str(), "aes-256-gcm");
1280 assert_eq!(KeyAlgorithm::HmacSha256.as_str(), "hmac-sha256");
1281 assert_eq!(KeyAlgorithm::Rsa2048.as_str(), "rsa-2048");
1282 assert_eq!(KeyAlgorithm::Rsa4096.as_str(), "rsa-4096");
1283 }
1284
1285 #[test]
1286 fn test_key_algorithm_key_length() {
1287 assert_eq!(KeyAlgorithm::Aes256Gcm.key_length(), 32);
1288 assert_eq!(KeyAlgorithm::HmacSha256.key_length(), 32);
1289 assert_eq!(KeyAlgorithm::Rsa2048.key_length(), 256);
1290 assert_eq!(KeyAlgorithm::Rsa4096.key_length(), 512);
1291 }
1292
1293 #[test]
1294 fn test_key_algorithm_is_symmetric() {
1295 assert!(KeyAlgorithm::Aes256Gcm.is_symmetric());
1296 assert!(KeyAlgorithm::HmacSha256.is_symmetric());
1297 assert!(!KeyAlgorithm::Rsa2048.is_symmetric());
1298 assert!(!KeyAlgorithm::Rsa4096.is_symmetric());
1299 }
1300
1301 #[test]
1304 fn test_key_purpose_can_encrypt() {
1305 assert!(KeyPurpose::Encryption.can_encrypt());
1306 assert!(!KeyPurpose::Signing.can_encrypt());
1307 assert!(KeyPurpose::EncryptionAndSigning.can_encrypt());
1308 }
1309
1310 #[test]
1311 fn test_key_purpose_can_sign() {
1312 assert!(!KeyPurpose::Encryption.can_sign());
1313 assert!(KeyPurpose::Signing.can_sign());
1314 assert!(KeyPurpose::EncryptionAndSigning.can_sign());
1315 }
1316
1317 #[test]
1320 fn test_key_status_is_usable_for_new() {
1321 assert!(KeyStatus::Active.is_usable_for_new());
1322 assert!(!KeyStatus::Deprecated.is_usable_for_new());
1323 assert!(!KeyStatus::Revoked.is_usable_for_new());
1324 assert!(!KeyStatus::Expired.is_usable_for_new());
1325 }
1326
1327 #[test]
1328 fn test_key_status_is_usable_for_old() {
1329 assert!(KeyStatus::Active.is_usable_for_old());
1330 assert!(KeyStatus::Deprecated.is_usable_for_old());
1331 assert!(!KeyStatus::Revoked.is_usable_for_old());
1332 assert!(KeyStatus::Expired.is_usable_for_old());
1333 }
1334
1335 #[test]
1336 fn test_key_status_is_dead() {
1337 assert!(!KeyStatus::Active.is_dead());
1338 assert!(KeyStatus::Revoked.is_dead());
1339 }
1340
1341 #[test]
1344 fn test_key_metadata_with_expiry() {
1345 let now = SystemTime::now();
1346 let meta = KeyMetadata::new(
1347 "id1".to_string(),
1348 "test".to_string(),
1349 KeyAlgorithm::Aes256Gcm,
1350 KeyPurpose::Encryption,
1351 1,
1352 )
1353 .with_expiry(now + Duration::from_secs(3600));
1354 assert!(!meta.is_expired());
1355 assert_eq!(meta.expires_at, Some(now + Duration::from_secs(3600)));
1356 }
1357
1358 #[test]
1359 fn test_key_metadata_is_expired() {
1360 let now = SystemTime::now();
1361 let meta = KeyMetadata::new(
1362 "id1".to_string(),
1363 "test".to_string(),
1364 KeyAlgorithm::Aes256Gcm,
1365 KeyPurpose::Encryption,
1366 1,
1367 )
1368 .with_expiry(now - Duration::from_secs(1));
1369 assert!(meta.is_expired());
1370 }
1371
1372 #[test]
1373 fn test_key_metadata_with_tag_and_description() {
1374 let meta = KeyMetadata::new(
1375 "id1".to_string(),
1376 "test".to_string(),
1377 KeyAlgorithm::Aes256Gcm,
1378 KeyPurpose::Encryption,
1379 1,
1380 )
1381 .with_description("test key")
1382 .with_tag("production")
1383 .with_tag("critical");
1384 assert_eq!(meta.description, "test key");
1385 assert_eq!(meta.tags, vec!["production", "critical"]);
1386 }
1387
1388 #[test]
1391 fn test_key_entry_compute_fingerprint() {
1392 let material = b"test-key-material";
1393 let fp = KeyEntry::compute_fingerprint(material);
1394 assert_eq!(fp.len(), 64); }
1396
1397 #[test]
1398 fn test_key_entry_verify_fingerprint() {
1399 let material = b"test-key-material";
1400 let entry = KeyEntry {
1401 metadata: KeyMetadata::new(
1402 "id1".to_string(),
1403 "test".to_string(),
1404 KeyAlgorithm::Aes256Gcm,
1405 KeyPurpose::Encryption,
1406 1,
1407 ),
1408 material: material.to_vec(),
1409 fingerprint: KeyEntry::compute_fingerprint(material),
1410 };
1411 assert!(entry.verify_fingerprint());
1412 }
1413
1414 #[test]
1415 fn test_key_entry_verify_fingerprint_mismatch() {
1416 let entry = KeyEntry {
1417 metadata: KeyMetadata::new(
1418 "id1".to_string(),
1419 "test".to_string(),
1420 KeyAlgorithm::Aes256Gcm,
1421 KeyPurpose::Encryption,
1422 1,
1423 ),
1424 material: b"actual-material".to_vec(),
1425 fingerprint: "0000000000000000000000000000000000000000000000000000000000000000"
1426 .to_string(),
1427 };
1428 assert!(!entry.verify_fingerprint());
1429 }
1430
1431 #[test]
1434 fn test_key_generator_generate_material_length() {
1435 let gen = KeyGenerator::new();
1436 let material = gen.generate_material(KeyAlgorithm::Aes256Gcm);
1437 assert_eq!(material.len(), 32);
1438 }
1439
1440 #[test]
1441 fn test_key_generator_generate_material_random() {
1442 let gen = KeyGenerator::new();
1443 let a = gen.generate_material(KeyAlgorithm::Aes256Gcm);
1444 let b = gen.generate_material(KeyAlgorithm::Aes256Gcm);
1445 assert_ne!(a, b, "随机生成的密钥应不同");
1446 }
1447
1448 #[test]
1449 fn test_key_generator_generate_key_id() {
1450 let id1 = KeyGenerator::generate_key_id();
1451 let id2 = KeyGenerator::generate_key_id();
1452 assert_eq!(id1.len(), 32); assert_ne!(id1, id2);
1454 }
1455
1456 #[test]
1457 fn test_key_generator_generate_full_entry() {
1458 let gen = KeyGenerator::new();
1459 let entry = gen.generate("test-key", KeyAlgorithm::HmacSha256, KeyPurpose::Signing, 1);
1460 assert_eq!(entry.metadata.name, "test-key");
1461 assert_eq!(entry.metadata.algorithm, KeyAlgorithm::HmacSha256);
1462 assert_eq!(entry.metadata.version, 1);
1463 assert_eq!(entry.material.len(), 32);
1464 assert!(entry.verify_fingerprint());
1465 }
1466
1467 #[test]
1470 fn test_rotation_policy_time_interval() {
1471 let policy = RotationPolicy::TimeInterval(Duration::from_secs(100));
1472 assert!(!policy.needs_rotation(Duration::from_secs(50), 0));
1473 assert!(policy.needs_rotation(Duration::from_secs(100), 0));
1474 assert!(policy.needs_rotation(Duration::from_secs(150), 0));
1475 }
1476
1477 #[test]
1478 fn test_rotation_policy_usage_count() {
1479 let policy = RotationPolicy::UsageCount(1000);
1480 assert!(!policy.needs_rotation(Duration::ZERO, 500));
1481 assert!(policy.needs_rotation(Duration::ZERO, 1000));
1482 assert!(policy.needs_rotation(Duration::ZERO, 1500));
1483 }
1484
1485 #[test]
1486 fn test_rotation_policy_time_or_usage() {
1487 let policy = RotationPolicy::TimeIntervalOrUsage(Duration::from_secs(100), 1000);
1488 assert!(!policy.needs_rotation(Duration::from_secs(50), 500));
1489 assert!(policy.needs_rotation(Duration::from_secs(100), 500));
1490 assert!(policy.needs_rotation(Duration::from_secs(50), 1000));
1491 }
1492
1493 #[test]
1494 fn test_rotation_policy_never() {
1495 let policy = RotationPolicy::Never;
1496 assert!(!policy.needs_rotation(Duration::from_secs(999999), 999999));
1497 }
1498
1499 #[test]
1502 fn test_key_store_put_and_get() {
1503 let mut store = KeyStore::new();
1504 let gen = KeyGenerator::new();
1505 let entry = gen.generate("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption, 1);
1506 let key_id = store.put(entry);
1507 assert!(store.get(&key_id).is_some());
1508 assert_eq!(store.count(), 1);
1509 }
1510
1511 #[test]
1512 fn test_key_store_get_latest_by_name() {
1513 let mut store = KeyStore::new();
1514 let gen = KeyGenerator::new();
1515 let e1 = gen.generate("key", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption, 1);
1516 let e2 = gen.generate("key", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption, 2);
1517 store.put(e1);
1518 store.put(e2);
1519 let latest = store.get_latest_by_name("key").unwrap();
1520 assert_eq!(latest.metadata.version, 2);
1521 }
1522
1523 #[test]
1524 fn test_key_store_get_by_name_and_version() {
1525 let mut store = KeyStore::new();
1526 let gen = KeyGenerator::new();
1527 let e1 = gen.generate("key", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption, 1);
1528 let e2 = gen.generate("key", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption, 2);
1529 store.put(e1);
1530 store.put(e2);
1531 assert!(store.get_by_name_and_version("key", 1).is_some());
1532 assert!(store.get_by_name_and_version("key", 2).is_some());
1533 assert!(store.get_by_name_and_version("key", 3).is_none());
1534 }
1535
1536 #[test]
1537 fn test_key_store_get_all_versions() {
1538 let mut store = KeyStore::new();
1539 let gen = KeyGenerator::new();
1540 for v in 1..=3 {
1541 let entry = gen.generate("key", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption, v);
1542 store.put(entry);
1543 }
1544 let versions = store.get_all_versions("key");
1545 assert_eq!(versions.len(), 3);
1546 }
1547
1548 #[test]
1549 fn test_key_store_remove() {
1550 let mut store = KeyStore::new();
1551 let gen = KeyGenerator::new();
1552 let entry = gen.generate("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption, 1);
1553 let key_id = store.put(entry);
1554 assert_eq!(store.count(), 1);
1555 let removed = store.remove(&key_id);
1556 assert!(removed.is_some());
1557 assert_eq!(store.count(), 0);
1558 }
1559
1560 #[test]
1561 fn test_key_store_set_status() {
1562 let mut store = KeyStore::new();
1563 let gen = KeyGenerator::new();
1564 let entry = gen.generate("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption, 1);
1565 let key_id = store.put(entry);
1566 assert!(store.set_status(&key_id, KeyStatus::Revoked));
1567 assert_eq!(
1568 store.get(&key_id).unwrap().metadata.status,
1569 KeyStatus::Revoked
1570 );
1571 }
1572
1573 #[test]
1574 fn test_key_store_get_by_tag() {
1575 let mut store = KeyStore::new();
1576 let gen = KeyGenerator::new();
1577 let mut entry = gen.generate("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption, 1);
1578 entry.metadata.tags = vec!["production".to_string()];
1579 store.put(entry);
1580 let results = store.get_by_tag("production");
1581 assert_eq!(results.len(), 1);
1582 assert_eq!(store.get_by_tag("staging").len(), 0);
1583 }
1584
1585 #[test]
1588 fn test_key_audit_log_record_and_query() {
1589 let mut log = KeyAuditLog::new();
1590 log.record(
1591 KeyEvent::Created,
1592 "id1".to_string(),
1593 "key1".to_string(),
1594 "created",
1595 );
1596 log.record(
1597 KeyEvent::Rotated,
1598 "id2".to_string(),
1599 "key1".to_string(),
1600 "rotated",
1601 );
1602 assert_eq!(log.count(), 2);
1603 assert_eq!(log.by_event(KeyEvent::Created).len(), 1);
1604 assert_eq!(log.by_key_name("key1").len(), 2);
1605 }
1606
1607 #[test]
1610 fn test_key_vault_generate_key() {
1611 let vault = KeyVault::new(RotationPolicy::Never);
1612 let key_id = vault
1613 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1614 .unwrap();
1615 assert!(vault.get_key(&key_id).is_some());
1616 assert_eq!(vault.key_count(), 1);
1617 assert_eq!(vault.version_count("test"), 1);
1618 }
1619
1620 #[test]
1621 fn test_key_vault_rotate_key() {
1622 let vault = KeyVault::new(RotationPolicy::Never);
1623 let old_id = vault
1624 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1625 .unwrap();
1626 let new_id = vault.rotate_key("test").unwrap();
1627 assert_ne!(old_id, new_id);
1628 assert_eq!(vault.version_count("test"), 2);
1629 let old = vault.get_key(&old_id).unwrap();
1631 assert_eq!(old.metadata.status, KeyStatus::Deprecated);
1632 let new_key = vault.get_key(&new_id).unwrap();
1634 assert_eq!(new_key.metadata.status, KeyStatus::Active);
1635 }
1636
1637 #[test]
1638 fn test_key_vault_rotate_nonexistent_key() {
1639 let vault = KeyVault::new(RotationPolicy::Never);
1640 let result = vault.rotate_key("nonexistent");
1641 assert!(result.is_err());
1642 }
1643
1644 #[test]
1645 fn test_key_vault_get_latest_key() {
1646 let vault = KeyVault::new(RotationPolicy::Never);
1647 vault
1648 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1649 .unwrap();
1650 vault.rotate_key("test").unwrap();
1651 let latest = vault.get_latest_key("test").unwrap();
1652 assert_eq!(latest.metadata.version, 2);
1653 }
1654
1655 #[test]
1656 fn test_key_vault_revoke_key() {
1657 let vault = KeyVault::new(RotationPolicy::Never);
1658 let key_id = vault
1659 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1660 .unwrap();
1661 vault.revoke_key(&key_id).unwrap();
1662 let entry = vault.get_key(&key_id).unwrap();
1663 assert_eq!(entry.metadata.status, KeyStatus::Revoked);
1664 }
1665
1666 #[test]
1667 fn test_key_vault_deprecate_key() {
1668 let vault = KeyVault::new(RotationPolicy::Never);
1669 let key_id = vault
1670 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1671 .unwrap();
1672 vault.deprecate_key(&key_id).unwrap();
1673 let entry = vault.get_key(&key_id).unwrap();
1674 assert_eq!(entry.metadata.status, KeyStatus::Deprecated);
1675 }
1676
1677 #[test]
1678 fn test_key_vault_audit_log() {
1679 let vault = KeyVault::new(RotationPolicy::Never);
1680 vault
1681 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1682 .unwrap();
1683 let log = vault.audit_log();
1684 assert!(log.count() >= 1);
1685 assert_eq!(log.by_event(KeyEvent::Created).len(), 1);
1686 }
1687
1688 #[test]
1689 fn test_key_vault_usage_count() {
1690 let vault = KeyVault::new(RotationPolicy::Never);
1691 let key_id = vault
1692 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1693 .unwrap();
1694 assert_eq!(vault.usage_count(&key_id), 0);
1695 vault.get_key(&key_id);
1696 vault.get_key(&key_id);
1697 assert_eq!(vault.usage_count(&key_id), 2);
1698 }
1699
1700 #[test]
1701 fn test_key_vault_needs_rotation_time() {
1702 let vault = KeyVault::new(RotationPolicy::TimeInterval(Duration::from_millis(0)));
1703 vault
1704 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1705 .unwrap();
1706 std::thread::sleep(Duration::from_millis(1));
1707 assert!(vault.needs_rotation("test"));
1708 }
1709
1710 #[test]
1711 fn test_key_vault_needs_rotation_never() {
1712 let vault = KeyVault::new(RotationPolicy::Never);
1713 vault
1714 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1715 .unwrap();
1716 assert!(!vault.needs_rotation("test"));
1717 }
1718
1719 #[test]
1720 fn test_key_vault_auto_rotate() {
1721 let vault = KeyVault::new(RotationPolicy::TimeInterval(Duration::from_millis(0)));
1722 vault
1723 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1724 .unwrap();
1725 std::thread::sleep(Duration::from_millis(1));
1726 let new_id = vault.auto_rotate("test");
1727 assert!(new_id.is_some());
1728 assert_eq!(vault.version_count("test"), 2);
1729 }
1730
1731 #[test]
1732 fn test_key_vault_auto_rotate_no_rotation_needed() {
1733 let vault = KeyVault::new(RotationPolicy::Never);
1734 vault
1735 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1736 .unwrap();
1737 let result = vault.auto_rotate("test");
1738 assert!(result.is_none());
1739 }
1740
1741 #[test]
1742 fn test_key_vault_delete_key() {
1743 let vault = KeyVault::new(RotationPolicy::Never);
1744 let key_id = vault
1745 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1746 .unwrap();
1747 assert_eq!(vault.key_count(), 1);
1748 vault.delete_key(&key_id).unwrap();
1749 assert_eq!(vault.key_count(), 0);
1750 }
1751
1752 #[test]
1753 fn test_key_vault_get_by_status() {
1754 let vault = KeyVault::new(RotationPolicy::Never);
1755 let id1 = vault
1756 .generate_key("k1", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1757 .unwrap();
1758 vault
1759 .generate_key("k2", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1760 .unwrap();
1761 vault.revoke_key(&id1).unwrap();
1762 let active = vault.get_by_status(KeyStatus::Active);
1763 let revoked = vault.get_by_status(KeyStatus::Revoked);
1764 assert_eq!(active.len(), 1);
1765 assert_eq!(revoked.len(), 1);
1766 }
1767
1768 #[test]
1769 fn test_key_vault_concurrent_access() {
1770 use std::sync::Arc;
1771 use std::thread;
1772 let vault = Arc::new(KeyVault::new(RotationPolicy::Never));
1773 let id = vault
1774 .generate_key("test", KeyAlgorithm::Aes256Gcm, KeyPurpose::Encryption)
1775 .unwrap();
1776 let mut handles = vec![];
1777 for _ in 0..4 {
1778 let v = vault.clone();
1779 let kid = id.clone();
1780 handles.push(thread::spawn(move || {
1781 v.get_key(&kid);
1782 }));
1783 }
1784 for h in handles {
1785 h.join().expect("thread panicked");
1786 }
1787 assert_eq!(vault.usage_count(&id), 4);
1788 }
1789
1790 #[test]
1793 fn test_key_error_display() {
1794 let err = KeyError::KeyNotFound {
1795 name: "test".to_string(),
1796 };
1797 assert!(err.to_string().contains("test"));
1798 let err2 = KeyError::KeyRevoked {
1799 key_id: "id1".to_string(),
1800 };
1801 assert!(err2.to_string().contains("id1"));
1802 }
1803
1804 #[test]
1807 fn test_kdf_default() {
1808 let cfg = KeyDerivationConfig::default();
1809 assert_eq!(cfg.algorithm, "pbkdf2");
1810 assert_eq!(cfg.key_len, 32);
1811 }
1812
1813 #[test]
1814 fn test_kdf_pbkdf2() {
1815 let cfg = KeyDerivationConfig::pbkdf2(100_000);
1816 assert!(cfg.is_pbkdf2());
1817 assert!(!cfg.is_argon2());
1818 assert_eq!(cfg.iterations, 100_000);
1819 }
1820
1821 #[test]
1822 fn test_kdf_argon2id() {
1823 let cfg = KeyDerivationConfig::argon2id(3, 65536, 4);
1824 assert!(cfg.is_argon2());
1825 assert!(!cfg.is_pbkdf2());
1826 assert_eq!(cfg.memory_kb, Some(65536));
1827 assert_eq!(cfg.parallelism, Some(4));
1828 }
1829
1830 #[test]
1831 fn test_kdf_scrypt() {
1832 let cfg = KeyDerivationConfig::scrypt(1024);
1833 assert_eq!(cfg.algorithm, "scrypt");
1834 assert_eq!(cfg.iterations, 1024);
1835 }
1836
1837 #[test]
1838 fn test_kdf_generate_salt() {
1839 let cfg = KeyDerivationConfig::default();
1840 let salt = cfg.generate_salt();
1841 assert_eq!(salt.len(), cfg.salt_len);
1842 }
1843
1844 #[test]
1847 fn test_nonce_generator_gcm() {
1848 let gen = NonceGenerator::for_gcm();
1849 let nonce = gen.generate();
1850 assert_eq!(nonce.len(), 12);
1851 }
1852
1853 #[test]
1854 fn test_nonce_generator_chacha20() {
1855 let gen = NonceGenerator::for_chacha20();
1856 let nonce = gen.generate();
1857 assert_eq!(nonce.len(), 16);
1858 }
1859
1860 #[test]
1861 fn test_nonce_generator_custom() {
1862 let gen = NonceGenerator::new(32);
1863 assert_eq!(gen.len(), 32);
1864 let nonce = gen.generate();
1865 assert_eq!(nonce.len(), 32);
1866 }
1867
1868 #[test]
1869 fn test_nonce_generator_unique() {
1870 let gen = NonceGenerator::for_gcm();
1871 let n1 = gen.generate();
1872 let n2 = gen.generate();
1873 assert_ne!(n1, n2);
1874 }
1875
1876 #[test]
1879 fn test_encryption_context_default() {
1880 let ctx = EncryptionContext::default();
1881 assert!(!ctx.has_aad());
1882 assert!(!ctx.has_tenant());
1883 }
1884
1885 #[test]
1886 fn test_encryption_context_builder() {
1887 let ctx = EncryptionContext::new()
1888 .with_aad(b"associated".to_vec())
1889 .with_label("db")
1890 .with_tenant("tenant1");
1891 assert!(ctx.has_aad());
1892 assert!(ctx.has_tenant());
1893 assert_eq!(ctx.label, "db");
1894 assert_eq!(ctx.tenant_id, Some("tenant1".to_string()));
1895 }
1896
1897 #[test]
1900 fn test_key_fingerprint() {
1901 let key = b"my-secret-key-1234567890123456";
1902 let fp = KeyFingerprint::from_key_material(key, KeyAlgorithm::Aes256Gcm);
1903 assert_eq!(fp.sha256_hex.len(), 64);
1904 assert_eq!(fp.short().len(), 8);
1905 }
1906
1907 #[test]
1908 fn test_key_fingerprint_matches() {
1909 let key = b"my-secret-key-1234567890123456";
1910 let fp1 = KeyFingerprint::from_key_material(key, KeyAlgorithm::Aes256Gcm);
1911 let fp2 = KeyFingerprint::from_key_material(key, KeyAlgorithm::Aes256Gcm);
1912 assert!(fp1.matches(&fp2));
1913 }
1914
1915 #[test]
1916 fn test_key_fingerprint_not_matches() {
1917 let fp1 = KeyFingerprint::from_key_material(b"key1", KeyAlgorithm::Aes256Gcm);
1918 let fp2 = KeyFingerprint::from_key_material(b"key2", KeyAlgorithm::Aes256Gcm);
1919 assert!(!fp1.matches(&fp2));
1920 }
1921
1922 #[test]
1923 fn test_key_fingerprint_display() {
1924 let fp = KeyFingerprint::from_key_material(b"key", KeyAlgorithm::Aes256Gcm);
1925 let s = format!("{}", fp);
1926 assert!(s.contains("aes-256-gcm"));
1927 }
1928
1929 #[test]
1932 fn test_security_policy_default() {
1933 let policy = SecurityPolicy::default();
1934 assert!(policy.require_encryption_at_rest);
1935 assert!(policy.require_key_rotation);
1936 assert!(policy.is_algorithm_allowed(KeyAlgorithm::Aes256Gcm));
1937 }
1938
1939 #[test]
1940 fn test_security_policy_strict() {
1941 let policy = SecurityPolicy::strict();
1942 assert!(policy.is_algorithm_allowed(KeyAlgorithm::Aes256Gcm));
1943 assert!(!policy.is_algorithm_allowed(KeyAlgorithm::HmacSha256));
1944 }
1945
1946 #[test]
1947 fn test_security_policy_key_length() {
1948 let policy = SecurityPolicy::default();
1949 assert!(policy.is_key_length_ok(32));
1950 assert!(!policy.is_key_length_ok(16));
1951 }
1952}