1use core::fmt;
2
3use zeroize::Zeroize;
4
5use crate::backends::ProviderRng;
6use crate::{Error, Provider, Result};
7
8pub struct Key {
13 bytes: [u8; Self::LEN],
14 provider: Option<Provider>,
15}
16
17impl Key {
18 pub const LEN: usize = 32;
20
21 pub fn generate() -> Result<Self> {
29 let provider = Provider::build_default().ok_or(Error::ProviderSelectionRequired)?;
30 Self::generate_with_provider(provider)
31 }
32
33 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 #[must_use]
55 pub const fn from_bytes(bytes: [u8; Self::LEN]) -> Self {
56 Self {
57 bytes,
58 provider: None,
59 }
60 }
61
62 #[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 #[must_use]
73 pub const fn as_bytes(&self) -> &[u8; Self::LEN] {
74 &self.bytes
75 }
76
77 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#[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 let key = Key::from_bytes([0x21; Key::LEN]);
149
150 if let Some(provider) = Provider::build_default() {
151 assert_eq!(key.provider(), Ok(provider));
155 assert_eq!(Key::generate().unwrap().provider(), Ok(provider));
156
157 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 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 for &provider in Provider::COMPILED {
185 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 let key = Key::from_bytes([0xAB; Key::LEN]);
201
202 let formatted = format!("{key:?}");
204
205 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 let bytes = [0x42; Key::LEN];
216 let key = Key::from(bytes);
217
218 assert_eq!(key.as_bytes(), &bytes);
220 }
221
222 #[test]
223 fn key_try_from_slice_accepts_exact_length() {
224 let bytes = [0x42; Key::LEN];
226
227 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 let bytes = [0x42; Key::LEN + 1];
236
237 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}