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#[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 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 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 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 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 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 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 if self.cur_len >= self.buffer.len() {
116 panic!("self.cur_len >= self.buffer.len()")
117 }
118
119 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 md2_compress(self);
127 md2_update_checksum(self);
128
129 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}