aranya_crypto_core/
keys.rs

1//! Basic keys and key material.
2
3use core::{borrow::Borrow, fmt::Debug, iter::IntoIterator, mem, result::Result};
4
5use generic_array::{ArrayLength, GenericArray, IntoArrayLength};
6use subtle::{Choice, ConstantTimeEq};
7use typenum::{generic_const_mappings::Const, IsLess, Unsigned, U65536};
8
9use crate::{
10    csprng::{Csprng, Random},
11    import::{ExportError, Import},
12    kdf::{Expand, Kdf, KdfError, Prk},
13    zeroize::ZeroizeOnDrop,
14};
15
16/// A fixed-length secret key.
17///
18/// Secret keys are either symmetric keys (e.g., for AES) or
19/// asymmetric private keys (e.g., for ECDH).
20pub trait SecretKey: Clone + ConstantTimeEq + for<'a> Import<&'a [u8]> + ZeroizeOnDrop {
21    /// Creates a random key, possibly using entropy from `rng`.
22    ///
23    /// Implementations are free to ignore `rng` and callers must
24    /// not rely on this function reading from `rng`.
25    fn new<R: Csprng>(rng: &mut R) -> Self;
26
27    /// The size of the key.
28    type Size: ArrayLength + 'static;
29    /// Shorthand for [`Size`][Self::Size];
30    const SIZE: usize = Self::Size::USIZE;
31
32    /// Attempts to export the key's secret data.
33    fn try_export_secret(&self) -> Result<SecretKeyBytes<Self::Size>, ExportError>;
34}
35
36/// A fixed-length byte encoding of a [`SecretKey`]'s data.
37#[derive(Clone, Default, ZeroizeOnDrop)]
38#[repr(transparent)]
39pub struct SecretKeyBytes<N: ArrayLength>(GenericArray<u8, N>);
40
41impl<N: ArrayLength> SecretKeyBytes<N> {
42    /// The size in bytes of the secret key.
43    pub const SIZE: usize = N::USIZE;
44
45    /// Creates a new secret.
46    #[inline]
47    pub const fn new(secret: GenericArray<u8, N>) -> Self {
48        Self(secret)
49    }
50
51    /// Returns the size in bytes of the secret key.
52    #[allow(clippy::len_without_is_empty)]
53    #[inline]
54    pub const fn len(&self) -> usize {
55        N::USIZE
56    }
57
58    /// Returns a reference to the secret key bytes as an array.
59    pub(crate) fn as_array<const U: usize>(&self) -> &[u8; U]
60    where
61        Const<U>: IntoArrayLength<ArrayLength = N>,
62    {
63        self.0.as_ref()
64    }
65
66    /// Returns the secret key bytes as a byte slice.
67    #[inline]
68    pub const fn as_bytes(&self) -> &[u8] {
69        self.0.as_slice()
70    }
71
72    /// Returns the secret as a mutable byte slice.
73    pub(crate) fn as_bytes_mut(&mut self) -> &mut [u8] {
74        &mut self.0
75    }
76
77    /// Converts the secret key bytes to an array.
78    #[inline]
79    pub fn into_bytes(mut self) -> GenericArray<u8, N> {
80        // This is fine since we're consuming the receiver. If
81        // the receiver were an exclusive reference this would be
82        // very wrong since it'd be replacing the secret key with
83        // all zeros.
84        mem::take(&mut self.0)
85    }
86}
87
88impl<N: ArrayLength> ConstantTimeEq for SecretKeyBytes<N> {
89    #[inline]
90    fn ct_eq(&self, other: &Self) -> Choice {
91        self.0.ct_eq(&other.0)
92    }
93}
94
95impl<N: ArrayLength> Random for SecretKeyBytes<N> {
96    fn random<R: Csprng>(rng: &mut R) -> Self {
97        Self(Random::random(rng))
98    }
99}
100
101impl<N: ArrayLength> Expand for SecretKeyBytes<N>
102where
103    N: IsLess<U65536>,
104{
105    type Size = N;
106
107    fn expand_multi<'a, K, I>(prk: &Prk<K::PrkSize>, info: I) -> Result<Self, KdfError>
108    where
109        K: Kdf,
110        I: IntoIterator<Item = &'a [u8]>,
111        I::IntoIter: Clone,
112    {
113        Ok(Self(Expand::expand_multi::<K, I>(prk, info)?))
114    }
115}
116
117/// A fixed-length asymmetric public key.
118pub trait PublicKey: Clone + Debug + Eq + for<'a> Import<&'a [u8]> {
119    /// The fixed-length byte encoding of the key.
120    type Data: Borrow<[u8]> + Clone + Sized;
121
122    /// Returns the byte representation of the public key.
123    fn export(&self) -> Self::Data;
124}
125
126raw_key! {
127    /// A generic secret key.
128    pub RawKey,
129}
130
131/// Creates a "raw" (i.e., a byte array) key.
132///
133/// # Example
134///
135/// ```
136/// use aranya_crypto_core::raw_key;
137///
138/// raw_key! {
139///     /// Some documentation.
140///     pub MyRawKey,
141///     /// Some more documentation.
142///     pub AnotherKey,
143/// }
144/// ```
145#[macro_export]
146macro_rules! raw_key {
147    () => {};
148    (
149        $(#[$meta:meta])*
150        $vis:vis $name:ident,
151        $($tail:tt)*
152    ) => {
153        $(#[$meta])*
154        #[derive(::core::clone::Clone, $crate::zeroize::ZeroizeOnDrop)]
155        #[repr(transparent)]
156        $vis struct $name<N: ::generic_array::ArrayLength>($crate::keys::SecretKeyBytes<N>);
157
158        impl<N: ::generic_array::ArrayLength> $name<N> {
159            /// Creates a new raw key.
160            #[inline]
161            pub const fn new(key: $crate::keys::SecretKeyBytes<N>) -> Self {
162                Self(key)
163            }
164
165            /// Returns the length in bytes of the key.
166            ///
167            /// Will always be exactly `N`.
168            #[allow(clippy::len_without_is_empty)]
169            #[inline]
170            pub const fn len(&self) -> usize {
171                self.0.len()
172            }
173
174            /// Returns the raw key bytes.
175            #[inline]
176            pub const fn as_slice(&self) -> &[u8] {
177                self.0.as_bytes()
178            }
179
180            /// Returns the raw key bytes.
181            #[inline]
182            pub const fn as_bytes(&self) -> &$crate::keys::SecretKeyBytes<N> {
183                &self.0
184            }
185
186            /// Converts the key into its raw key bytes.
187            #[inline]
188            pub fn into_bytes(mut self) -> $crate::keys::SecretKeyBytes<N> {
189                // This is fine since we're consuming the
190                // receiver. If the receiver were an exclusive
191                // reference this would be very wrong since it'd
192                // be replacing the secret key with all zeros.
193                ::core::mem::take(&mut self.0)
194            }
195        }
196
197        impl<N: ::generic_array::ArrayLength> $crate::keys::SecretKey for $name<N>
198        {
199            type Size = N;
200
201            #[inline]
202            fn new<R: $crate::csprng::Csprng>(rng: &mut R) -> Self {
203                Self($crate::csprng::Random::random(rng))
204            }
205
206            #[inline]
207            fn try_export_secret(&self) -> ::core::result::Result<
208                $crate::keys::SecretKeyBytes<Self::Size>,
209                $crate::import::ExportError,
210            > {
211                ::core::result::Result::Ok(self.0.clone())
212            }
213        }
214
215        impl<N: ::generic_array::ArrayLength> $crate::csprng::Random for $name<N> {
216            fn random<R: $crate::csprng::Csprng>(rng: &mut R) -> Self {
217                let sk = <$crate::keys::SecretKeyBytes<N> as $crate::csprng::Random>::random(rng);
218                Self(sk)
219            }
220        }
221
222
223        impl<N: ::generic_array::ArrayLength> $crate::kdf::Expand for $name<N>
224        where
225            N: ::typenum::IsLess<::typenum::U65536>
226        {
227            type Size = N;
228
229            fn expand_multi<'a, K, I>(
230                prk: &$crate::kdf::Prk<K::PrkSize>,
231                info: I,
232            ) -> ::core::result::Result<Self, $crate::kdf::KdfError>
233            where
234                K: $crate::kdf::Kdf,
235                I: ::core::iter::IntoIterator<Item = &'a [u8]>,
236                I::IntoIter: ::core::clone::Clone,
237            {
238                ::core::result::Result::Ok(Self($crate::kdf::Expand::expand_multi::<K, I>(prk, info)?))
239            }
240        }
241
242        impl<N: ::generic_array::ArrayLength> ::subtle::ConstantTimeEq for $name<N> {
243            #[inline]
244            fn ct_eq(&self, other: &Self) -> ::subtle::Choice {
245                self.0.ct_eq(&other.0)
246            }
247        }
248
249        impl<N, const U: usize> $crate::import::Import<[u8; U]> for $name<N>
250        where
251            N: ::generic_array::ArrayLength,
252            ::typenum::generic_const_mappings::Const<U>: ::generic_array::IntoArrayLength<ArrayLength = N>,
253        {
254            #[inline]
255            fn import(key: [u8; U]) -> ::core::result::Result<Self, $crate::import::ImportError> {
256                let sk = $crate::keys::SecretKeyBytes::new(key.into());
257                ::core::result::Result::Ok(Self(sk))
258            }
259        }
260
261        impl<N: ::generic_array::ArrayLength> $crate::import::Import<&[u8]> for $name<N> {
262            #[inline]
263            fn import(data: &[u8]) -> ::core::result::Result<Self, $crate::import::ImportError> {
264                let bytes = $crate::import::Import::<_>::import(data)?;
265                let sk = $crate::keys::SecretKeyBytes::new(bytes);
266                ::core::result::Result::Ok(Self(sk))
267            }
268        }
269
270        raw_key!{ $($tail)* }
271    };
272}
273pub(crate) use raw_key;