wolf_crypto/
buf.rs

1//! Types for Keys, IVs, and Generally Sensitive Bytes
2use zeroize::Zeroize;
3use core::convert::TryFrom;
4use crate::can_cast_u32;
5use core::fmt;
6
7/// A trait for types that represent initialization vector (IV) sizes.
8///
9/// This trait is sealed and can only be implemented within this crate.
10pub trait IvSize : crate::sealed::Sealed {
11    /// Returns the size of the IV in bytes.
12    fn size() -> usize;
13
14    /// Returns the size of the IV as a [`u32`].
15    ///
16    /// # Panics
17    ///
18    /// In debug builds, this method will panic if the size is greater than [`u32::MAX`].
19    #[cfg_attr(not(debug_assertions), inline(always))]
20    fn size_32() -> u32 {
21        debug_assert!(can_cast_u32(Self::size()), "IvSize `size` is too large.");
22        Self::size() as u32
23    }
24}
25
26macro_rules! make_iv_size {
27    ($ident:ident = $size:literal) => {
28        #[doc = concat!("Represents a `", stringify!($size), "` byte IV size.")]
29        pub struct $ident;
30
31        impl $ident {
32            #[doc = concat!(
33                "The size of the IV as a u32 constant (`", stringify!($size), "`)"
34            )]
35            pub const SIZE_U32: u32 = $size;
36            #[doc = concat!(
37                "The size of the IV as a usize constant (`", stringify!($size), "`)"
38            )]
39            pub const SIZE: usize = $size;
40        }
41
42        impl $crate::sealed::Sealed for $ident {}
43
44        impl $crate::buf::IvSize for $ident {
45            #[doc = concat!("Returns the size of the IV in bytes. (`", stringify!($size), "`)")]
46            #[inline]
47            fn size() -> usize {
48                Self::SIZE
49            }
50
51            #[doc = concat!("Returns the size of the IV in bytes. (`", stringify!($size), "`)")]
52            #[inline]
53            fn size_32() -> u32 {
54                Self::SIZE_U32
55            }
56        }
57    };
58}
59
60make_iv_size! { U16 = 16 }
61make_iv_size! { U12 = 12 }
62
63/// A trait for types that can be used as generic initialization vectors.
64pub trait GenericIv {
65    /// The associated size type for this IV.
66    type Size : IvSize;
67
68    /// Returns a reference to the IV as a byte slice.
69    fn as_slice(&self) -> &[u8];
70}
71
72/// Error returned when the provided slice is not the expected length.
73#[derive(Debug)]
74pub struct InvalidSize;
75
76impl fmt::Display for InvalidSize {
77    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78        f.write_str("InvalidSize")
79    }
80}
81
82std! {
83    impl std::error::Error for InvalidSize {}
84}
85
86macro_rules! def_nonce {
87    ($ident:ident, $size:ident) => {
88        #[doc = concat!("Represents an IV / Nonce with the size: [`", stringify!($size), "`].")]
89        #[doc = ""]
90        #[doc = concat!("[`", stringify!($size), "`]: crate::buf::", stringify!($size))]
91        #[repr(transparent)]
92        #[cfg_attr(test, derive(Debug))]
93        pub struct $ident {
94            inner: [u8; $size::SIZE]
95        }
96
97        impl $ident {
98            /// The size type for this IV / Nonce.
99            pub const SIZE: $size = $size;
100
101            #[doc = "Creates a new nonce / IV"]
102            pub const fn new(inner: [u8; $size::SIZE]) -> Self {
103                Self { inner }
104            }
105
106            /// Returns a reference to the IV / Nonce as a slice.
107            #[inline]
108            pub const fn slice(&self) -> &[u8] {
109                self.inner.as_slice()
110            }
111
112            /// Zeros out the contents of the IV / Nonce.
113            #[inline]
114            pub fn zero(&mut self) {
115                self.inner.as_mut_slice().zeroize();
116            }
117            /// Creates a copy of the IV / Nonce.
118            ///
119            /// This type purposefully does not derive the `Copy` trait, to ensure that nonce / IV
120            /// reuse is explicit.
121            #[inline]
122            #[must_use]
123            pub const fn copy(&self) -> Self {
124                Self::new(self.inner)
125            }
126        }
127
128        impl GenericIv for $ident {
129            type Size = $size;
130
131            #[inline]
132            fn as_slice(&self) -> &[u8] {
133                self.inner.as_slice()
134            }
135        }
136
137        impl From<[u8; $size::SIZE]> for $ident {
138            fn from(value: [u8; $size::SIZE]) -> Self {
139                Self::new(value)
140            }
141        }
142
143        impl<'s> From<&'s [u8; $size::SIZE]> for $ident {
144            fn from(value: &'s [u8; $size::SIZE]) -> Self {
145                Self::new(*value)
146            }
147        }
148
149        // NOTE: with #[repr(transparent)] TryFrom for [u8; C] is implicitly implemented.
150
151        impl<'s> TryFrom<&'s [u8]> for $ident {
152            type Error = InvalidSize;
153
154            fn try_from(value: &'s [u8]) -> Result<Self, Self::Error> {
155                match value.try_into() {
156                    Ok(res) => Ok(Self::new(res)),
157                    Err(_) => Err(InvalidSize)
158                }
159            }
160        }
161
162        #[cfg(test)]
163        impl proptest::arbitrary::Arbitrary for $ident {
164            type Parameters = ();
165
166            fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
167                use proptest::strategy::Strategy as _;
168                proptest::arbitrary::any::<[u8; $size::SIZE]>().prop_map($ident::new).boxed()
169            }
170
171            type Strategy = proptest::prelude::BoxedStrategy<Self>;
172        }
173    };
174}
175
176def_nonce!(Nonce, U12);
177def_nonce!(Nonce16, U16);
178def_nonce!(Iv, U16);
179
180impl<'r> GenericIv for &'r [u8; 12] {
181    type Size = U12;
182
183    #[inline]
184    fn as_slice(&self) -> &[u8] {
185        *self
186    }
187}
188
189impl GenericIv for [u8; 12] {
190    type Size = U12;
191
192    #[inline]
193    fn as_slice(&self) -> &[u8] {
194        self
195    }
196}
197
198impl<'r> GenericIv for &'r [u8; 16] {
199    type Size = U16;
200
201    #[inline]
202    fn as_slice(&self) -> &[u8] {
203        *self
204    }
205}
206
207impl GenericIv for [u8; 16] {
208    type Size = U16;
209
210    #[inline]
211    fn as_slice(&self) -> &[u8] {
212        self
213    }
214}
215
216/// A trait for types that represent byte arrays.
217pub trait ByteArray {
218    /// The target type of the byte array.
219    type Target;
220
221    /// Returns the readable capacity of the byte array.
222    fn capacity(&self) -> usize;
223
224    /// Returns a reference to the byte array as a slice.
225    fn slice(&self) -> &[u8];
226    /// Returns a mutable reference to the byte array as a slice.
227    fn mut_slice(&mut self) -> &mut [u8];
228
229    /// Zeros out the contents of the byte array.
230    #[inline]
231    fn zero(&mut self) {
232        self.mut_slice().zeroize();
233    }
234}
235
236impl<const N: usize> ByteArray for [u8; N] {
237    type Target = Self;
238
239    #[inline]
240    fn capacity(&self) -> usize {
241        N
242    }
243
244    #[inline]
245    fn slice(&self) -> &[u8] {
246        self.as_slice()
247    }
248    #[inline]
249    fn mut_slice(&mut self) -> &mut [u8] {
250        self.as_mut_slice()
251    }
252}
253
254#[cfg(feature = "alloc")]
255impl ByteArray for Vec<u8> {
256    type Target = Self;
257
258    #[inline]
259    fn capacity(&self) -> usize {
260        self.len()
261    }
262
263    #[inline]
264    fn slice(&self) -> &[u8] {
265        self.as_slice()
266    }
267    #[inline]
268    fn mut_slice(&mut self) -> &mut [u8] {
269        self.as_mut_slice()
270    }
271}