1#![no_std]
2#![doc = include_str!("../README.md")]
3#![doc(
4 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg",
5 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/26acc39f/logo.svg"
6)]
7#![forbid(unsafe_code)]
8#![cfg_attr(docsrs, feature(doc_cfg))]
9#![warn(missing_docs, rust_2018_idioms)]
10
11pub use digest::{self, Mac};
12
13use belt_block::BeltBlock;
14use cipher::{BlockBackend, BlockCipher, BlockClosure, BlockEncryptMut};
15use core::fmt;
16use digest::{
17 block_buffer::Lazy,
18 core_api::{
19 AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, CoreWrapper, FixedOutputCore,
20 UpdateCore,
21 },
22 crypto_common::{InnerInit, InnerUser},
23 generic_array::{
24 typenum::{IsLess, Le, NonZero, U256},
25 ArrayLength, GenericArray,
26 },
27 MacMarker, Output, OutputSizeUser, Reset,
28};
29
30#[cfg(feature = "zeroize")]
31use cipher::zeroize::{Zeroize, ZeroizeOnDrop};
32
33pub type BeltMac<C = BeltBlock> = CoreWrapper<BeltMacCore<C>>;
35
36#[derive(Clone)]
37pub struct BeltMacCore<C = BeltBlock>
39where
40 C: BlockCipher + BlockEncryptMut + Clone,
41{
42 cipher: C,
43 state: Block<C>,
44 r: Block<C>,
45}
46
47impl<C> BlockSizeUser for BeltMacCore<C>
48where
49 C: BlockCipher + BlockEncryptMut + Clone,
50{
51 type BlockSize = C::BlockSize;
52}
53
54impl<C> OutputSizeUser for BeltMacCore<C>
55where
56 C: BlockCipher + BlockEncryptMut + Clone,
57{
58 type OutputSize = C::BlockSize;
59}
60
61impl<C> InnerUser for BeltMacCore<C>
62where
63 C: BlockCipher + BlockEncryptMut + Clone,
64{
65 type Inner = C;
66}
67
68impl<C> MacMarker for BeltMacCore<C> where C: BlockCipher + BlockEncryptMut + Clone {}
69
70impl<C> InnerInit for BeltMacCore<C>
71where
72 C: BlockCipher + BlockEncryptMut + Clone,
73{
74 #[inline]
75 fn inner_init(mut cipher: C) -> Self {
76 let state = Default::default();
77 let mut r = Default::default();
78 cipher.encrypt_block_mut(&mut r);
79 Self { cipher, state, r }
80 }
81}
82
83impl<C> BufferKindUser for BeltMacCore<C>
84where
85 C: BlockCipher + BlockEncryptMut + Clone,
86{
87 type BufferKind = Lazy;
88}
89
90impl<C> UpdateCore for BeltMacCore<C>
91where
92 C: BlockCipher + BlockEncryptMut + Clone,
93{
94 #[inline]
95 fn update_blocks(&mut self, blocks: &[Block<Self>]) {
96 struct Ctx<'a, N: ArrayLength<u8>> {
97 state: &'a mut Block<Self>,
98 blocks: &'a [Block<Self>],
99 }
100
101 impl<'a, N: ArrayLength<u8>> BlockSizeUser for Ctx<'a, N> {
102 type BlockSize = N;
103 }
104
105 impl<'a, N: ArrayLength<u8>> BlockClosure for Ctx<'a, N> {
106 #[inline(always)]
107 fn call<B: BlockBackend<BlockSize = Self::BlockSize>>(self, backend: &mut B) {
108 for block in self.blocks {
109 xor(self.state, block);
110 backend.proc_block((self.state).into());
111 }
112 }
113 }
114
115 let Self { cipher, state, .. } = self;
116 cipher.encrypt_with_backend_mut(Ctx { state, blocks })
117 }
118}
119
120impl<C> Reset for BeltMacCore<C>
121where
122 C: BlockCipher + BlockEncryptMut + Clone,
123{
124 #[inline(always)]
125 fn reset(&mut self) {
126 self.state = Default::default();
127 }
128}
129
130impl<C> FixedOutputCore for BeltMacCore<C>
131where
132 C: BlockCipher + BlockEncryptMut + Clone,
133 C::BlockSize: IsLess<U256>,
134 Le<C::BlockSize, U256>: NonZero,
135{
136 #[inline]
137 fn finalize_fixed_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
138 let pos = buffer.get_pos();
139 let buf = buffer.pad_with_zeros();
140
141 let cipher = &mut self.cipher;
142 let r = &self.r;
143 let bs = r.len();
144 let mut new_r = Block::<C>::default();
145 if pos == bs {
146 let (h1, h2) = new_r.split_at_mut(bs - 4);
148 h1.copy_from_slice(&r[4..]);
149 for i in 0..4 {
150 h2[i] = r[i] ^ r[4 + i];
151 }
152 } else {
153 buf[pos] = 0x80;
154 let (h1, h2) = new_r.split_at_mut(4);
156 for i in 0..4 {
157 h1[i] = r[i] ^ r[bs - 4 + i];
158 }
159 h2.copy_from_slice(&r[..bs - 4]);
160 }
161
162 let mut state = self.state.clone();
163 xor(&mut state, buf);
164 xor(&mut state, &new_r);
165 cipher.encrypt_block_b2b_mut(&state, out);
166 }
167}
168
169impl<C> AlgorithmName for BeltMacCore<C>
170where
171 C: BlockCipher + BlockEncryptMut + Clone + AlgorithmName,
172{
173 fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
174 f.write_str("BeltMac<")?;
175 <C as AlgorithmName>::write_alg_name(f)?;
176 f.write_str(">")
177 }
178}
179
180impl<C> fmt::Debug for BeltMacCore<C>
181where
182 C: BlockCipher + BlockEncryptMut + Clone + AlgorithmName,
183{
184 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
185 f.write_str("BeltMacCore<")?;
186 <C as AlgorithmName>::write_alg_name(f)?;
187 f.write_str("> { ... }")
188 }
189}
190
191#[cfg(feature = "zeroize")]
192#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
193impl<C> Drop for BeltMacCore<C>
194where
195 C: BlockCipher + BlockEncryptMut + Clone,
196{
197 fn drop(&mut self) {
198 self.state.zeroize();
199 }
200}
201
202#[cfg(feature = "zeroize")]
203#[cfg_attr(docsrs, doc(cfg(feature = "zeroize")))]
204impl<C> ZeroizeOnDrop for BeltMacCore<C> where
205 C: BlockCipher + BlockEncryptMut + Clone + ZeroizeOnDrop
206{
207}
208
209#[inline(always)]
210fn xor<N: ArrayLength<u8>>(buf: &mut GenericArray<u8, N>, data: &GenericArray<u8, N>) {
211 for i in 0..N::USIZE {
212 buf[i] ^= data[i];
213 }
214}