1#![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
58pub type CbcMac<C> = CoreWrapper<CbcMacCore<C>>;
60
61#[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}