Skip to main content

md5/
block_api.rs

1use core::fmt;
2use digest::{
3    HashMarker, Output,
4    array::Array,
5    block_api::{
6        AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, Eager, FixedOutputCore,
7        OutputSizeUser, Reset, UpdateCore,
8    },
9    common::hazmat::{DeserializeStateError, SerializableState, SerializedState},
10    typenum::{U16, U24, U64, Unsigned},
11};
12
13pub use crate::compress::compress;
14use crate::consts;
15
16const STATE_LEN: usize = 4;
17
18/// Core MD5 hasher state.
19#[derive(Clone)]
20pub struct Md5Core {
21    block_len: u64,
22    state: [u32; STATE_LEN],
23}
24
25impl HashMarker for Md5Core {}
26
27impl BlockSizeUser for Md5Core {
28    type BlockSize = U64;
29}
30
31impl BufferKindUser for Md5Core {
32    type BufferKind = Eager;
33}
34
35impl OutputSizeUser for Md5Core {
36    type OutputSize = U16;
37}
38
39impl UpdateCore for Md5Core {
40    #[inline]
41    fn update_blocks(&mut self, blocks: &[Block<Self>]) {
42        self.block_len = self.block_len.wrapping_add(blocks.len() as u64);
43        let blocks = Array::cast_slice_to_core(blocks);
44        compress(&mut self.state, blocks)
45    }
46}
47
48impl FixedOutputCore for Md5Core {
49    #[inline]
50    fn finalize_fixed_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
51        let bit_len = self
52            .block_len
53            .wrapping_mul(Self::BlockSize::U64)
54            .wrapping_add(buffer.get_pos() as u64)
55            .wrapping_mul(8);
56        let mut s = self.state;
57        buffer.len64_padding_le(bit_len, |b| compress(&mut s, &[b.0]));
58        for (chunk, v) in out.chunks_exact_mut(4).zip(s.iter()) {
59            chunk.copy_from_slice(&v.to_le_bytes());
60        }
61    }
62}
63
64impl Default for Md5Core {
65    #[inline]
66    fn default() -> Self {
67        Self {
68            block_len: 0,
69            state: consts::STATE_INIT,
70        }
71    }
72}
73
74impl Reset for Md5Core {
75    #[inline]
76    fn reset(&mut self) {
77        *self = Default::default();
78    }
79}
80
81impl AlgorithmName for Md5Core {
82    fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
83        f.write_str("Md5")
84    }
85}
86
87impl fmt::Debug for Md5Core {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        f.write_str("Md5Core { ... }")
90    }
91}
92
93impl Drop for Md5Core {
94    fn drop(&mut self) {
95        #[cfg(feature = "zeroize")]
96        {
97            use digest::zeroize::Zeroize;
98            self.state.zeroize();
99            self.block_len.zeroize();
100        }
101    }
102}
103
104#[cfg(feature = "zeroize")]
105impl digest::zeroize::ZeroizeOnDrop for Md5Core {}
106
107impl SerializableState for Md5Core {
108    type SerializedStateSize = U24;
109
110    fn serialize(&self) -> SerializedState<Self> {
111        let mut serialized_state = SerializedState::<Self>::default();
112
113        for (val, chunk) in self.state.iter().zip(serialized_state.chunks_exact_mut(4)) {
114            chunk.copy_from_slice(&val.to_le_bytes());
115        }
116
117        serialized_state[16..].copy_from_slice(&self.block_len.to_le_bytes());
118        serialized_state
119    }
120
121    fn deserialize(
122        serialized_state: &SerializedState<Self>,
123    ) -> Result<Self, DeserializeStateError> {
124        let (serialized_state, serialized_block_len) = serialized_state.split::<U16>();
125
126        let mut state = [0; STATE_LEN];
127        for (val, chunk) in state.iter_mut().zip(serialized_state.chunks_exact(4)) {
128            *val = u32::from_le_bytes(chunk.try_into().unwrap());
129        }
130
131        let block_len = u64::from_le_bytes(*serialized_block_len.as_ref());
132
133        Ok(Self { state, block_len })
134    }
135}