1#![no_std]
27#![doc(
28 html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
29 html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
30)]
31#![warn(missing_docs, rust_2018_idioms)]
32
33#[cfg(all(feature = "asm", any(target_arch = "x86", target_arch = "x86_64")))]
34extern crate md5_asm as compress;
35
36#[cfg(not(all(feature = "asm", any(target_arch = "x86", target_arch = "x86_64"))))]
37mod compress;
38
39pub use digest::{self, Digest};
40
41use compress::compress;
42
43use core::{fmt, slice::from_ref};
44#[cfg(feature = "oid")]
45use digest::const_oid::{AssociatedOid, ObjectIdentifier};
46use digest::{
47 block_buffer::Eager,
48 core_api::{
49 AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, CoreWrapper, FixedOutputCore,
50 OutputSizeUser, Reset, UpdateCore,
51 },
52 typenum::{Unsigned, U16, U64},
53 HashMarker, Output,
54};
55#[derive(Clone)]
57pub struct Md5Core {
58 block_len: u64,
59 state: [u32; 4],
60}
61
62impl HashMarker for Md5Core {}
63
64impl BlockSizeUser for Md5Core {
65 type BlockSize = U64;
66}
67
68impl BufferKindUser for Md5Core {
69 type BufferKind = Eager;
70}
71
72impl OutputSizeUser for Md5Core {
73 type OutputSize = U16;
74}
75
76impl UpdateCore for Md5Core {
77 #[inline]
78 fn update_blocks(&mut self, blocks: &[Block<Self>]) {
79 self.block_len = self.block_len.wrapping_add(blocks.len() as u64);
80 compress(&mut self.state, convert(blocks))
81 }
82}
83
84impl FixedOutputCore for Md5Core {
85 #[inline]
86 fn finalize_fixed_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
87 let bit_len = self
88 .block_len
89 .wrapping_mul(Self::BlockSize::U64)
90 .wrapping_add(buffer.get_pos() as u64)
91 .wrapping_mul(8);
92 let mut s = self.state;
93 buffer.len64_padding_le(bit_len, |b| compress(&mut s, convert(from_ref(b))));
94 for (chunk, v) in out.chunks_exact_mut(4).zip(s.iter()) {
95 chunk.copy_from_slice(&v.to_le_bytes());
96 }
97 }
98}
99
100impl Default for Md5Core {
101 #[inline]
102 fn default() -> Self {
103 Self {
104 block_len: 0,
105 state: [0x6745_2301, 0xEFCD_AB89, 0x98BA_DCFE, 0x1032_5476],
106 }
107 }
108}
109
110impl Reset for Md5Core {
111 #[inline]
112 fn reset(&mut self) {
113 *self = Default::default();
114 }
115}
116
117impl AlgorithmName for Md5Core {
118 fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
119 f.write_str("Md5")
120 }
121}
122
123impl fmt::Debug for Md5Core {
124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125 f.write_str("Md5Core { ... }")
126 }
127}
128
129#[cfg(feature = "oid")]
130#[cfg_attr(docsrs, doc(cfg(feature = "oid")))]
131impl AssociatedOid for Md5Core {
132 const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.2.5");
133}
134
135pub type Md5 = CoreWrapper<Md5Core>;
137
138const BLOCK_SIZE: usize = <Md5Core as BlockSizeUser>::BlockSize::USIZE;
139
140#[inline(always)]
141fn convert(blocks: &[Block<Md5Core>]) -> &[[u8; BLOCK_SIZE]] {
142 let p = blocks.as_ptr() as *const [u8; BLOCK_SIZE];
145 unsafe { core::slice::from_raw_parts(p, blocks.len()) }
146}