md5/
lib.rs

1//! An implementation of the [MD5][1] cryptographic hash algorithm.
2//!
3//! # Usage
4//!
5//! ```rust
6//! use md5::{Md5, Digest};
7//! use hex_literal::hex;
8//!
9//! // create a Md5 hasher instance
10//! let mut hasher = Md5::new();
11//!
12//! // process input message
13//! hasher.update(b"hello world");
14//!
15//! // acquire hash digest in the form of GenericArray,
16//! // which in this case is equivalent to [u8; 16]
17//! let result = hasher.finalize();
18//! assert_eq!(result[..], hex!("5eb63bbbe01eeed093cb22bb8f5acdc3"));
19//! ```
20//!
21//! Also see [RustCrypto/hashes][2] readme.
22//!
23//! [1]: https://en.wikipedia.org/wiki/MD5
24//! [2]: https://github.com/RustCrypto/hashes
25
26#![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/// Core MD5 hasher state.
52#[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
133/// MD5 hasher state.
134pub 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    // SAFETY: GenericArray<u8, U64> and [u8; 64] have
141    // exactly the same memory layout
142    let p = blocks.as_ptr() as *const [u8; BLOCK_SIZE];
143    unsafe { core::slice::from_raw_parts(p, blocks.len()) }
144}