cbc_mac/
lib.rs

1//! [Cipher Block Chaining Message Authentication Code (CBC-MAC)][CBC-MAC]
2//! implemented in pure Rust and generic over block cipher.
3//!
4//! **WARNING!** The algorithm has known weaknesses in case of variable-length
5//! messages. See the linked Wikipedia article for more information.
6//!
7//! # Examples
8//!
9//! ```
10//! use cbc_mac::{CbcMac, Mac};
11//! use des::Des;
12//! use hex_literal::hex;
13//!
14//! // CBC-MAC with the DES block cipher is equivalent to DAA
15//! type Daa = CbcMac<Des>;
16//!
17//! // test from FIPS 113
18//! let key = hex!("0123456789ABCDEF");
19//! let mut mac = Daa::new_from_slice(&key).unwrap();
20//! mac.update(b"7654321 Now is the time for ");
21//! let correct = hex!("F1D30F6849312CA4");
22//! mac.verify_slice(&correct).unwrap();
23//! ```
24//!
25//! [CBC-MAC]: https://en.wikipedia.org/wiki/CBC-MAC#Security_with_fixed_and_variable-length_messages
26
27#![no_std]
28#![doc(
29    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg",
30    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg",
31    html_root_url = "https://docs.rs/cbc-mac/0.1.1"
32)]
33#![deny(unsafe_code)]
34#![cfg_attr(docsrs, feature(doc_cfg))]
35#![warn(missing_docs, rust_2018_idioms)]
36
37pub use digest::{self, Mac};
38
39use cipher::{BlockBackend, BlockCipher, BlockClosure, BlockEncryptMut};
40use core::fmt;
41use digest::{
42    block_buffer::Eager,
43    core_api::{
44        AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, CoreWrapper, FixedOutputCore,
45        UpdateCore,
46    },
47    crypto_common::{InnerInit, InnerUser},
48    generic_array::{
49        typenum::{IsLess, Le, NonZero, U256},
50        ArrayLength, GenericArray,
51    },
52    MacMarker, Output, OutputSizeUser, Reset,
53};
54
55#[cfg(feature = "zeroize")]
56use cipher::zeroize::{Zeroize, ZeroizeOnDrop};
57
58/// Generic CMAC instance.
59pub type CbcMac<C> = CoreWrapper<CbcMacCore<C>>;
60
61/// Generic core CMAC instance, which operates over blocks.
62#[derive(Clone)]
63pub struct CbcMacCore<C>
64where
65    C: BlockCipher + BlockEncryptMut + Clone,
66{
67    cipher: C,
68    state: Block<C>,
69}
70
71impl<C> BlockSizeUser for CbcMacCore<C>
72where
73    C: BlockCipher + BlockEncryptMut + Clone,
74{
75    type BlockSize = C::BlockSize;
76}
77
78impl<C> OutputSizeUser for CbcMacCore<C>
79where
80    C: BlockCipher + BlockEncryptMut + Clone,
81{
82    type OutputSize = C::BlockSize;
83}
84
85impl<C> InnerUser for CbcMacCore<C>
86where
87    C: BlockCipher + BlockEncryptMut + Clone,
88{
89    type Inner = C;
90}
91
92impl<C> MacMarker for CbcMacCore<C> where C: BlockCipher + BlockEncryptMut + Clone {}
93
94impl<C> InnerInit for CbcMacCore<C>
95where
96    C: BlockCipher + BlockEncryptMut + Clone,
97{
98    #[inline]
99    fn inner_init(cipher: C) -> Self {
100        let state = Default::default();
101        Self { cipher, state }
102    }
103}
104
105impl<C> BufferKindUser for CbcMacCore<C>
106where
107    C: BlockCipher + BlockEncryptMut + Clone,
108{
109    type BufferKind = Eager;
110}
111
112impl<C> UpdateCore for CbcMacCore<C>
113where
114    C: BlockCipher + BlockEncryptMut + Clone,
115{
116    #[inline]
117    fn update_blocks(&mut self, blocks: &[Block<Self>]) {
118        struct Ctx<'a, N: ArrayLength<u8>> {
119            state: &'a mut Block<Self>,
120            blocks: &'a [Block<Self>],
121        }
122
123        impl<'a, N: ArrayLength<u8>> BlockSizeUser for Ctx<'a, N> {
124            type BlockSize = N;
125        }
126
127        impl<'a, N: ArrayLength<u8>> BlockClosure for Ctx<'a, N> {
128            #[inline(always)]
129            fn call<B: BlockBackend<BlockSize = Self::BlockSize>>(self, backend: &mut B) {
130                for block in self.blocks {
131                    xor(self.state, block);
132                    backend.proc_block((self.state).into());
133                }
134            }
135        }
136
137        let Self { cipher, state } = self;
138        cipher.encrypt_with_backend_mut(Ctx { state, blocks })
139    }
140}
141
142impl<C> Reset for CbcMacCore<C>
143where
144    C: BlockCipher + BlockEncryptMut + Clone,
145{
146    #[inline(always)]
147    fn reset(&mut self) {
148        self.state = Default::default();
149    }
150}
151
152impl<C> FixedOutputCore for CbcMacCore<C>
153where
154    C: BlockCipher + BlockEncryptMut + Clone,
155    C::BlockSize: IsLess<U256>,
156    Le<C::BlockSize, U256>: NonZero,
157{
158    #[inline]
159    fn finalize_fixed_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
160        let Self { state, cipher } = self;
161        let pos = buffer.get_pos();
162        if pos != 0 {
163            xor(state, buffer.pad_with_zeros());
164            cipher.encrypt_block_mut(state);
165        }
166        out.copy_from_slice(state);
167    }
168}
169
170impl<C> AlgorithmName for CbcMacCore<C>
171where
172    C: BlockCipher + BlockEncryptMut + Clone + AlgorithmName,
173{
174    fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
175        f.write_str("CbcMac<")?;
176        <C as AlgorithmName>::write_alg_name(f)?;
177        f.write_str(">")
178    }
179}
180
181impl<C> fmt::Debug for CbcMacCore<C>
182where
183    C: BlockCipher + BlockEncryptMut + Clone + AlgorithmName,
184{
185    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
186        f.write_str("CbcMacCore<")?;
187        <C as AlgorithmName>::write_alg_name(f)?;
188        f.write_str("> { ... }")
189    }
190}
191
192#[cfg(feature = "zeroize")]
193#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
194impl<C> Drop for CbcMacCore<C>
195where
196    C: BlockCipher + BlockEncryptMut + Clone,
197{
198    fn drop(&mut self) {
199        self.state.zeroize();
200    }
201}
202
203#[cfg(feature = "zeroize")]
204#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
205impl<C> ZeroizeOnDrop for CbcMacCore<C> where
206    C: BlockCipher + BlockEncryptMut + Clone + ZeroizeOnDrop
207{
208}
209
210#[inline(always)]
211fn xor<N: ArrayLength<u8>>(buf: &mut GenericArray<u8, N>, data: &GenericArray<u8, N>) {
212    for i in 0..N::USIZE {
213        buf[i] ^= data[i];
214    }
215}