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