Skip to main content

belt_mac/
block_api.rs

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/// Generic core Belt MAC instance, which operates over blocks.
18#[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            // phi1
126            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            // phi2
134            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}