1use cipher::{BlockCipherEncBackend, BlockCipherEncClosure, BlockCipherEncrypt};
2use core::fmt;
3use dbl::Dbl;
4use digest::{
5 MacMarker, Output, OutputSizeUser, Reset,
6 array::{Array, ArraySize},
7 block_api::{
8 AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, FixedOutputCore, Lazy,
9 SmallBlockSizeUser, UpdateCore,
10 },
11 block_buffer::BlockSizes,
12 common::{InnerInit, InnerUser},
13};
14
15#[cfg(feature = "zeroize")]
16use digest::zeroize::{Zeroize, ZeroizeOnDrop};
17
18#[derive(Clone)]
20pub struct CmacCore<C: CmacCipher> {
21 cipher: C,
22 state: Block<C>,
23}
24
25impl<C: CmacCipher> BlockSizeUser for CmacCore<C> {
26 type BlockSize = C::BlockSize;
27}
28
29impl<C: CmacCipher> OutputSizeUser for CmacCore<C> {
30 type OutputSize = C::BlockSize;
31}
32
33impl<C: CmacCipher> InnerUser for CmacCore<C> {
34 type Inner = C;
35}
36
37impl<C: CmacCipher> MacMarker for CmacCore<C> {}
38
39impl<C: CmacCipher> InnerInit for CmacCore<C> {
40 #[inline]
41 fn inner_init(cipher: C) -> Self {
42 let state = Default::default();
43 Self { cipher, state }
44 }
45}
46
47impl<C: CmacCipher> BufferKindUser for CmacCore<C> {
48 type BufferKind = Lazy;
49}
50
51impl<C: CmacCipher> UpdateCore for CmacCore<C> {
52 #[inline]
53 fn update_blocks(&mut self, blocks: &[Block<Self>]) {
54 struct Closure<'a, N: BlockSizes> {
55 state: &'a mut Block<Self>,
56 blocks: &'a [Block<Self>],
57 }
58
59 impl<N: BlockSizes> BlockSizeUser for Closure<'_, N> {
60 type BlockSize = N;
61 }
62
63 impl<N: BlockSizes> BlockCipherEncClosure for Closure<'_, N> {
64 #[inline(always)]
65 fn call<B: BlockCipherEncBackend<BlockSize = Self::BlockSize>>(self, backend: &B) {
66 for block in self.blocks {
67 xor(self.state, block);
68 backend.encrypt_block((self.state).into());
69 }
70 }
71 }
72
73 let Self { cipher, state } = self;
74 cipher.encrypt_with_backend(Closure { state, blocks });
75 }
76}
77
78impl<C: CmacCipher> Reset for CmacCore<C> {
79 #[inline(always)]
80 fn reset(&mut self) {
81 self.state = Default::default();
82 }
83}
84
85impl<C: CmacCipher> FixedOutputCore for CmacCore<C> {
86 #[inline]
87 fn finalize_fixed_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
88 let Self { state, cipher } = self;
89 let pos = buffer.get_pos();
90 let buf = buffer.pad_with_zeros();
91
92 let mut subkey = Default::default();
93 cipher.encrypt_block(&mut subkey);
94 let key1 = C::dbl(subkey);
95
96 xor(state, &buf);
97 if pos == buf.len() {
98 xor(state, &key1);
99 } else {
100 state[pos] ^= 0x80;
101 let key2 = C::dbl(key1);
102 xor(state, &key2);
103 }
104 cipher.encrypt_block(state);
105 out.copy_from_slice(state);
106 }
107}
108
109impl<C: CmacCipher + AlgorithmName> AlgorithmName for CmacCore<C> {
110 fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
111 f.write_str("Cmac<")?;
112 <C as AlgorithmName>::write_alg_name(f)?;
113 f.write_str(">")
114 }
115}
116
117impl<C: CmacCipher> fmt::Debug for CmacCore<C> {
118 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 f.write_str("CmacCore { ... }")
120 }
121}
122
123impl<C: CmacCipher> Drop for CmacCore<C> {
124 fn drop(&mut self) {
125 #[cfg(feature = "zeroize")]
126 {
127 self.state.zeroize();
128 }
129 }
130}
131
132#[cfg(feature = "zeroize")]
133impl<C: CmacCipher + ZeroizeOnDrop> ZeroizeOnDrop for CmacCore<C> {}
134
135#[inline(always)]
136fn xor<N: ArraySize>(buf: &mut Array<u8, N>, data: &Array<u8, N>) {
137 for i in 0..N::USIZE {
138 buf[i] ^= data[i];
139 }
140}
141
142pub trait CmacCipher: SmallBlockSizeUser + BlockCipherEncrypt {
144 fn dbl(block: Block<Self>) -> Block<Self>;
146}
147
148impl<C> CmacCipher for C
149where
150 Self: SmallBlockSizeUser + BlockCipherEncrypt,
151 Block<Self>: Dbl,
152{
153 fn dbl(block: Block<Self>) -> Block<Self> {
154 block.dbl()
155 }
156}