1#![no_std]
43#![doc(
44 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg",
45 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg"
46)]
47#![forbid(unsafe_code)]
48#![cfg_attr(docsrs, feature(doc_cfg))]
49#![warn(missing_docs, rust_2018_idioms)]
50
51pub use digest::{self, Mac};
52
53use cipher::{BlockBackend, BlockCipher, BlockClosure, BlockEncryptMut};
54use core::fmt;
55use dbl::Dbl;
56use digest::{
57 block_buffer::Lazy,
58 core_api::{
59 AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, CoreWrapper, FixedOutputCore,
60 UpdateCore,
61 },
62 crypto_common::{InnerInit, InnerUser},
63 generic_array::{
64 typenum::{IsLess, Le, NonZero, U256},
65 ArrayLength, GenericArray,
66 },
67 MacMarker, Output, OutputSizeUser, Reset,
68};
69
70#[cfg(feature = "zeroize")]
71use cipher::zeroize::{Zeroize, ZeroizeOnDrop};
72
73pub type Cmac<C> = CoreWrapper<CmacCore<C>>;
75
76#[derive(Clone)]
78pub struct CmacCore<C>
79where
80 C: BlockCipher + BlockEncryptMut + Clone,
81 Block<C>: Dbl,
82{
83 cipher: C,
84 state: Block<C>,
85}
86
87impl<C> BlockSizeUser for CmacCore<C>
88where
89 C: BlockCipher + BlockEncryptMut + Clone,
90 Block<C>: Dbl,
91{
92 type BlockSize = C::BlockSize;
93}
94
95impl<C> OutputSizeUser for CmacCore<C>
96where
97 C: BlockCipher + BlockEncryptMut + Clone,
98 Block<C>: Dbl,
99{
100 type OutputSize = C::BlockSize;
101}
102
103impl<C> InnerUser for CmacCore<C>
104where
105 C: BlockCipher + BlockEncryptMut + Clone,
106 Block<C>: Dbl,
107{
108 type Inner = C;
109}
110
111impl<C> MacMarker for CmacCore<C>
112where
113 C: BlockCipher + BlockEncryptMut + Clone,
114 Block<C>: Dbl,
115{
116}
117
118impl<C> InnerInit for CmacCore<C>
119where
120 C: BlockCipher + BlockEncryptMut + Clone,
121 Block<C>: Dbl,
122{
123 #[inline]
124 fn inner_init(cipher: C) -> Self {
125 let state = Default::default();
126 Self { cipher, state }
127 }
128}
129
130impl<C> BufferKindUser for CmacCore<C>
131where
132 C: BlockCipher + BlockEncryptMut + Clone,
133 Block<C>: Dbl,
134{
135 type BufferKind = Lazy;
136}
137
138impl<C> UpdateCore for CmacCore<C>
139where
140 C: BlockCipher + BlockEncryptMut + Clone,
141 Block<C>: Dbl,
142{
143 #[inline]
144 fn update_blocks(&mut self, blocks: &[Block<Self>]) {
145 struct Ctx<'a, N: ArrayLength<u8>> {
146 state: &'a mut Block<Self>,
147 blocks: &'a [Block<Self>],
148 }
149
150 impl<'a, N: ArrayLength<u8>> BlockSizeUser for Ctx<'a, N> {
151 type BlockSize = N;
152 }
153
154 impl<'a, N: ArrayLength<u8>> BlockClosure for Ctx<'a, N> {
155 #[inline(always)]
156 fn call<B: BlockBackend<BlockSize = Self::BlockSize>>(self, backend: &mut B) {
157 for block in self.blocks {
158 xor(self.state, block);
159 backend.proc_block((self.state).into());
160 }
161 }
162 }
163
164 let Self { cipher, state } = self;
165 cipher.encrypt_with_backend_mut(Ctx { state, blocks })
166 }
167}
168
169impl<C> Reset for CmacCore<C>
170where
171 C: BlockCipher + BlockEncryptMut + Clone,
172 Block<C>: Dbl,
173{
174 #[inline(always)]
175 fn reset(&mut self) {
176 self.state = Default::default();
177 }
178}
179
180impl<C> FixedOutputCore for CmacCore<C>
181where
182 C: BlockCipher + BlockEncryptMut + Clone,
183 Block<C>: Dbl,
184 C::BlockSize: IsLess<U256>,
185 Le<C::BlockSize, U256>: NonZero,
186{
187 #[inline]
188 fn finalize_fixed_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
189 let Self { state, cipher } = self;
190 let pos = buffer.get_pos();
191 let buf = buffer.pad_with_zeros();
192
193 let mut subkey = Default::default();
194 cipher.encrypt_block_mut(&mut subkey);
195 let key1 = subkey.dbl();
196
197 xor(state, buf);
198 if pos == buf.len() {
199 xor(state, &key1);
200 } else {
201 state[pos] ^= 0x80;
202 let key2 = key1.dbl();
203 xor(state, &key2);
204 }
205 cipher.encrypt_block_mut(state);
206 out.copy_from_slice(state);
207 }
208}
209
210impl<C> AlgorithmName for CmacCore<C>
211where
212 C: BlockCipher + BlockEncryptMut + Clone + AlgorithmName,
213 Block<C>: Dbl,
214{
215 fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
216 f.write_str("Cmac<")?;
217 <C as AlgorithmName>::write_alg_name(f)?;
218 f.write_str(">")
219 }
220}
221
222impl<C> fmt::Debug for CmacCore<C>
223where
224 C: BlockCipher + BlockEncryptMut + Clone + AlgorithmName,
225 Block<C>: Dbl,
226{
227 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228 f.write_str("CmacCore<")?;
229 <C as AlgorithmName>::write_alg_name(f)?;
230 f.write_str("> { ... }")
231 }
232}
233
234#[cfg(feature = "zeroize")]
235#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
236impl<C> Drop for CmacCore<C>
237where
238 C: BlockCipher + BlockEncryptMut + Clone,
239 Block<C>: Dbl,
240{
241 fn drop(&mut self) {
242 self.state.zeroize();
243 }
244}
245
246#[cfg(feature = "zeroize")]
247#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
248impl<C> ZeroizeOnDrop for CmacCore<C>
249where
250 C: BlockCipher + BlockEncryptMut + Clone + ZeroizeOnDrop,
251 Block<C>: Dbl,
252{
253}
254
255#[inline(always)]
256fn xor<N: ArrayLength<u8>>(buf: &mut GenericArray<u8, N>, data: &GenericArray<u8, N>) {
257 for i in 0..N::USIZE {
258 buf[i] ^= data[i];
259 }
260}