1#![no_std]
27#![doc(html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")]
28#![deny(unsafe_code)]
29#![warn(missing_docs, rust_2018_idioms)]
30
31#[cfg(feature = "asm")]
32extern crate md5_asm as utils;
33
34#[cfg(feature = "std")]
35extern crate std;
36
37#[cfg(not(feature = "asm"))]
38mod utils;
39
40pub use digest::{self, Digest};
41
42use crate::utils::compress;
43
44use block_buffer::BlockBuffer;
45use digest::generic_array::typenum::{U16, U64};
46use digest::generic_array::GenericArray;
47use digest::{BlockInput, FixedOutputDirty, Reset, Update};
48
49mod consts;
50
51#[derive(Clone)]
53pub struct Md5 {
54 length_bytes: u64,
55 buffer: BlockBuffer<U64>,
56 state: [u32; 4],
57}
58
59impl Default for Md5 {
60 fn default() -> Self {
61 Md5 {
62 length_bytes: 0,
63 buffer: Default::default(),
64 state: consts::S0,
65 }
66 }
67}
68
69#[inline(always)]
70fn convert(d: &GenericArray<u8, U64>) -> &[u8; 64] {
71 #[allow(unsafe_code)]
72 unsafe {
73 &*(d.as_ptr() as *const [u8; 64])
74 }
75}
76
77impl Md5 {
78 #[inline]
79 fn finalize_inner(&mut self) {
80 let s = &mut self.state;
81 let l = (self.length_bytes << 3) as u64;
82 self.buffer.len64_padding_le(l, |d| compress(s, convert(d)));
83 }
84}
85
86impl BlockInput for Md5 {
87 type BlockSize = U64;
88}
89
90impl Update for Md5 {
91 #[inline]
92 fn update(&mut self, input: impl AsRef<[u8]>) {
93 let input = input.as_ref();
94 self.length_bytes = self.length_bytes.wrapping_add(input.len() as u64);
97 let s = &mut self.state;
98 self.buffer.input_block(input, |d| compress(s, convert(d)));
99 }
100}
101
102impl FixedOutputDirty for Md5 {
103 type OutputSize = U16;
104
105 #[inline]
106 fn finalize_into_dirty(&mut self, out: &mut GenericArray<u8, U16>) {
107 self.finalize_inner();
108 for (chunk, v) in out.chunks_exact_mut(4).zip(self.state.iter()) {
109 chunk.copy_from_slice(&v.to_le_bytes());
110 }
111 }
112}
113
114impl Reset for Md5 {
115 fn reset(&mut self) {
116 self.state = consts::S0;
117 self.length_bytes = 0;
118 self.buffer.reset();
119 }
120}
121
122opaque_debug::implement!(Md5);
123digest::impl_write!(Md5);