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