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