crypto_mac/
lib.rs

1//! This crate provides trait for Message Authentication Code (MAC) algorithms.
2
3#![no_std]
4#![cfg_attr(docsrs, feature(doc_cfg))]
5#![doc(
6    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
7    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
8    html_root_url = "https://docs.rs/crypto-mac/0.11.1"
9)]
10#![forbid(unsafe_code)]
11#![warn(missing_docs, rust_2018_idioms)]
12
13#[cfg(feature = "std")]
14extern crate std;
15
16#[cfg(feature = "cipher")]
17pub use cipher;
18#[cfg(feature = "cipher")]
19use cipher::{BlockCipher, NewBlockCipher};
20
21#[cfg(feature = "dev")]
22#[cfg_attr(docsrs, doc(cfg(feature = "dev")))]
23pub mod dev;
24
25mod errors;
26
27pub use crate::errors::{InvalidKeyLength, MacError};
28pub use generic_array::{self, typenum::consts};
29
30use generic_array::typenum::Unsigned;
31use generic_array::{ArrayLength, GenericArray};
32use subtle::{Choice, ConstantTimeEq};
33
34/// Key for an algorithm that implements [`NewMac`].
35pub type Key<M> = GenericArray<u8, <M as NewMac>::KeySize>;
36
37/// Instantiate a [`Mac`] algorithm.
38pub trait NewMac: Sized {
39    /// Key size in bytes with which cipher guaranteed to be initialized.
40    type KeySize: ArrayLength<u8>;
41
42    /// Initialize new MAC instance from key with fixed size.
43    fn new(key: &Key<Self>) -> Self;
44
45    /// Initialize new MAC instance from key with variable size.
46    ///
47    /// Default implementation will accept only keys with length equal to
48    /// `KeySize`, but some MACs can accept range of key lengths.
49    fn new_from_slice(key: &[u8]) -> Result<Self, InvalidKeyLength> {
50        if key.len() != Self::KeySize::to_usize() {
51            Err(InvalidKeyLength)
52        } else {
53            Ok(Self::new(GenericArray::from_slice(key)))
54        }
55    }
56}
57
58/// The [`Mac`] trait defines methods for a Message Authentication algorithm.
59pub trait Mac: Clone {
60    /// Output size of the [[`Mac`]]
61    type OutputSize: ArrayLength<u8>;
62
63    /// Update MAC state with the given data.
64    fn update(&mut self, data: &[u8]);
65
66    /// Reset [`Mac`] instance.
67    fn reset(&mut self);
68
69    /// Obtain the result of a [`Mac`] computation as a [`Output`] and consume
70    /// [`Mac`] instance.
71    fn finalize(self) -> Output<Self>;
72
73    /// Obtain the result of a [`Mac`] computation as a [`Output`] and reset
74    /// [`Mac`] instance.
75    fn finalize_reset(&mut self) -> Output<Self> {
76        let res = self.clone().finalize();
77        self.reset();
78        res
79    }
80
81    /// Check if tag/code value is correct for the processed input.
82    fn verify(self, tag: &[u8]) -> Result<(), MacError> {
83        let choice = self.finalize().bytes.ct_eq(tag);
84
85        if choice.unwrap_u8() == 1 {
86            Ok(())
87        } else {
88            Err(MacError)
89        }
90    }
91}
92
93/// [`Output`] is a thin wrapper around bytes array which provides a safe `Eq`
94/// implementation that runs in a fixed time.
95#[derive(Clone)]
96pub struct Output<M: Mac> {
97    bytes: GenericArray<u8, M::OutputSize>,
98}
99
100impl<M: Mac> Output<M> {
101    /// Create a new MAC [`Output`].
102    pub fn new(bytes: GenericArray<u8, M::OutputSize>) -> Output<M> {
103        Output { bytes }
104    }
105
106    /// Get the MAC tag/code value as a byte array.
107    ///
108    /// Be very careful using this method, since incorrect use of the tag value
109    /// may permit timing attacks which defeat the security provided by the
110    /// [`Mac`] trait.
111    pub fn into_bytes(self) -> GenericArray<u8, M::OutputSize> {
112        self.bytes
113    }
114}
115
116impl<M: Mac> ConstantTimeEq for Output<M> {
117    fn ct_eq(&self, other: &Self) -> Choice {
118        self.bytes.ct_eq(&other.bytes)
119    }
120}
121
122impl<M: Mac> PartialEq for Output<M> {
123    fn eq(&self, x: &Output<M>) -> bool {
124        self.ct_eq(x).unwrap_u8() == 1
125    }
126}
127
128impl<M: Mac> Eq for Output<M> {}
129
130#[cfg(feature = "cipher")]
131#[cfg_attr(docsrs, doc(cfg(feature = "cipher")))]
132/// Trait for MAC functions which can be created from block cipher.
133pub trait FromBlockCipher {
134    /// Block cipher type
135    type Cipher: BlockCipher;
136
137    /// Create new MAC isntance from provided block cipher.
138    fn from_cipher(cipher: Self::Cipher) -> Self;
139}
140
141#[cfg(feature = "cipher")]
142#[cfg_attr(docsrs, doc(cfg(feature = "cipher")))]
143impl<T> NewMac for T
144where
145    T: FromBlockCipher,
146    T::Cipher: NewBlockCipher,
147{
148    type KeySize = <<Self as FromBlockCipher>::Cipher as NewBlockCipher>::KeySize;
149
150    fn new(key: &Key<Self>) -> Self {
151        let cipher = <Self as FromBlockCipher>::Cipher::new(key);
152        Self::from_cipher(cipher)
153    }
154
155    fn new_from_slice(key: &[u8]) -> Result<Self, InvalidKeyLength> {
156        <Self as FromBlockCipher>::Cipher::new_from_slice(key)
157            .map_err(|_| InvalidKeyLength)
158            .map(Self::from_cipher)
159    }
160}