enigma/hashes/
md2.rs

1static MD2_S_TABLE: &'static [u8] = &[
2    0x29, 0x2E, 0x43, 0xC9, 0xA2, 0xD8, 0x7C, 0x01, 0x3D, 0x36, 0x54, 0xA1, 0xEC, 0xF0, 0x06, 0x13,
3    0x62, 0xA7, 0x05, 0xF3, 0xC0, 0xC7, 0x73, 0x8C, 0x98, 0x93, 0x2B, 0xD9, 0xBC, 0x4C, 0x82, 0xCA,
4    0x1E, 0x9B, 0x57, 0x3C, 0xFD, 0xD4, 0xE0, 0x16, 0x67, 0x42, 0x6F, 0x18, 0x8A, 0x17, 0xE5, 0x12,
5    0xBE, 0x4E, 0xC4, 0xD6, 0xDA, 0x9E, 0xDE, 0x49, 0xA0, 0xFB, 0xF5, 0x8E, 0xBB, 0x2F, 0xEE, 0x7A,
6    0xA9, 0x68, 0x79, 0x91, 0x15, 0xB2, 0x07, 0x3F, 0x94, 0xC2, 0x10, 0x89, 0x0B, 0x22, 0x5F, 0x21,
7    0x80, 0x7F, 0x5D, 0x9A, 0x5A, 0x90, 0x32, 0x27, 0x35, 0x3E, 0xCC, 0xE7, 0xBF, 0xF7, 0x97, 0x03,
8    0xFF, 0x19, 0x30, 0xB3, 0x48, 0xA5, 0xB5, 0xD1, 0xD7, 0x5E, 0x92, 0x2A, 0xAC, 0x56, 0xAA, 0xC6,
9    0x4F, 0xB8, 0x38, 0xD2, 0x96, 0xA4, 0x7D, 0xB6, 0x76, 0xFC, 0x6B, 0xE2, 0x9C, 0x74, 0x04, 0xF1,
10    0x45, 0x9D, 0x70, 0x59, 0x64, 0x71, 0x87, 0x20, 0x86, 0x5B, 0xCF, 0x65, 0xE6, 0x2D, 0xA8, 0x02,
11    0x1B, 0x60, 0x25, 0xAD, 0xAE, 0xB0, 0xB9, 0xF6, 0x1C, 0x46, 0x61, 0x69, 0x34, 0x40, 0x7E, 0x0F,
12    0x55, 0x47, 0xA3, 0x23, 0xDD, 0x51, 0xAF, 0x3A, 0xC3, 0x5C, 0xF9, 0xCE, 0xBA, 0xC5, 0xEA, 0x26,
13    0x2C, 0x53, 0x0D, 0x6E, 0x85, 0x28, 0x84, 0x09, 0xD3, 0xDF, 0xCD, 0xF4, 0x41, 0x81, 0x4D, 0x52,
14    0x6A, 0xDC, 0x37, 0xC8, 0x6C, 0xC1, 0xAB, 0xFA, 0x24, 0xE1, 0x7B, 0x08, 0x0C, 0xBD, 0xB1, 0x4A,
15    0x78, 0x88, 0x95, 0x8B, 0xE3, 0x63, 0xE8, 0x6D, 0xE9, 0xCB, 0xD5, 0xFE, 0x3B, 0x00, 0x1D, 0x39,
16    0xF2, 0xEF, 0xB7, 0x0E, 0x66, 0x58, 0xD0, 0xE4, 0xA6, 0x77, 0x72, 0xF8, 0xEB, 0x75, 0x4B, 0x0A,
17    0x31, 0x44, 0x50, 0xB4, 0x8F, 0xED, 0x1F, 0x1A, 0xDB, 0x99, 0x8D, 0x33, 0x9F, 0x11, 0x83, 0x14
18];
19
20/// Struct storing the necessary state for the Message Digest 2 (MD2) hash function
21/// Code is ported and `rustified` from libtomcrypt
22#[allow(non_camel_case_types)]
23pub struct MD2 {
24    check_sum : [u8; 16],
25    x         : [u8; 48],
26    buffer    : [u8; 16],
27    cur_len   : usize
28}
29
30fn md2_compress(state: &mut MD2) {
31   /* copy block to state.x */
32   for i in 0..16 {
33       state.x[16 + i] = state.buffer[i];
34       state.x[32 + i] = state.x[i] ^ state.x[16 + i];
35   }
36
37   let mut t = 0u8;
38   /* perform 18 rounds */
39   for round in 0..18 {
40       for i in 0..48 {
41           state.x[i] ^= MD2_S_TABLE[(t & 255) as usize];
42           t = state.x[i];
43       }
44       t = t + round & 255;
45   }
46}
47
48#[allow(non_snake_case)]
49fn md2_update_checksum(state: &mut MD2) {
50    let mut L = state.check_sum[15];
51    for i in 0..16 {
52        /* caution, the RFC says its "C[j] = S[M[i*16+j] xor L]" but the reference
53         * source code [and test vectors] say otherwise. */
54        state.check_sum[i] ^= MD2_S_TABLE[(state.buffer[i] ^ L) as usize] & 255;
55        L = state.check_sum[i];
56    }
57}
58
59impl MD2 {
60    /// Creates a new MD2 instance
61    ///
62    /// # Returns
63    /// * The created instance
64    pub fn new() -> MD2 {
65        MD2 {
66            check_sum : [0; 16],
67            x         : [0; 48],
68            buffer    : [0; 16],
69            cur_len   : 0
70        }
71    }
72
73    fn reset(&mut self) {
74        self.check_sum = [0; 16];
75        self.x         = [0; 48];
76        self.buffer    = [0; 16];
77        self.cur_len   = 0;
78    }
79}
80
81impl ::hashes::HashFunction for MD2 {
82    fn set_input(&mut self, input: &[u8]) {
83        use std::cmp::{min};
84
85        // First reset the hash state
86        self.reset();
87
88        let mut index = 0usize;
89        let mut in_len = input.len();
90
91        loop {
92            if in_len <= 0 {
93                break;
94            }
95
96            let n = min(in_len, (16 - self.cur_len));
97            for i in 0..n {
98                self.buffer[self.cur_len + i] = input[index + i];
99            }
100            self.cur_len += n;
101            index        += n;
102            in_len       -= n;
103
104            /* if 16 bytes are filled compress and update checksum */
105            if self.cur_len == 16 {
106                md2_compress(self);
107                md2_update_checksum(self);
108                self.cur_len = 0;
109            }
110        }
111    }
112
113    fn hash(&mut self) {
114        // When is this the case?
115        if self.cur_len >= self.buffer.len() {
116           panic!("self.cur_len >= self.buffer.len()")
117        }
118
119        /* pad the message */
120        let k: u8 = 16u8 - self.cur_len as u8;
121        for i in self.cur_len as usize..16 {
122            self.buffer[i] = k;
123        }
124
125        /* hash and update */
126        md2_compress(self);
127        md2_update_checksum(self);
128
129        /* hash checksum */
130        for i in 0..16 {
131            self.buffer[i] = self.check_sum[i];
132        }
133        md2_compress(self);
134    }
135
136    fn get_output(&mut self, output: &mut [u8]) {
137        assert!(output.len() >= self.get_output_length());
138
139        for i in 0..16 {
140            output[i] = self.x[i];
141        }
142    }
143
144    fn get_blocksize(&self) -> u32 { 16 }
145
146    fn get_output_length_in_bits(&self) -> u32 { 128 }
147}
148
149#[cfg(test)]
150mod tests {
151    use hashes::md2::MD2;
152    use hashes::test::{HashTestCase, perform_hash_test};
153
154    #[test]
155    fn test_md2() {
156        let tests = vec![
157            hash_test!(
158                "",
159                vec![0x83,0x50,0xe5,0xa3,0xe2,0x4c,0x15,0x3d,0xf2,0x27,0x5c,0x9f,0x80,0x69,0x27,0x73],
160                "8350e5a3e24c153df2275c9f80692773"),
161            hash_test!(
162                "a",
163                vec![0x32,0xec,0x01,0xec,0x4a,0x6d,0xac,0x72,0xc0,0xab,0x96,0xfb,0x34,0xc0,0xb5,0xd1],
164                "32ec01ec4a6dac72c0ab96fb34c0b5d1"),
165            hash_test!(
166                "message digest",
167                vec![0xab,0x4f,0x49,0x6b,0xfb,0x2a,0x53,0x0b,0x21,0x9f,0xf3,0x30,0x31,0xfe,0x06,0xb0],
168                "ab4f496bfb2a530b219ff33031fe06b0"),
169            hash_test!(
170                "abcdefghijklmnopqrstuvwxyz",
171                vec![0x4e,0x8d,0xdf,0xf3,0x65,0x02,0x92,0xab,0x5a,0x41,0x08,0xc3,0xaa,0x47,0x94,0x0b],
172                "4e8ddff3650292ab5a4108c3aa47940b"),
173            hash_test!(
174                "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
175                vec![0xda,0x33,0xde,0xf2,0xa4,0x2d,0xf1,0x39,0x75,0x35,0x28,0x46,0xc3,0x03,0x38,0xcd],
176                "da33def2a42df13975352846c30338cd"),
177            hash_test!(
178                "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
179                vec![0xd5,0x97,0x6f,0x79,0xd8,0x3d,0x3a,0x0d,0xc9,0x80,0x6c,0x3c,0x66,0xf3,0xef,0xd8],
180                "d5976f79d83d3a0dc9806c3c66f3efd8")
181        ];
182
183        let mut md2 = MD2::new();
184        for t in tests.iter() {
185            perform_hash_test(&mut md2, t);
186        }
187    }
188}