From 514c5542652b447857223ab645ee0b3c5260d374 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Thu, 14 May 2015 16:29:34 -0400 Subject: md4 implementation --- src/lib.rs | 6 ++ src/md4.rs | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 211 insertions(+) create mode 100644 src/md4.rs diff --git a/src/lib.rs b/src/lib.rs index 54321fe..ec1dc61 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,7 @@ mod base64; mod crack; mod data; mod http; +mod md4; mod primitives; mod random; mod sha1; @@ -21,6 +22,11 @@ pub use aes::aes_128_ctr_with_counter; pub use base64::to_base64; pub use http::parse_query_string; pub use http::create_query_string; +pub use md4::md4; +pub use md4::pad_md4; +pub use md4::md4_padding; +pub use md4::md4_with_state; +pub use md4::md4_mac; pub use primitives::fixed_xor; pub use primitives::pad_pkcs7; pub use primitives::unpad_pkcs7; diff --git a/src/md4.rs b/src/md4.rs new file mode 100644 index 0000000..4fd9121 --- /dev/null +++ b/src/md4.rs @@ -0,0 +1,205 @@ +#[cfg(test)] use serialize::hex::ToHex; + +pub fn md4 (bytes: &[u8]) -> [u8; 16] { + md4_with_state( + bytes, + [ + 0x67452301, + 0xEFCDAB89, + 0x98BADCFE, + 0x10325476, + ], + bytes.len() as u64 + ) +} + +pub fn pad_md4 (bytes: &[u8], len: u64) -> Vec { + return bytes + .iter() + .map(|x| *x) + .chain(md4_padding(len)) + .collect(); +} + +pub fn md4_padding (len: u64) -> Vec { + let ml: u64 = len * 8; + let ml_bytes: [u8; 8] = unsafe { + ::std::mem::transmute(ml.to_le()) + }; + return [0x80u8] + .iter() + .map(|x| *x) + .chain(::std::iter::repeat(0x00).take((119 - (len % 64) as usize) % 64)) + .chain(ml_bytes.iter().map(|x| *x)) + .collect(); +} + +fn round1 (offset: u32, x: u32, s: u32, h: &mut [u32; 4]) { + let a = (4 - offset as usize) % 4; + let b = (5 - offset as usize) % 4; + let c = (6 - offset as usize) % 4; + let d = (7 - offset as usize) % 4; + + h[a] = h[a] + .wrapping_add((h[b] & h[c]) | (!h[b] & h[d])) + .wrapping_add(x) + .rotate_left(s) +} + +fn round2 (offset: u32, x: u32, s: u32, h: &mut [u32; 4]) { + let a = (4 - offset as usize) % 4; + let b = (5 - offset as usize) % 4; + let c = (6 - offset as usize) % 4; + let d = (7 - offset as usize) % 4; + + h[a] = h[a] + .wrapping_add((h[b] & h[c]) | (h[b] & h[d]) | (h[c] & h[d])) + .wrapping_add(x) + .wrapping_add(0x5A827999) + .rotate_left(s) +} + +fn round3 (offset: u32, x: u32, s: u32, h: &mut [u32; 4]) { + let a = (4 - offset as usize) % 4; + let b = (5 - offset as usize) % 4; + let c = (6 - offset as usize) % 4; + let d = (7 - offset as usize) % 4; + + h[a] = h[a] + .wrapping_add(h[b] ^ h[c] ^ h[d]) + .wrapping_add(x) + .wrapping_add(0x6ED9EBA1) + .rotate_left(s) +} + +pub fn md4_with_state (bytes: &[u8], mut h: [u32; 4], len: u64) -> [u8; 16] { + for chunk in pad_md4(bytes, len).chunks(64) { + let chunk_words: &[u32; 16] = unsafe { + ::std::mem::transmute(chunk.as_ptr()) + }; + let mut x: [u32; 16] = unsafe { ::std::mem::uninitialized() }; + for i in 0..16 { + x[i] = u32::from_le(chunk_words[i]); + } + + let mut hh = h; + + round1(0, x[ 0], 3, &mut hh); + round1(1, x[ 1], 7, &mut hh); + round1(2, x[ 2], 11, &mut hh); + round1(3, x[ 3], 19, &mut hh); + round1(0, x[ 4], 3, &mut hh); + round1(1, x[ 5], 7, &mut hh); + round1(2, x[ 6], 11, &mut hh); + round1(3, x[ 7], 19, &mut hh); + round1(0, x[ 8], 3, &mut hh); + round1(1, x[ 9], 7, &mut hh); + round1(2, x[10], 11, &mut hh); + round1(3, x[11], 19, &mut hh); + round1(0, x[12], 3, &mut hh); + round1(1, x[13], 7, &mut hh); + round1(2, x[14], 11, &mut hh); + round1(3, x[15], 19, &mut hh); + + round2(0, x[ 0], 3, &mut hh); + round2(1, x[ 4], 5, &mut hh); + round2(2, x[ 8], 9, &mut hh); + round2(3, x[12], 13, &mut hh); + round2(0, x[ 1], 3, &mut hh); + round2(1, x[ 5], 5, &mut hh); + round2(2, x[ 9], 9, &mut hh); + round2(3, x[13], 13, &mut hh); + round2(0, x[ 2], 3, &mut hh); + round2(1, x[ 6], 5, &mut hh); + round2(2, x[10], 9, &mut hh); + round2(3, x[14], 13, &mut hh); + round2(0, x[ 3], 3, &mut hh); + round2(1, x[ 7], 5, &mut hh); + round2(2, x[11], 9, &mut hh); + round2(3, x[15], 13, &mut hh); + + round3(0, x[ 0], 3, &mut hh); + round3(1, x[ 8], 9, &mut hh); + round3(2, x[ 4], 11, &mut hh); + round3(3, x[12], 15, &mut hh); + round3(0, x[ 2], 3, &mut hh); + round3(1, x[10], 9, &mut hh); + round3(2, x[ 6], 11, &mut hh); + round3(3, x[14], 15, &mut hh); + round3(0, x[ 1], 3, &mut hh); + round3(1, x[ 9], 9, &mut hh); + round3(2, x[ 5], 11, &mut hh); + round3(3, x[13], 15, &mut hh); + round3(0, x[ 3], 3, &mut hh); + round3(1, x[11], 9, &mut hh); + round3(2, x[ 7], 11, &mut hh); + round3(3, x[15], 15, &mut hh); + + h[0] = h[0].wrapping_add(hh[0]); + h[1] = h[1].wrapping_add(hh[1]); + h[2] = h[2].wrapping_add(hh[2]); + h[3] = h[3].wrapping_add(hh[3]); + } + + for word in h.iter_mut() { + *word = word.to_le(); + } + + return unsafe { ::std::mem::transmute(h) }; +} + +pub fn md4_mac (bytes: &[u8], key: &[u8]) -> [u8; 16] { + let full_bytes: Vec = key + .iter() + .chain(bytes.iter()) + .map(|x| *x) + .collect(); + return md4(&full_bytes[..]); +} + +#[test] +fn test_md4 () { + let tests = [ + ( + &b""[..], + "31d6cfe0d16ae931b73c59d7e0c089c0" + ), + ( + &b"The quick brown fox jumps over the lazy dog"[..], + "1bee69a46ba811185c194762abaeae90" + ), + ( + &b"The quick brown fox jumps over the lazy cog"[..], + "b86e130ce7028da59e672d56ad0113df" + ), + ( + &b"a"[..], + "bde52cb31de33e46245e05fbdbd6fb24" + ), + ( + &b"abc"[..], + "a448017aaf21d8525fc10ae87aa6729d" + ), + ( + &b"message digest"[..], + "d9130a8164549fe818874806e1c7014b" + ), + ( + &b"abcdefghijklmnopqrstuvwxyz"[..], + "d79e1c308aa5bbcdeea8ed63df412da9" + ), + ( + &b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"[..], + "043f8582f241db351ce627e153e7f0e4" + ), + ( + &b"12345678901234567890123456789012345678901234567890123456789012345678901234567890"[..], + "e33b4ddc9c38f2199c3e7b164fcc0536" + ), + ]; + for &(input, expected) in tests.iter() { + println!("{:?}", input); + let got = &md4(input)[..].to_hex(); + assert_eq!(got, expected); + } +} -- cgit v1.2.3-54-g00ecf