Skip to main content

key_vault/
metadata.rs

1//! Public, non-secret metadata associated with a registered key.
2//!
3//! [`KeyMetadata`] is the information *about* a key that callers are allowed to
4//! see: when it was registered, how long the underlying material is, an
5//! optional hint about which algorithm family it belongs to. None of these
6//! fields contain key bytes; all of them are safe to log.
7//!
8//! Anything that would identify the *value* of the key (raw bytes, fragments,
9//! decoy bytes, codex tables) lives elsewhere and is unreachable through
10//! `KeyMetadata`.
11
12use core::time::Duration;
13
14/// Hint about which cryptographic algorithm a stored key is intended for.
15///
16/// This is advisory only. The vault does not verify that the registered bytes
17/// are actually a valid key for the named algorithm — that is the caller's
18/// responsibility, and the [`KeyFetch`](crate::KeyFetch) implementation's
19/// responsibility for hardware-backed sources. The variant exists so that
20/// audit-trail records and security monitors can label events meaningfully.
21#[non_exhaustive]
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
23pub enum AlgorithmHint {
24    /// 128-bit symmetric key (e.g. AES-128 KEK).
25    Symmetric128,
26    /// 256-bit symmetric key (e.g. AES-256, ChaCha20).
27    Symmetric256,
28    /// Ed25519 signing key (32-byte seed).
29    Ed25519,
30    /// X25519 ECDH private key (32 bytes).
31    X25519,
32    /// NIST P-256 ECDSA private key.
33    P256,
34    /// NIST P-384 ECDSA private key.
35    P384,
36    /// RSA-2048 private key (DER-encoded).
37    Rsa2048,
38    /// RSA-3072 private key.
39    Rsa3072,
40    /// RSA-4096 private key.
41    Rsa4096,
42    /// HMAC key (length given by [`KeyMetadata::length`]).
43    Hmac,
44    /// Other — caller supplies their own meaning out-of-band.
45    Other,
46}
47
48/// Public, non-secret information about a registered key.
49///
50/// `KeyMetadata` is safe to log, send to monitors, and include in audit
51/// records. It contains no information from which the key value could be
52/// derived.
53///
54/// The `length` field reports the *raw* key length in bytes — the size of the
55/// material that was registered with the vault before fragmentation. It is not
56/// the size of the in-memory fragmented representation (which is larger and
57/// implementation-defined).
58#[derive(Debug, Clone)]
59pub struct KeyMetadata {
60    /// Time at which the key was registered with the vault, expressed as a
61    /// `Duration` since the [`UNIX_EPOCH`](std::time::UNIX_EPOCH).
62    ///
63    /// We use `Duration` instead of `SystemTime` so the type is portable to
64    /// `no_std` builds in the future. Callers that need a wall-clock
65    /// representation can reconstruct one via
66    /// `UNIX_EPOCH + metadata.registered_since_epoch()`.
67    registered_since_epoch: Duration,
68    /// Raw key length in bytes.
69    length: usize,
70    /// Optional hint for downstream audit and monitoring code.
71    algorithm: Option<AlgorithmHint>,
72}
73
74impl KeyMetadata {
75    /// Construct metadata from explicit fields.
76    ///
77    /// Crate-internal — produced by the vault at registration time.
78    #[allow(dead_code)] // produced by the vault when keys are registered in Phase 0.3.
79    #[must_use]
80    pub(crate) fn new(
81        registered_since_epoch: Duration,
82        length: usize,
83        algorithm: Option<AlgorithmHint>,
84    ) -> Self {
85        Self {
86            registered_since_epoch,
87            length,
88            algorithm,
89        }
90    }
91
92    /// Raw key length, in bytes.
93    ///
94    /// This is the length of the material that was originally registered, not
95    /// the size of the in-memory fragmented representation.
96    #[must_use]
97    pub fn length(&self) -> usize {
98        self.length
99    }
100
101    /// Algorithm hint, if one was provided at registration.
102    #[must_use]
103    pub fn algorithm(&self) -> Option<AlgorithmHint> {
104        self.algorithm
105    }
106
107    /// Time of registration, expressed as a `Duration` since the Unix epoch.
108    #[must_use]
109    pub fn registered_since_epoch(&self) -> Duration {
110        self.registered_since_epoch
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117
118    #[test]
119    fn fields_round_trip() {
120        let meta = KeyMetadata::new(
121            Duration::from_secs(1_700_000_000),
122            32,
123            Some(AlgorithmHint::Symmetric256),
124        );
125        assert_eq!(meta.length(), 32);
126        assert_eq!(meta.algorithm(), Some(AlgorithmHint::Symmetric256));
127        assert_eq!(
128            meta.registered_since_epoch(),
129            Duration::from_secs(1_700_000_000)
130        );
131    }
132
133    #[test]
134    fn algorithm_hint_is_optional() {
135        let meta = KeyMetadata::new(Duration::ZERO, 16, None);
136        assert!(meta.algorithm().is_none());
137    }
138}