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