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