md5/
lib.rs

1//! The [MD5] hash function.
2//!
3//! ## Example
4//!
5//! ```
6//! let digest = md5::compute(b"abcdefghijklmnopqrstuvwxyz");
7//! assert_eq!(format!("{:x}", digest), "c3fcd3d76192e4007dfb496cca67e13b");
8//! ```
9//!
10//! ## Security Warning
11//!
12//! The package is provided for the purposes of interoperability with protocols
13//! and systems that mandate the use of MD5. However, MD5 should be considered
14//! [cryptographically broken and unsuitable for further use][VU836068].
15//! Collision attacks against MD5 are both practical and trivial, and
16//! [theoretical attacks against MD5 have been found][ACM1724151].
17//!
18//! [RFC6151] advises no new protocols to be designed with any MD5-based
19//! constructions, including HMAC-MD5.
20//!
21//! [MD5]: https://en.wikipedia.org/wiki/MD5
22//!
23//! [ACM1724151]: https://dl.acm.org/citation.cfm?id=1724151
24//! [RFC6151]: https://tools.ietf.org/html/rfc6151
25//! [VU836068]: https://www.kb.cert.org/vuls/id/836068
26
27// The implementation is based on:
28// https://www.ietf.org/rfc/rfc1321.txt
29
30#![cfg_attr(not(feature = "std"), no_std)]
31
32#[cfg(feature = "std")]
33use std as core;
34
35/// A digest.
36#[derive(Clone, Copy, Eq, Hash, PartialEq)]
37pub struct Digest(pub [u8; 16]);
38
39impl core::convert::From<Digest> for [u8; 16] {
40    #[inline]
41    fn from(digest: Digest) -> Self {
42        digest.0
43    }
44}
45
46impl core::fmt::Debug for Digest {
47    #[inline]
48    fn fmt(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
49        core::fmt::LowerHex::fmt(self, formatter)
50    }
51}
52
53impl core::ops::Deref for Digest {
54    type Target = [u8; 16];
55
56    #[inline]
57    fn deref(&self) -> &Self::Target {
58        &self.0
59    }
60}
61
62impl core::ops::DerefMut for Digest {
63    #[inline]
64    fn deref_mut(&mut self) -> &mut Self::Target {
65        &mut self.0
66    }
67}
68
69macro_rules! implement {
70    ($kind:ident, $format:expr) => {
71        impl core::fmt::$kind for Digest {
72            fn fmt(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
73                for value in &self.0 {
74                    write!(formatter, $format, value)?;
75                }
76                Ok(())
77            }
78        }
79    };
80}
81
82implement!(LowerHex, "{:02x}");
83implement!(UpperHex, "{:02X}");
84
85/// A context.
86#[derive(Clone)]
87pub struct Context {
88    buffer: [u8; 64],
89    count: u64,
90    state: [u32; 4],
91}
92
93const PADDING: [u8; 64] = [
94    0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
95    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
96    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
98];
99
100impl Context {
101    /// Create a context for computing a digest.
102    #[inline]
103    pub fn new() -> Context {
104        Context {
105            buffer: [0; 64],
106            count: 0,
107            state: [0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476],
108        }
109    }
110
111    /// Consume data.
112    #[inline]
113    pub fn consume<T: AsRef<[u8]>>(&mut self, data: T) {
114        consume(self, data.as_ref());
115    }
116
117    /// Finalize and return the digest.
118    #[rustfmt::skip]
119    #[allow(clippy::double_parens, clippy::needless_range_loop)]
120    pub fn finalize(mut self) -> Digest {
121        let mut input = [0u32; 16];
122        let k = ((self.count >> 3) & 0x3f) as usize;
123        input[14] = self.count as u32;
124        input[15] = (self.count >> 32) as u32;
125        consume(
126            &mut self,
127            &PADDING[..(if k < 56 { 56 - k } else { 120 - k })],
128        );
129        let mut j = 0;
130        for i in 0..14 {
131            input[i] = ((self.buffer[j + 3] as u32) << 24) |
132                       ((self.buffer[j + 2] as u32) << 16) |
133                       ((self.buffer[j + 1] as u32) <<  8) |
134                       ((self.buffer[j    ] as u32)      );
135            j += 4;
136        }
137        transform(&mut self.state, &input);
138        let mut digest = [0u8; 16];
139        let mut j = 0;
140        for i in 0..4 {
141            digest[j    ] = ((self.state[i]      ) & 0xff) as u8;
142            digest[j + 1] = ((self.state[i] >>  8) & 0xff) as u8;
143            digest[j + 2] = ((self.state[i] >> 16) & 0xff) as u8;
144            digest[j + 3] = ((self.state[i] >> 24) & 0xff) as u8;
145            j += 4;
146        }
147        Digest(digest)
148    }
149
150    /// Finalize and return the digest.
151    #[deprecated(since = "0.8.0", note = "Use `finalize`.")]
152    #[inline]
153    pub fn compute(self) -> Digest {
154        self.finalize()
155    }
156}
157
158impl Default for Context {
159    #[inline]
160    fn default() -> Self {
161        Self::new()
162    }
163}
164
165impl core::convert::From<Context> for Digest {
166    #[inline]
167    fn from(context: Context) -> Digest {
168        context.finalize()
169    }
170}
171
172#[cfg(feature = "std")]
173impl core::io::Write for Context {
174    #[inline]
175    fn write(&mut self, data: &[u8]) -> core::io::Result<usize> {
176        self.consume(data);
177        Ok(data.len())
178    }
179
180    #[inline]
181    fn flush(&mut self) -> core::io::Result<()> {
182        Ok(())
183    }
184}
185
186/// Compute the digest of data.
187#[inline]
188pub fn compute<T: AsRef<[u8]>>(data: T) -> Digest {
189    let mut context = Context::new();
190    context.consume(data);
191    context.finalize()
192}
193
194#[rustfmt::skip]
195#[allow(clippy::double_parens, clippy::needless_range_loop)]
196fn consume(
197    Context {
198        buffer,
199        count,
200        state,
201    }: &mut Context,
202    data: &[u8],
203) {
204    let mut input = [0u32; 16];
205    let mut k = ((*count >> 3) & 0x3f) as usize;
206    *count = count.wrapping_add((data.len() as u64) << 3);
207    for &value in data {
208        buffer[k] = value;
209        k += 1;
210        if k == 0x40 {
211            let mut j = 0;
212            for i in 0..16 {
213                input[i] = ((buffer[j + 3] as u32) << 24) |
214                           ((buffer[j + 2] as u32) << 16) |
215                           ((buffer[j + 1] as u32) <<  8) |
216                           ((buffer[j    ] as u32)      );
217                j += 4;
218            }
219            transform(state, &input);
220            k = 0;
221        }
222    }
223}
224
225#[rustfmt::skip]
226fn transform(state: &mut [u32; 4], input: &[u32; 16]) {
227    let (mut a, mut b, mut c, mut d) = (state[0], state[1], state[2], state[3]);
228    macro_rules! add(
229        ($a:expr, $b:expr) => ($a.wrapping_add($b));
230    );
231    macro_rules! rotate(
232        ($x:expr, $n:expr) => ($x.rotate_left($n));
233    );
234    {
235        macro_rules! F(
236            ($x:expr, $y:expr, $z:expr) => (($x & $y) | (!$x & $z));
237        );
238        macro_rules! T(
239            ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
240                $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
241                $a = rotate!($a, $s);
242                $a = add!($a, $b);
243            });
244        );
245        const S1: u32 =  7;
246        const S2: u32 = 12;
247        const S3: u32 = 17;
248        const S4: u32 = 22;
249        T!(a, b, c, d, input[ 0], S1, 3614090360);
250        T!(d, a, b, c, input[ 1], S2, 3905402710);
251        T!(c, d, a, b, input[ 2], S3,  606105819);
252        T!(b, c, d, a, input[ 3], S4, 3250441966);
253        T!(a, b, c, d, input[ 4], S1, 4118548399);
254        T!(d, a, b, c, input[ 5], S2, 1200080426);
255        T!(c, d, a, b, input[ 6], S3, 2821735955);
256        T!(b, c, d, a, input[ 7], S4, 4249261313);
257        T!(a, b, c, d, input[ 8], S1, 1770035416);
258        T!(d, a, b, c, input[ 9], S2, 2336552879);
259        T!(c, d, a, b, input[10], S3, 4294925233);
260        T!(b, c, d, a, input[11], S4, 2304563134);
261        T!(a, b, c, d, input[12], S1, 1804603682);
262        T!(d, a, b, c, input[13], S2, 4254626195);
263        T!(c, d, a, b, input[14], S3, 2792965006);
264        T!(b, c, d, a, input[15], S4, 1236535329);
265    }
266    {
267        macro_rules! F(
268            ($x:expr, $y:expr, $z:expr) => (($x & $z) | ($y & !$z));
269        );
270        macro_rules! T(
271            ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
272                $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
273                $a = rotate!($a, $s);
274                $a = add!($a, $b);
275            });
276        );
277        const S1: u32 =  5;
278        const S2: u32 =  9;
279        const S3: u32 = 14;
280        const S4: u32 = 20;
281        T!(a, b, c, d, input[ 1], S1, 4129170786);
282        T!(d, a, b, c, input[ 6], S2, 3225465664);
283        T!(c, d, a, b, input[11], S3,  643717713);
284        T!(b, c, d, a, input[ 0], S4, 3921069994);
285        T!(a, b, c, d, input[ 5], S1, 3593408605);
286        T!(d, a, b, c, input[10], S2,   38016083);
287        T!(c, d, a, b, input[15], S3, 3634488961);
288        T!(b, c, d, a, input[ 4], S4, 3889429448);
289        T!(a, b, c, d, input[ 9], S1,  568446438);
290        T!(d, a, b, c, input[14], S2, 3275163606);
291        T!(c, d, a, b, input[ 3], S3, 4107603335);
292        T!(b, c, d, a, input[ 8], S4, 1163531501);
293        T!(a, b, c, d, input[13], S1, 2850285829);
294        T!(d, a, b, c, input[ 2], S2, 4243563512);
295        T!(c, d, a, b, input[ 7], S3, 1735328473);
296        T!(b, c, d, a, input[12], S4, 2368359562);
297    }
298    {
299        macro_rules! F(
300            ($x:expr, $y:expr, $z:expr) => ($x ^ $y ^ $z);
301        );
302        macro_rules! T(
303            ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
304                $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
305                $a = rotate!($a, $s);
306                $a = add!($a, $b);
307            });
308        );
309        const S1: u32 =  4;
310        const S2: u32 = 11;
311        const S3: u32 = 16;
312        const S4: u32 = 23;
313        T!(a, b, c, d, input[ 5], S1, 4294588738);
314        T!(d, a, b, c, input[ 8], S2, 2272392833);
315        T!(c, d, a, b, input[11], S3, 1839030562);
316        T!(b, c, d, a, input[14], S4, 4259657740);
317        T!(a, b, c, d, input[ 1], S1, 2763975236);
318        T!(d, a, b, c, input[ 4], S2, 1272893353);
319        T!(c, d, a, b, input[ 7], S3, 4139469664);
320        T!(b, c, d, a, input[10], S4, 3200236656);
321        T!(a, b, c, d, input[13], S1,  681279174);
322        T!(d, a, b, c, input[ 0], S2, 3936430074);
323        T!(c, d, a, b, input[ 3], S3, 3572445317);
324        T!(b, c, d, a, input[ 6], S4,   76029189);
325        T!(a, b, c, d, input[ 9], S1, 3654602809);
326        T!(d, a, b, c, input[12], S2, 3873151461);
327        T!(c, d, a, b, input[15], S3,  530742520);
328        T!(b, c, d, a, input[ 2], S4, 3299628645);
329    }
330    {
331        macro_rules! F(
332            ($x:expr, $y:expr, $z:expr) => ($y ^ ($x | !$z));
333        );
334        macro_rules! T(
335            ($a:expr, $b:expr, $c:expr, $d:expr, $x:expr, $s:expr, $ac:expr) => ({
336                $a = add!(add!(add!($a, F!($b, $c, $d)), $x), $ac);
337                $a = rotate!($a, $s);
338                $a = add!($a, $b);
339            });
340        );
341        const S1: u32 =  6;
342        const S2: u32 = 10;
343        const S3: u32 = 15;
344        const S4: u32 = 21;
345        T!(a, b, c, d, input[ 0], S1, 4096336452);
346        T!(d, a, b, c, input[ 7], S2, 1126891415);
347        T!(c, d, a, b, input[14], S3, 2878612391);
348        T!(b, c, d, a, input[ 5], S4, 4237533241);
349        T!(a, b, c, d, input[12], S1, 1700485571);
350        T!(d, a, b, c, input[ 3], S2, 2399980690);
351        T!(c, d, a, b, input[10], S3, 4293915773);
352        T!(b, c, d, a, input[ 1], S4, 2240044497);
353        T!(a, b, c, d, input[ 8], S1, 1873313359);
354        T!(d, a, b, c, input[15], S2, 4264355552);
355        T!(c, d, a, b, input[ 6], S3, 2734768916);
356        T!(b, c, d, a, input[13], S4, 1309151649);
357        T!(a, b, c, d, input[ 4], S1, 4149444226);
358        T!(d, a, b, c, input[11], S2, 3174756917);
359        T!(c, d, a, b, input[ 2], S3,  718787259);
360        T!(b, c, d, a, input[ 9], S4, 3951481745);
361    }
362    state[0] = add!(state[0], a);
363    state[1] = add!(state[1], b);
364    state[2] = add!(state[2], c);
365    state[3] = add!(state[3], d);
366}
367
368#[cfg(test)]
369mod tests {
370    use std::io::prelude::Write;
371
372    use super::Context;
373
374    #[test]
375    fn compute() {
376        let inputs = [
377            "",
378            "a",
379            "abc",
380            "message digest",
381            "abcdefghijklmnopqrstuvwxyz",
382            "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
383            "0123456789012345678901234567890123456789012345678901234567890123",
384            "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
385        ];
386        let outputs = [
387            "d41d8cd98f00b204e9800998ecf8427e",
388            "0cc175b9c0f1b6a831c399e269772661",
389            "900150983cd24fb0d6963f7d28e17f72",
390            "f96b697d7cb7938d525a2f31aaf161d0",
391            "c3fcd3d76192e4007dfb496cca67e13b",
392            "d174ab98d277d9f5a5611c2c9f419d9f",
393            "7f7bfd348709deeaace19e3f535f8c54",
394            "57edf4a22be3c955ac49da2e2107b67a",
395        ];
396        for (input, &output) in inputs.iter().zip(outputs.iter()) {
397            let digest = super::compute(input);
398            assert_eq!(format!("{digest:x}"), output);
399
400            let mut context = Context::new();
401            context.consume(input);
402            let digest = context.finalize();
403            assert_eq!(format!("{digest:x}"), output);
404        }
405    }
406
407    #[test]
408    fn index() {
409        let mut digest = super::compute(b"abc");
410        assert_eq!(digest[0], 0x90);
411        assert_eq!(&digest[0], &0x90);
412        assert_eq!(&mut digest[0], &mut 0x90);
413    }
414
415    #[test]
416    fn write_29() {
417        let data = vec![0; 8 * 1024 * 1024];
418        let mut context = Context::new();
419        for _ in 0..64 {
420            context.write(&data).unwrap();
421        }
422        assert_eq!(
423            format!("{:x}", context.finalize()),
424            "aa559b4e3523a6c931f08f4df52d58f2",
425        );
426    }
427
428    #[test]
429    fn write_32() {
430        let data = vec![0; std::u32::MAX as usize + 1];
431        let mut context = Context::new();
432        context.write(&data).unwrap();
433        assert_eq!(
434            format!("{:x}", context.finalize()),
435            "c9a5a6878d97b48cc965c1e41859f034",
436        );
437    }
438}