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#[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}