//! An implementation of the [MD5][1] cryptographic hash algorithm. //! //! # Usage //! //! ```rust //! use md5::{Md5, Digest}; //! use hex_literal::hex; //! //! // create a Md5 hasher instance //! let mut hasher = Md5::new(); //! //! // process input message //! hasher.update(b"hello world"); //! //! // acquire hash digest in the form of GenericArray, //! // which in this case is equivalent to [u8; 16] //! let result = hasher.finalize(); //! assert_eq!(result[..], hex!("5eb63bbbe01eeed093cb22bb8f5acdc3")); //! ``` //! //! Also see [RustCrypto/hashes][2] readme. //! //! [1]: https://en.wikipedia.org/wiki/MD5 //! [2]: https://github.com/RustCrypto/hashes #![no_std] #![doc( html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" )] #![warn(missing_docs, rust_2018_idioms)] #[cfg(all(feature = "asm", any(target_arch = "x86", target_arch = "x86_64")))] extern crate md5_asm as compress; #[cfg(not(all(feature = "asm", any(target_arch = "x86", target_arch = "x86_64"))))] mod compress; pub use digest::{self, Digest}; use compress::compress; use core::{fmt, slice::from_ref}; #[cfg(feature = "oid")] use digest::const_oid::{AssociatedOid, ObjectIdentifier}; use digest::{ block_buffer::Eager, core_api::{ AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, CoreWrapper, FixedOutputCore, OutputSizeUser, Reset, UpdateCore, }, typenum::{Unsigned, U16, U64}, HashMarker, Output, }; /// Core MD5 hasher state. #[derive(Clone)] pub struct Md5Core { block_len: u64, state: [u32; 4], } impl HashMarker for Md5Core {} impl BlockSizeUser for Md5Core { type BlockSize = U64; } impl BufferKindUser for Md5Core { type BufferKind = Eager; } impl OutputSizeUser for Md5Core { type OutputSize = U16; } impl UpdateCore for Md5Core { #[inline] fn update_blocks(&mut self, blocks: &[Block]) { self.block_len = self.block_len.wrapping_add(blocks.len() as u64); compress(&mut self.state, convert(blocks)) } } impl FixedOutputCore for Md5Core { #[inline] fn finalize_fixed_core(&mut self, buffer: &mut Buffer, out: &mut Output) { let bit_len = self .block_len .wrapping_mul(Self::BlockSize::U64) .wrapping_add(buffer.get_pos() as u64) .wrapping_mul(8); let mut s = self.state; buffer.len64_padding_le(bit_len, |b| compress(&mut s, convert(from_ref(b)))); for (chunk, v) in out.chunks_exact_mut(4).zip(s.iter()) { chunk.copy_from_slice(&v.to_le_bytes()); } } } impl Default for Md5Core { #[inline] fn default() -> Self { Self { block_len: 0, state: [0x6745_2301, 0xEFCD_AB89, 0x98BA_DCFE, 0x1032_5476], } } } impl Reset for Md5Core { #[inline] fn reset(&mut self) { *self = Default::default(); } } impl AlgorithmName for Md5Core { fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("Md5") } } impl fmt::Debug for Md5Core { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("Md5Core { ... }") } } #[cfg(feature = "oid")] #[cfg_attr(docsrs, doc(cfg(feature = "oid")))] impl AssociatedOid for Md5Core { const OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.2.5"); } /// MD5 hasher state. pub type Md5 = CoreWrapper; const BLOCK_SIZE: usize = ::BlockSize::USIZE; #[inline(always)] fn convert(blocks: &[Block]) -> &[[u8; BLOCK_SIZE]] { // SAFETY: GenericArray and [u8; 64] have // exactly the same memory layout let p = blocks.as_ptr() as *const [u8; BLOCK_SIZE]; unsafe { core::slice::from_raw_parts(p, blocks.len()) } }