diff --git a/md6/src/lib.rs b/md6/src/lib.rs index f0def63a..3a85aa4d 100644 --- a/md6/src/lib.rs +++ b/md6/src/lib.rs @@ -57,7 +57,7 @@ impl MD6 { Some(Self { rounds, ..self }) } - fn control_word( + pub fn control_word( &self, is_final_compression: bool, num_of_padding_data_bits: u16, @@ -72,7 +72,33 @@ impl MD6 { } } - fn compression(&self, node_id: u64, control_word: ControlWord, data: [u64; 64]) -> [u64; 16] { + pub fn compression( + &self, + node_id: u64, + control_word: ControlWord, + data: [u64; 64], + ) -> [u64; 16] { + let mut input = [0u64; 89]; + input[0..=14].copy_from_slice(&Self::VECTOR_Q); + input[15..=22].copy_from_slice( + self.key + .chunks(8) + .map(|bytes: &[u8]| -> u64 { + u64::from_be_bytes([ + bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], + bytes[7], + ]) + }) + .collect::>() + .as_slice(), + ); + input[23] = node_id; + input[24] = control_word.into(); + input[25..].copy_from_slice(&data); + self.compression_internal(input) + } + + fn compression_internal(&self, input: [u64; 89]) -> [u64; 16] { const T0: usize = 17; const T1: usize = 18; const T2: usize = 21; @@ -82,9 +108,6 @@ impl MD6 { const R_I_N: [u64; 16] = [10, 5, 13, 10, 11, 12, 2, 7, 14, 15, 7, 13, 11, 7, 6, 12]; const L_I_N: [u64; 16] = [11, 24, 9, 16, 15, 9, 27, 15, 6, 2, 29, 8, 15, 5, 31, 9]; - const S0: u64 = 0x0123_4567_89AB_CDEF; - const S1: u64 = 0x7311_C281_2425_CFA0; - const S: [u64; 168] = [ 0x0123456789abcdef, 0x0347cace1376567e, @@ -256,23 +279,6 @@ impl MD6 { 0x2859265840d89322, ]; - let mut input = [0u64; 89]; - input[0..=14].copy_from_slice(&Self::VECTOR_Q); - input[15..=22].copy_from_slice( - self.key - .chunks(8) - .map(|bytes: &[u8]| -> u64 { - u64::from_be_bytes([ - bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], - bytes[7], - ]) - }) - .collect::>() - .as_slice(), - ); - input[23] = node_id; - input[24] = control_word.into(); - input[25..].copy_from_slice(&data); let input_len = input.len(); let steps = self.rounds as usize * 16; let mut output_vec = Vec::new(); @@ -282,7 +288,6 @@ impl MD6 { x += (input[i - T1] ^ input[i - T2]) + (input[i - T3] ^ input[i - T4]); x += x >> R_I_N[i - input_len]; output_vec[i - input_len] = x + (x << L_I_N[i - input_len]); - dbg!(output_vec[i - input_len]); } let mut result = [0u64; 16]; result.copy_from_slice(&output_vec[steps + input_len - 16..steps + input_len - 1]); @@ -297,10 +302,6 @@ impl MD6 { default_r } } - - fn next_round_const(curr_round_const: u64) -> u64 { - curr_round_const.rotate_left(1) ^ (curr_round_const | 0x7311_C281_2425_CFA0) - } } impl KeySizeUser for MD6 { @@ -343,24 +344,44 @@ impl Update for MD6 { } } -struct ControlWord { - rounds: u16, - mode: u8, - is_final_compression: bool, - num_of_padding_data_bits: u16, - keylen: u8, - desired_digest_length: u16, +#[derive(Debug, PartialEq)] +pub struct ControlWord { + pub rounds: u16, + pub mode: u8, + pub is_final_compression: bool, + pub num_of_padding_data_bits: u16, + pub keylen: u8, + pub desired_digest_length: u16, } impl From for u64 { fn from(value: ControlWord) -> Self { - todo!() + (value.rounds as u64) << 48 | (value.mode as u64) << 40 | (value.is_final_compression as u64) << 36 | (value.num_of_padding_data_bits as u64) << 20 | (value.keylen as u64) << 12 | (value.desired_digest_length as u64) } } impl From for ControlWord { - fn from(_: u64) -> Self { - todo!() + fn from(value: u64) -> Self { + let bytes = value.to_be_bytes(); + let _reserved = bytes[0] >> 4; + let rounds = u16::from_be_bytes([bytes[0] & 0b0000_1111, bytes[1]]); + let mode = bytes[2]; + let is_final_compression = bytes[3] & 0b1111_0000 != 0; + let num_of_padding_data_bits = u16::from_be_bytes([ + (bytes[3] << 4) | (bytes[4] >> 4), + (bytes[4] << 4) | (bytes[5] >> 4), + ]); + let keylen = (bytes[5] << 4) | (bytes[6] >> 4); + let desired_digest_length = u16::from_be_bytes([bytes[6] & 0b0000_1111, bytes[7]]); + + Self { + rounds, + mode, + is_final_compression, + num_of_padding_data_bits, + keylen, + desired_digest_length, + } } } @@ -369,27 +390,98 @@ mod tests { use super::*; #[test] - fn test_zero_sized_md6() { - assert_eq!(MD6::new(0).is_err(), true) + fn test_control_word_from_u64_1() { + let left = ControlWord { + rounds: 5, + mode: 64, + is_final_compression: true, + num_of_padding_data_bits: 4072, + keylen: 0, + desired_digest_length: 256, + }; + + let right = ControlWord::from(0x0005_4010_FE80_0100); + + assert_eq!(left, right); + } + + #[test] + fn test_control_word_from_u64_2() { + let left = ControlWord { + rounds: 5, + mode: 64, + is_final_compression: false, + num_of_padding_data_bits: 0, + keylen: 10, + desired_digest_length: 224 + }; + + let right = ControlWord::from(0x0005_4000_0000_A0E0); + + assert_eq!(left, right); } #[test] - fn test_1024byte_md6() { - assert_eq!(MD6::new(1024).is_err(), true) + fn test_control_word_from_u64_3() { + let left = ControlWord { + rounds: 104, + mode: 0, + is_final_compression: false, + num_of_padding_data_bits: 0, + keylen: 0, + desired_digest_length: 256, + }; + + let right = ControlWord::from(0x0068_0000_0000_0100); + + assert_eq!(left, right); } #[test] - fn test_1byte_md6() { - assert_eq!(MD6::new(1).is_ok(), true) + fn test_control_word_as_u64_1() { + let left = u64::from(ControlWord { + rounds: 5, + mode: 64, + is_final_compression: true, + num_of_padding_data_bits: 4072, + keylen: 0, + desired_digest_length: 256, + }); + + let right = 0x0005_4010_FE80_0100; + + assert_eq!(left, right); } #[test] - fn test_64byte_md6() { - assert_eq!(MD6::new(64).is_ok(), true) + fn test_control_word_as_u64_2() { + let left = u64::from(ControlWord { + rounds: 5, + mode: 64, + is_final_compression: false, + num_of_padding_data_bits: 0, + keylen: 10, + desired_digest_length: 224 + }); + + let right = 0x0005_4000_0000_A0E0; + + assert_eq!(left, right) } #[test] - fn test_512byte_md6() { - assert_eq!(MD6::new(512).is_err(), true) + fn test_control_word_as_u64_3() { + let left = u64::from(ControlWord { + rounds: 104, + mode: 0, + is_final_compression: false, + num_of_padding_data_bits: 0, + keylen: 0, + desired_digest_length: 256, + }); + + let right = 0x0068_0000_0000_0100; + + assert_eq!(left, right); } }