2022-09-16 12:07:57 +00:00
use crate ::hash ::{ bytes_to_words_le , md4 ::pad , words_to_bytes_le , Digest } ;
// based on RFC1321
const A : u32 = 0x67452301 ;
const B : u32 = 0xefcdab89 ;
const C : u32 = 0x98badcfe ;
const D : u32 = 0x10325476 ;
const K : [ u32 ; 64 ] = [
0xd76aa478 , 0xe8c7b756 , 0x242070db , 0xc1bdceee , 0xf57c0faf , 0x4787c62a , 0xa8304613 , 0xfd469501 ,
0x698098d8 , 0x8b44f7af , 0xffff5bb1 , 0x895cd7be , 0x6b901122 , 0xfd987193 , 0xa679438e , 0x49b40821 ,
0xf61e2562 , 0xc040b340 , 0x265e5a51 , 0xe9b6c7aa , 0xd62f105d , 0x02441453 , 0xd8a1e681 , 0xe7d3fbc8 ,
0x21e1cde6 , 0xc33707d6 , 0xf4d50d87 , 0x455a14ed , 0xa9e3e905 , 0xfcefa3f8 , 0x676f02d9 , 0x8d2a4c8a ,
0xfffa3942 , 0x8771f681 , 0x6d9d6122 , 0xfde5380c , 0xa4beea44 , 0x4bdecfa9 , 0xf6bb4b60 , 0xbebfbc70 ,
0x289b7ec6 , 0xeaa127fa , 0xd4ef3085 , 0x04881d05 , 0xd9d4d039 , 0xe6db99e5 , 0x1fa27cf8 , 0xc4ac5665 ,
0xf4292244 , 0x432aff97 , 0xab9423a7 , 0xfc93a039 , 0x655b59c3 , 0x8f0ccc92 , 0xffeff47d , 0x85845dd1 ,
0x6fa87e4f , 0xfe2ce6e0 , 0xa3014314 , 0x4e0811a1 , 0xf7537e82 , 0xbd3af235 , 0x2ad7d2bb , 0xeb86d391 ,
] ;
// shifts & indices for each step
const S : [ u32 ; 64 ] = [
7 , 12 , 17 , 22 , 7 , 12 , 17 , 22 , 7 , 12 , 17 , 22 , 7 , 12 , 17 , 22 , 5 , 9 , 14 , 20 , 5 , 9 , 14 , 20 , 5 , 9 ,
14 , 20 , 5 , 9 , 14 , 20 , 4 , 11 , 16 , 23 , 4 , 11 , 16 , 23 , 4 , 11 , 16 , 23 , 4 , 11 , 16 , 23 , 6 , 10 , 15 ,
21 , 6 , 10 , 15 , 21 , 6 , 10 , 15 , 21 , 6 , 10 , 15 , 21 ,
] ;
const W : [ usize ; 64 ] = [
0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 15 , 1 , 6 , 11 , 0 , 5 , 10 , 15 , 4 , 9 , 14 , 3 , 8 ,
13 , 2 , 7 , 12 , 5 , 8 , 11 , 14 , 1 , 4 , 7 , 10 , 13 , 0 , 3 , 6 , 9 , 12 , 15 , 2 , 0 , 7 , 14 , 5 , 12 , 3 , 10 , 1 ,
8 , 15 , 6 , 13 , 4 , 11 , 2 , 9 ,
] ;
// round functions
const F : fn ( u32 , u32 , u32 ) -> u32 = | x : u32 , y : u32 , z : u32 | ( x & y ) | ( ! x & z ) ;
const G : fn ( u32 , u32 , u32 ) -> u32 = | x : u32 , y : u32 , z : u32 | ( x & z ) | ( y & ! z ) ;
const H : fn ( u32 , u32 , u32 ) -> u32 = | x : u32 , y : u32 , z : u32 | x ^ y ^ z ;
const I : fn ( u32 , u32 , u32 ) -> u32 = | x : u32 , y : u32 , z : u32 | y ^ ( x | ! z ) ;
fn step ( [ mut a , b , c , d ] : [ u32 ; 4 ] , words : & [ u32 ] , index : usize ) -> [ u32 ; 4 ] {
2022-09-17 13:49:17 +00:00
let round_function = match index {
2022-09-16 12:07:57 +00:00
0 ..= 15 = > F ,
16 ..= 31 = > G ,
32 ..= 47 = > H ,
48 ..= 63 = > I ,
_ = > panic! ( " This function shouldn't be called using an index outside 0..48 " ) ,
} ;
2022-09-17 13:49:17 +00:00
a = round_function ( b , c , d )
2022-09-16 12:07:57 +00:00
. wrapping_add ( a )
. wrapping_add ( words [ W [ index ] ] )
. wrapping_add ( K [ index ] )
. rotate_left ( S [ index ] )
. wrapping_add ( b ) ;
[ a , b , c , d ]
}
2022-09-17 13:49:17 +00:00
/// Computes the MD5 digest of the input bytes.
///
/// Returns a `Digest<16>` which implements `Display` in order to get at hexadecimal-string representation.
///
2022-09-16 12:07:57 +00:00
/// # Examples
2022-09-17 13:49:17 +00:00
///
/// Basic usage:
///
2022-09-16 12:07:57 +00:00
/// ```
/// let input = "lol";
/// let digest = lore::md5(input);
///
/// assert_eq!(digest.to_string(), "9cdfb439c7876e703e307864c9167a15");
2022-09-17 13:49:17 +00:00
///
2022-09-16 12:07:57 +00:00
/// ```
pub fn hash ( message : impl AsRef < [ u8 ] > ) -> Digest < 16 > {
2022-09-19 11:03:47 +00:00
// the padding function for MD5 is exactly equivalent to the MD4 version, so we reuse it.
2022-09-16 12:07:57 +00:00
let padded = pad ( message ) ;
let buffer = padded . array_chunks ::< 64 > ( ) . map ( bytes_to_words_le ) . fold (
[ A , B , C , D ] ,
| [ a , b , c , d ] , words | {
2022-09-19 11:03:47 +00:00
// initialize state
2022-09-16 12:07:57 +00:00
let mut state = [ a , b , c , d ] ;
for i in 0 .. 64 {
state = step ( state , & words , i ) ;
println! ( " {state:08x?} " ) ;
state . rotate_right ( 1 ) ;
}
2022-09-19 11:03:47 +00:00
// add the computed state to the buffer
2022-09-16 12:07:57 +00:00
[
a . wrapping_add ( state [ 0 ] ) ,
b . wrapping_add ( state [ 1 ] ) ,
c . wrapping_add ( state [ 2 ] ) ,
d . wrapping_add ( state [ 3 ] ) ,
]
} ,
) ;
let digest = * words_to_bytes_le ( buffer )
. array_chunks ::< 16 > ( )
. next ( )
. unwrap ( ) ;
Digest ( digest )
}
#[ cfg(test) ]
mod tests {
use super ::* ;
#[ test ]
fn md5_hash ( ) {
assert_eq! ( " d41d8cd98f00b204e9800998ecf8427e " , hash ( " " ) . to_string ( ) ) ;
assert_eq! (
" 73e51861b65c1e83d6136fb6a002585e " ,
hash ( " tihi xd " ) . to_string ( )
) ;
assert_eq! ( " 9cdfb439c7876e703e307864c9167a15 " , hash ( " lol " ) . to_string ( ) ) ;
assert_eq! (
" fd6f92edff2b7db7cd92b494c4926ef0 " ,
hash ( " Lorem ipsum dolor sit amet. Nam placeat iste aut dolorem necessitatibus sit unde magni. Nam cumque quia nam fugit quibusdam ut incidunt minima nam dignissimos iusto et voluptatum magnam. Et pariatur eius vel excepturi odit libero sit molestiae consequatur vel nostrum ullam. Sit sint beatae eos doloribus sapiente aut aperiam ullam ut laboriosam debitis! Qui reiciendis rerum est omnis galisum aut similique iure est dolores fuga sit rerum dicta. Aut excepturi fuga et enim ipsum a quia ut velit atque id iste nobis. Non molestiae vero et veritatis aliquam sed enim ducimus. At sunt tempora quo quisquam unde aut ipsum nulla et fugit eius in nulla fugit qui magnam excepturi aut rerum officia. Et officia magnam eos reiciendis voluptatum ea voluptas recusandae in similique enim. Ut provident laudantium ut temporibus eius ut laudantium voluptate aut ducimus impedit. Et asperiores aperiam sit deleniti voluptas ex porro omnis ut voluptas assumenda aut necessitatibus aliquid. " ) . to_string ( )
) ;
}
#[ test ]
fn md5_steps ( ) {
let expected : [ [ u32 ; 4 ] ; 64 ] = [
[ 0x5954a129 , 0xefcdab89 , 0x98badcfe , 0x10325476 ] ,
[ 0x3171555d , 0x5954a129 , 0xefcdab89 , 0x98badcfe ] ,
[ 0x24368ecc , 0x3171555d , 0x5954a129 , 0xefcdab89 ] ,
[ 0x1d414db3 , 0x24368ecc , 0x3171555d , 0x5954a129 ] ,
[ 0x9da81fec , 0x1d414db3 , 0x24368ecc , 0x3171555d ] ,
[ 0x983a9b4c , 0x9da81fec , 0x1d414db3 , 0x24368ecc ] ,
[ 0x01f76eec , 0x983a9b4c , 0x9da81fec , 0x1d414db3 ] ,
[ 0x82251f6b , 0x01f76eec , 0x983a9b4c , 0x9da81fec ] ,
[ 0x3648b77a , 0x82251f6b , 0x01f76eec , 0x983a9b4c ] ,
[ 0xa57749ed , 0x3648b77a , 0x82251f6b , 0x01f76eec ] ,
[ 0x69859a5a , 0xa57749ed , 0x3648b77a , 0x82251f6b ] ,
[ 0x8dd64e23 , 0x69859a5a , 0xa57749ed , 0x3648b77a ] ,
[ 0x4cc08388 , 0x8dd64e23 , 0x69859a5a , 0xa57749ed ] ,
[ 0x9a1db095 , 0x4cc08388 , 0x8dd64e23 , 0x69859a5a ] ,
[ 0xf3a1ec18 , 0x9a1db095 , 0x4cc08388 , 0x8dd64e23 ] ,
[ 0x68bf5f16 , 0xf3a1ec18 , 0x9a1db095 , 0x4cc08388 ] ,
[ 0x08cf03db , 0x68bf5f16 , 0xf3a1ec18 , 0x9a1db095 ] ,
[ 0x03bceaa0 , 0x08cf03db , 0x68bf5f16 , 0xf3a1ec18 ] ,
[ 0x2809715f , 0x03bceaa0 , 0x08cf03db , 0x68bf5f16 ] ,
[ 0xc305e2e6 , 0x2809715f , 0x03bceaa0 , 0x08cf03db ] ,
[ 0x0386e9c7 , 0xc305e2e6 , 0x2809715f , 0x03bceaa0 ] ,
[ 0x0f4c9f59 , 0x0386e9c7 , 0xc305e2e6 , 0x2809715f ] ,
[ 0x8814e065 , 0x0f4c9f59 , 0x0386e9c7 , 0xc305e2e6 ] ,
[ 0xd8d052d2 , 0x8814e065 , 0x0f4c9f59 , 0x0386e9c7 ] ,
[ 0x8ff59707 , 0xd8d052d2 , 0x8814e065 , 0x0f4c9f59 ] ,
[ 0x4069945d , 0x8ff59707 , 0xd8d052d2 , 0x8814e065 ] ,
[ 0x213a0570 , 0x4069945d , 0x8ff59707 , 0xd8d052d2 ] ,
[ 0xf2affb96 , 0x213a0570 , 0x4069945d , 0x8ff59707 ] ,
[ 0x555223a9 , 0xf2affb96 , 0x213a0570 , 0x4069945d ] ,
[ 0x37ba19ca , 0x555223a9 , 0xf2affb96 , 0x213a0570 ] ,
[ 0x003749f2 , 0x37ba19ca , 0x555223a9 , 0xf2affb96 ] ,
[ 0x20617338 , 0x003749f2 , 0x37ba19ca , 0x555223a9 ] ,
[ 0xf3e971ee , 0x20617338 , 0x003749f2 , 0x37ba19ca ] ,
[ 0x4ec4ee85 , 0xf3e971ee , 0x20617338 , 0x003749f2 ] ,
[ 0xe62bf9a6 , 0x4ec4ee85 , 0xf3e971ee , 0x20617338 ] ,
[ 0x0ae8a02f , 0xe62bf9a6 , 0x4ec4ee85 , 0xf3e971ee ] ,
[ 0xbc31561a , 0x0ae8a02f , 0xe62bf9a6 , 0x4ec4ee85 ] ,
[ 0x6a9f6576 , 0xbc31561a , 0x0ae8a02f , 0xe62bf9a6 ] ,
[ 0x42e91ea3 , 0x6a9f6576 , 0xbc31561a , 0x0ae8a02f ] ,
[ 0x7a181668 , 0x42e91ea3 , 0x6a9f6576 , 0xbc31561a ] ,
[ 0xedcc403b , 0x7a181668 , 0x42e91ea3 , 0x6a9f6576 ] ,
[ 0x1fcae4da , 0xedcc403b , 0x7a181668 , 0x42e91ea3 ] ,
[ 0x217c84d1 , 0x1fcae4da , 0xedcc403b , 0x7a181668 ] ,
[ 0xf02591fa , 0x217c84d1 , 0x1fcae4da , 0xedcc403b ] ,
[ 0x5375b853 , 0xf02591fa , 0x217c84d1 , 0x1fcae4da ] ,
[ 0xecd77499 , 0x5375b853 , 0xf02591fa , 0x217c84d1 ] ,
[ 0x4bd1053f , 0xecd77499 , 0x5375b853 , 0xf02591fa ] ,
[ 0x7625a818 , 0x4bd1053f , 0xecd77499 , 0x5375b853 ] ,
[ 0xf7223b53 , 0x7625a818 , 0x4bd1053f , 0xecd77499 ] ,
[ 0x2e422a17 , 0xf7223b53 , 0x7625a818 , 0x4bd1053f ] ,
[ 0xe5235245 , 0x2e422a17 , 0xf7223b53 , 0x7625a818 ] ,
[ 0x8e8a212d , 0xe5235245 , 0x2e422a17 , 0xf7223b53 ] ,
[ 0x551950d2 , 0x8e8a212d , 0xe5235245 , 0x2e422a17 ] ,
[ 0xf067530c , 0x551950d2 , 0x8e8a212d , 0xe5235245 ] ,
[ 0xdb4e97cc , 0xf067530c , 0x551950d2 , 0x8e8a212d ] ,
[ 0x5b429768 , 0xdb4e97cc , 0xf067530c , 0x551950d2 ] ,
[ 0xb0c06d7a , 0x5b429768 , 0xdb4e97cc , 0xf067530c ] ,
[ 0xd1906cf3 , 0xb0c06d7a , 0x5b429768 , 0xdb4e97cc ] ,
[ 0x3fc74ed9 , 0xd1906cf3 , 0xb0c06d7a , 0x5b429768 ] ,
[ 0xa6b24624 , 0x3fc74ed9 , 0xd1906cf3 , 0xb0c06d7a ] ,
[ 0xf9d3c272 , 0xa6b24624 , 0x3fc74ed9 , 0xd1906cf3 ] ,
[ 0x4e25ae2a , 0xf9d3c272 , 0xa6b24624 , 0x3fc74ed9 ] ,
[ 0x1db436d8 , 0x4e25ae2a , 0xf9d3c272 , 0xa6b24624 ] ,
[ 0x9350b12d , 0x1db436d8 , 0x4e25ae2a , 0xf9d3c272 ] ,
] ;
let words : [ u32 ; 16 ] = [
0x69686974 , 0x80647820 , 0x00000000 , 0x00000000 , 0x00000000 , 0x00000000 , 0x00000000 ,
0x00000000 , 0x00000000 , 0x00000000 , 0x00000000 , 0x00000000 , 0x00000000 , 0x00000000 ,
0x00000038 , 0x00000000 ,
] ;
let mut state = [ A , B , C , D ] ;
#[ allow(clippy::needless_range_loop) ]
for i in 0 .. 64 {
state = step ( state , & words , i ) ;
assert_eq! ( expected [ i ] , state ) ;
state . rotate_right ( 1 ) ;
}
}
}