Skip to main content

fast_floe/
key.rs

1use core::fmt;
2
3use zeroize::Zeroize;
4
5use crate::backends::ProviderRng;
6use crate::{Error, Provider, Result};
7
8/// A 256-bit FLOE key that zeroizes its owned bytes on drop.
9///
10/// Use [`Key::generate`] for a fresh random key or [`Key::from_bytes`] when
11/// importing existing key material.
12pub struct Key {
13    bytes: [u8; Self::LEN],
14    provider: Option<Provider>,
15}
16
17impl Key {
18    /// Required FLOE key length in bytes.
19    pub const LEN: usize = 32;
20
21    /// Generates a new 256-bit FLOE key with the build default provider.
22    ///
23    /// # Errors
24    ///
25    /// Returns [`Error::ProviderSelectionRequired`] when multiple providers
26    /// are compiled, or [`Error::RngFailure`] if the provider cannot obtain
27    /// secure randomness.
28    pub fn generate() -> Result<Self> {
29        let provider = Provider::build_default().ok_or(Error::ProviderSelectionRequired)?;
30        Self::generate_with_provider(provider)
31    }
32
33    /// Generates a new 256-bit FLOE key bound to `provider`.
34    ///
35    /// # Errors
36    ///
37    /// Returns [`Error::RngFailure`] if the provider cannot obtain secure
38    /// randomness.
39    pub fn generate_with_provider(provider: Provider) -> Result<Self> {
40        let mut rng = ProviderRng::new(provider);
41        let mut key = [0u8; Self::LEN];
42        rng.generate_key(&mut key)?;
43
44        Ok(Self {
45            bytes: key,
46            provider: Some(provider),
47        })
48    }
49
50    /// Imports an existing 256-bit key using the build default provider.
51    ///
52    /// Provider resolution is deferred until [`Self::provider`] or the first
53    /// cryptographic operation.
54    #[must_use]
55    pub const fn from_bytes(bytes: [u8; Self::LEN]) -> Self {
56        Self {
57            bytes,
58            provider: None,
59        }
60    }
61
62    /// Imports an existing 256-bit key bound to `provider`.
63    #[must_use]
64    pub const fn from_bytes_with_provider(bytes: [u8; Self::LEN], provider: Provider) -> Self {
65        Self {
66            bytes,
67            provider: Some(provider),
68        }
69    }
70
71    /// Returns the raw secret key bytes. Handle with care.
72    #[must_use]
73    pub const fn as_bytes(&self) -> &[u8; Self::LEN] {
74        &self.bytes
75    }
76
77    /// Returns the concrete provider this key will use.
78    ///
79    /// # Errors
80    ///
81    /// Returns [`Error::ProviderSelectionRequired`] when this key has no
82    /// explicit provider and multiple providers are compiled.
83    pub const fn provider(&self) -> Result<Provider> {
84        match self.provider {
85            Some(provider) => Ok(provider),
86            None => match Provider::build_default() {
87                Some(provider) => Ok(provider),
88                None => Err(Error::ProviderSelectionRequired),
89            },
90        }
91    }
92}
93
94impl Clone for Key {
95    fn clone(&self) -> Self {
96        Self {
97            bytes: self.bytes,
98            provider: self.provider,
99        }
100    }
101}
102
103impl Drop for Key {
104    fn drop(&mut self) {
105        self.bytes.zeroize();
106    }
107}
108
109impl fmt::Debug for Key {
110    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111        f.debug_tuple("Key").field(&"[REDACTED]").finish()
112    }
113}
114
115impl From<[u8; Key::LEN]> for Key {
116    fn from(bytes: [u8; Key::LEN]) -> Self {
117        Self::from_bytes(bytes)
118    }
119}
120
121impl TryFrom<&[u8]> for Key {
122    type Error = Error;
123
124    fn try_from(bytes: &[u8]) -> Result<Self> {
125        let actual = bytes.len();
126        let bytes = bytes
127            .try_into()
128            .map_err(|_| Error::InvalidKeyLength { actual })?;
129        Ok(Self::from_bytes(bytes))
130    }
131}
132
133// The all-zero key every KAT is generated with, bound to the build's first
134// compiled provider so multi-provider test builds stay deterministic.
135#[cfg(test)]
136pub(crate) fn test_key() -> Key {
137    Key::from_bytes_with_provider([0; Key::LEN], Provider::COMPILED[0])
138}
139
140#[cfg(test)]
141mod tests {
142    use super::*;
143    use crate::{Parameters, decrypt, encrypt};
144
145    #[test]
146    fn implicit_keys_resolve_only_for_single_provider_builds() {
147        // Given a key imported without naming a provider
148        let key = Key::from_bytes([0x21; Key::LEN]);
149
150        if let Some(provider) = Provider::build_default() {
151            // When exactly one provider is compiled into this build
152
153            // Then imported and generated keys resolve to it implicitly
154            assert_eq!(key.provider(), Ok(provider));
155            assert_eq!(Key::generate().unwrap().provider(), Ok(provider));
156
157            // Then the implicitly resolved key round-trips a message
158            let ciphertext = encrypt(
159                &key,
160                b"implicit provider",
161                Parameters::SEGMENT_4_KIB,
162                b"message",
163            )
164            .unwrap();
165            assert_eq!(
166                decrypt(&key, b"implicit provider", &ciphertext).unwrap(),
167                b"message"
168            );
169        } else {
170            // When multiple providers are compiled into this build
171
172            // Then resolution and generation demand an explicit provider
173            assert_eq!(key.provider(), Err(Error::ProviderSelectionRequired));
174            assert!(matches!(
175                Key::generate(),
176                Err(Error::ProviderSelectionRequired)
177            ));
178        }
179    }
180
181    #[test]
182    fn generated_keys_have_required_size() {
183        // Given every provider compiled into this build
184        for &provider in Provider::COMPILED {
185            // When the provider generates a key
186            // Then the key is exactly Key::LEN bytes
187            assert_eq!(
188                Key::generate_with_provider(provider)
189                    .unwrap()
190                    .as_bytes()
191                    .len(),
192                Key::LEN
193            );
194        }
195    }
196
197    #[test]
198    fn key_debug_is_redacted() {
199        // Given a key with a recognizable byte pattern
200        let key = Key::from_bytes([0xAB; Key::LEN]);
201
202        // When the key is formatted for debugging
203        let formatted = format!("{key:?}");
204
205        // Then the output is redacted and contains no key material
206        assert!(formatted.contains("REDACTED"));
207        assert!(!formatted.contains("ab"));
208        assert!(!formatted.contains("AB"));
209        assert!(!formatted.contains("171"));
210    }
211
212    #[test]
213    fn key_from_array_preserves_bytes() {
214        // Given a key converted from a byte array
215        let bytes = [0x42; Key::LEN];
216        let key = Key::from(bytes);
217
218        // Then it carries the same bytes
219        assert_eq!(key.as_bytes(), &bytes);
220    }
221
222    #[test]
223    fn key_try_from_slice_accepts_exact_length() {
224        // Given a slice of exactly Key::LEN bytes
225        let bytes = [0x42; Key::LEN];
226
227        // When it is converted, then the key preserves the bytes
228        let key = Key::try_from(&bytes[..]).unwrap();
229        assert_eq!(key.as_bytes(), &bytes);
230    }
231
232    #[test]
233    fn key_try_from_slice_rejects_short_and_long_inputs() {
234        // Given slices one byte shorter and one byte longer than a key
235        let bytes = [0x42; Key::LEN + 1];
236
237        // When each is converted, then the actual length is reported
238        for length in [Key::LEN - 1, Key::LEN + 1] {
239            assert!(matches!(
240                Key::try_from(&bytes[..length]),
241                Err(Error::InvalidKeyLength { actual }) if actual == length
242            ));
243        }
244    }
245}