Skip to main content

cmac/
block_api.rs

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/// Generic core CMAC instance, which operates over blocks.
19#[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
142/// Helper trait implemented for cipher supported by CMAC
143pub trait CmacCipher: SmallBlockSizeUser + BlockCipherEncrypt {
144    /// Double block. See the [`Dbl`] trait docs for more information.
145    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}