spideroak_crypto/
mac.rs

1//! Message Authentication Codes.
2
3use core::{
4    array::TryFromSliceError,
5    fmt::{self, Debug},
6    result::Result,
7};
8
9use generic_array::{ArrayLength, GenericArray};
10use subtle::{Choice, ConstantTimeEq};
11use typenum::{IsGreaterOrEqual, IsLess, U32, U48, U64, U65536};
12
13use crate::keys::{raw_key, InvalidKey, SecretKey};
14
15/// An error from a [`Mac`].
16#[derive(Debug, Eq, PartialEq)]
17pub enum MacError {
18    /// The key provided to [`Mac::new`] is insecure.
19    InsecureKey,
20    /// The MAC (authentication tag) could not be verified.
21    Verification,
22}
23
24impl fmt::Display for MacError {
25    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26        match self {
27            Self::InsecureKey => write!(f, "insecure key"),
28            Self::Verification => write!(f, "unable to verify MAC"),
29        }
30    }
31}
32
33impl core::error::Error for MacError {}
34
35/// A keyed Message Authentication Code Function (MAC).
36///
37/// # Requirements
38///
39/// The MAC must:
40///
41/// * Produce tags at least 256 bits long
42/// * Have at minimum a 256-bit security level
43/// * Reject insecure keys
44/// * Be at least strongly EUF-CMA (SUF-CMA) secure
45/// * Be a PRF
46///
47/// Examples of keyed MAC algorithms that fulfill these
48/// requirements include HMAC-SHA-512 (for |K| >= 256) and
49/// KMAC256 (for |K| >= 256).
50pub trait Mac: Clone + Sized {
51    /// An authentication tag.
52    type Tag: ConstantTimeEq;
53    /// The size in octets of a tag used by this [`Mac`].
54    ///
55    /// Must be at least 32 octets and less than 2¹⁶ octets.
56    type TagSize: ArrayLength + IsGreaterOrEqual<U32> + IsLess<U65536> + 'static;
57
58    /// A fixed-length key used by [`new`][Self::new].
59    ///
60    /// # Note About Variable Length Keys
61    ///
62    /// Some MACs (HMAC, KMAC, etc.) accept variable length keys
63    /// and do not have a fixed key length. For these MACs,
64    /// [`Key`][Self::Key] should have an appropriate default key
65    /// length. For example, KMAC256 should use a 256-bit key.
66    type Key: SecretKey<Size = Self::KeySize>;
67    /// The size in octets of [`Key`][Self::Key].
68    ///
69    /// Must be at least [`MinKeySize`][Self::MinKeySize] or 32
70    /// octets (whichever is greater) and less than 2¹⁶ octets.
71    type KeySize: ArrayLength
72        + IsGreaterOrEqual<Self::MinKeySize>
73        + IsGreaterOrEqual<U32>
74        + IsLess<U65536>
75        + 'static;
76
77    /// Creates a [`Mac`] with a fixed-length key.
78    fn new(key: &Self::Key) -> Self;
79
80    /// The minimum allowed size in octets of the variable length
81    /// key used by [`try_new`][Self::try_new].
82    ///
83    /// Must be at least 32 octets and less than 2¹⁶ octets.
84    type MinKeySize: ArrayLength + IsGreaterOrEqual<U32> + IsLess<U65536> + 'static;
85
86    /// Attempts to create a new `Mac` with a variable-length
87    /// key.
88    ///
89    /// It returns [`InvalidKey`] if `key` is shorter than
90    /// [`MinKeySize`][Self::MinKeySize].
91    ///
92    /// A `Mac` is allowed to require `key.len()` to be exactly
93    /// [`KeySize`][Self::KeySize].
94    fn try_new(key: &[u8]) -> Result<Self, InvalidKey>;
95
96    /// Updates the current MAC with `data`.
97    fn update(&mut self, data: &[u8]);
98
99    /// Returns the current authentication tag.
100    fn tag(self) -> Self::Tag;
101
102    /// Determines in constant time whether the current tag is
103    /// equal to `expect`.
104    fn verify(self, expect: &Self::Tag) -> Result<(), MacError> {
105        if bool::from(self.tag().ct_eq(expect)) {
106            Ok(())
107        } else {
108            Err(MacError::Verification)
109        }
110    }
111
112    /// Returns the tag for `data` using `key`.
113    ///
114    /// While this function is provided by default,
115    /// implementations of [`Mac`] are encouraged to provide
116    /// optimized "single-shot" implementations.
117    fn mac(key: &Self::Key, data: &[u8]) -> Self::Tag {
118        let mut h = Self::new(key);
119        h.update(data);
120        h.tag()
121    }
122}
123
124raw_key! {
125    /// A [`Mac`] key.
126    pub MacKey,
127}
128
129/// An authentication tag.
130#[derive(Copy, Clone, Debug)]
131pub struct Tag<const N: usize>([u8; N]);
132
133impl<const N: usize> Tag<N> {
134    /// Returns its length in octets.
135    #[allow(clippy::len_without_is_empty)]
136    #[inline]
137    pub const fn len(&self) -> usize {
138        N
139    }
140
141    /// Returns itself as a byte array.
142    #[inline]
143    pub const fn as_bytes(&self) -> &[u8; N] {
144        &self.0
145    }
146}
147
148impl<const N: usize> ConstantTimeEq for Tag<N> {
149    #[inline]
150    fn ct_eq(&self, other: &Self) -> Choice {
151        self.0[..].ct_eq(&other.0[..])
152    }
153}
154
155impl<const N: usize> AsRef<[u8]> for Tag<N> {
156    #[inline]
157    fn as_ref(&self) -> &[u8] {
158        &self.0
159    }
160}
161
162impl<const N: usize> From<[u8; N]> for Tag<N> {
163    #[inline]
164    fn from(tag: [u8; N]) -> Self {
165        Self(tag)
166    }
167}
168
169impl From<GenericArray<u8, U32>> for Tag<32> {
170    #[inline]
171    fn from(tag: GenericArray<u8, U32>) -> Self {
172        Self(tag.into())
173    }
174}
175
176impl From<GenericArray<u8, U48>> for Tag<48> {
177    #[inline]
178    fn from(tag: GenericArray<u8, U48>) -> Self {
179        Self(tag.into())
180    }
181}
182
183impl From<GenericArray<u8, U64>> for Tag<64> {
184    #[inline]
185    fn from(tag: GenericArray<u8, U64>) -> Self {
186        Self(tag.into())
187    }
188}
189
190impl<const N: usize> From<Tag<N>> for [u8; N] {
191    #[inline]
192    fn from(tag: Tag<N>) -> Self {
193        tag.0
194    }
195}
196
197impl<const N: usize> TryFrom<&[u8]> for Tag<N> {
198    type Error = TryFromSliceError;
199
200    #[inline]
201    fn try_from(tag: &[u8]) -> Result<Self, Self::Error> {
202        Ok(Tag(tag.try_into()?))
203    }
204}