1use std::fmt;
6
7use zeroize::Zeroize;
8
9use crate::error::{Error, Result};
10
11pub struct Key<const N: usize>([u8; N]);
13
14impl<const N: usize> Key<N> {
15 pub fn new(bytes: [u8; N]) -> Self {
16 Self(bytes)
17 }
18
19 pub fn from_slice(bytes: &[u8], label: &'static str) -> Result<Self> {
21 let array: [u8; N] = bytes.try_into().map_err(|_| Error::InvalidKeyLength {
22 label,
23 expected: N,
24 got: bytes.len(),
25 })?;
26 Ok(Self(array))
27 }
28
29 pub fn as_bytes(&self) -> &[u8; N] {
30 &self.0
31 }
32}
33
34impl<const N: usize> Drop for Key<N> {
35 fn drop(&mut self) {
36 self.0.zeroize();
37 }
38}
39
40impl<const N: usize> fmt::Debug for Key<N> {
41 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 write!(f, "Key<{N}>(***)")
43 }
44}
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49
50 #[test]
51 fn from_slice_checks_length() {
52 let key = Key::<32>::from_slice(&[7u8; 32], "AES-256-GCM").unwrap();
53 assert_eq!(key.as_bytes()[0], 7);
54
55 let error = Key::<32>::from_slice(&[0u8; 16], "AES-256-GCM").unwrap_err();
56 assert_eq!(
57 error,
58 Error::InvalidKeyLength {
59 label: "AES-256-GCM",
60 expected: 32,
61 got: 16
62 }
63 );
64 }
65
66 #[test]
67 fn debug_is_redacted() {
68 let key = Key::<16>::new([0u8; 16]);
69 assert_eq!(format!("{key:?}"), "Key<16>(***)");
70 }
71}