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(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/// The MD5 hasher
52#[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        // Unlike Sha1 and Sha2, the length value in MD5 is defined as
95        // the length of the message mod 2^64 - ie: integer overflow is OK.
96        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);