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
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/// Core MD5 hasher state.
56#[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
135/// MD5 hasher state.
136pub 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    // SAFETY: GenericArray<u8, U64> and [u8; 64] have
143    // exactly the same memory layout
144    let p = blocks.as_ptr() as *const [u8; BLOCK_SIZE];
145    unsafe { core::slice::from_raw_parts(p, blocks.len()) }
146}