comparison dcrypt/crypto/hashes/MD5.d @ 27:8b5eaf3c2979

Fixed error in hash message padding reported by Glenn Haecker.
author Thomas Dixon <reikon@reikon.us>
date Sat, 09 May 2009 23:29:20 -0400
parents 176c933827a8
children ad687db713a4
comparison
equal deleted inserted replaced
26:176c933827a8 27:8b5eaf3c2979
15 * 15 *
16 * Conforms: RFC 1321 16 * Conforms: RFC 1321
17 * References: http://www.faqs.org/rfcs/rfc1321.html 17 * References: http://www.faqs.org/rfcs/rfc1321.html
18 * Bugs: MD5 is not cryptographically secure. 18 * Bugs: MD5 is not cryptographically secure.
19 */ 19 */
20 class MD5 : Hash { 20 class MD5 : Hash
21 {
21 private uint h0, h1, h2, h3; 22 private uint h0, h1, h2, h3;
22 23
23 // Shift amounts 24 // Shift amounts
24 private enum { 25 private enum
26 {
25 S11 = 7, 27 S11 = 7,
26 S12 = 12, 28 S12 = 12,
27 S13 = 17, 29 S13 = 17,
28 S14 = 22, 30 S14 = 22,
29 31
41 S42 = 10, 43 S42 = 10,
42 S43 = 15, 44 S43 = 15,
43 S44 = 21 45 S44 = 21
44 }; 46 };
45 47
46 this (void[] input_=null) { 48 this (void[] input_=null)
49 {
47 reset(); 50 reset();
48 super(input_); 51 super(input_);
49 } 52 }
50 53
51 uint blockSize() { 54 uint blockSize()
55 {
52 return 64; 56 return 64;
53 } 57 }
54 58
55 uint digestSize() { 59 uint digestSize()
60 {
56 return 16; 61 return 16;
57 } 62 }
58 63
59 char[] name() { 64 char[] name()
65 {
60 return "MD5"; 66 return "MD5";
61 } 67 }
62 68
63 void transform(ubyte[] input) { 69 void transform(ubyte[] input)
70 {
64 uint[] w = new uint[16]; 71 uint[] w = new uint[16];
65 72
66 for (int i = 0, j = 0; i < 16; i++,j+=int.sizeof) 73 for (int i = 0, j = 0; i < 16; i++,j+=int.sizeof)
67 w[i] = ByteConverter.LittleEndian.to!(uint)(input[j..j+int.sizeof]); 74 w[i] = ByteConverter.LittleEndian.to!(uint)(input[j..j+int.sizeof]);
68 75
149 h2 += c; 156 h2 += c;
150 h3 += d; 157 h3 += d;
151 // FATALITY! \o/ 158 // FATALITY! \o/
152 } 159 }
153 160
154 private uint f(uint x, uint y, uint z) { 161 private uint f(uint x, uint y, uint z)
162 {
155 return (x&y)|(~x&z); 163 return (x&y)|(~x&z);
156 } 164 }
157 165
158 private uint h(uint x, uint y, uint z) { 166 private uint h(uint x, uint y, uint z)
167 {
159 return x^y^z; 168 return x^y^z;
160 } 169 }
161 170
162 private uint g(uint x, uint y, uint z) { 171 private uint g(uint x, uint y, uint z)
172 {
163 return (x&z)|(y&~z); 173 return (x&z)|(y&~z);
164 } 174 }
165 175
166 private uint i(uint x, uint y, uint z) { 176 private uint i(uint x, uint y, uint z)
177 {
167 return y^(x|~z); 178 return y^(x|~z);
168 } 179 }
169 180
170 private void ff(ref uint a, uint b, uint c, 181 private void ff(ref uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
171 uint d, uint x, uint s, uint ac) { 182 {
172 a += f(b, c, d) + x + ac; 183 a += f(b, c, d) + x + ac;
173 a = Bitwise.rotateLeft(a, s); 184 a = Bitwise.rotateLeft(a, s);
174 a += b; 185 a += b;
175 } 186 }
176 187
177 private void gg(ref uint a, uint b, uint c, 188 private void gg(ref uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
178 uint d, uint x, uint s, uint ac) { 189 {
179 a += g(b, c, d) + x + ac; 190 a += g(b, c, d) + x + ac;
180 a = Bitwise.rotateLeft(a, s); 191 a = Bitwise.rotateLeft(a, s);
181 a += b; 192 a += b;
182 } 193 }
183 194
184 private void hh(ref uint a, uint b, uint c, 195 private void hh(ref uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
185 uint d, uint x, uint s, uint ac) { 196 {
186 a += h(b, c, d) + x + ac; 197 a += h(b, c, d) + x + ac;
187 a = Bitwise.rotateLeft(a, s); 198 a = Bitwise.rotateLeft(a, s);
188 a += b; 199 a += b;
189 } 200 }
190 201
191 private void ii(ref uint a, uint b, uint c, 202 private void ii(ref uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
192 uint d, uint x, uint s, uint ac) { 203 {
193 a += i(b, c, d) + x + ac; 204 a += i(b, c, d) + x + ac;
194 a = Bitwise.rotateLeft(a, s); 205 a = Bitwise.rotateLeft(a, s);
195 a += b; 206 a += b;
196 } 207 }
197 208
198 ubyte[] digest() { 209 ubyte[] digest()
210 {
199 padMessage(MODE_MD); 211 padMessage(MODE_MD);
200 ubyte[] result = new ubyte[digestSize]; 212 ubyte[] result = new ubyte[digestSize];
201 213
202 result[0..4] = ByteConverter.LittleEndian.from!(uint)(h0); 214 result[0..4] = ByteConverter.LittleEndian.from!(uint)(h0);
203 result[4..8] = ByteConverter.LittleEndian.from!(uint)(h1); 215 result[4..8] = ByteConverter.LittleEndian.from!(uint)(h1);
206 218
207 reset(); 219 reset();
208 return result; 220 return result;
209 } 221 }
210 222
211 void reset() { 223 void reset()
224 {
212 super.reset(); 225 super.reset();
213 h0 = 0x67452301u; 226 h0 = 0x67452301u;
214 h1 = 0xefcdab89u; 227 h1 = 0xefcdab89u;
215 h2 = 0x98badcfeu; 228 h2 = 0x98badcfeu;
216 h3 = 0x10325476u; 229 h3 = 0x10325476u;
217 } 230 }
218 231
219 MD5 copy() { 232 MD5 copy()
233 {
220 MD5 h = new MD5(buffer[0..index]); 234 MD5 h = new MD5(buffer[0..index]);
221 h.bytes = bytes; 235 h.bytes = bytes;
222 h.h0 = h0; 236 h.h0 = h0;
223 h.h1 = h1; 237 h.h1 = h1;
224 h.h2 = h2; 238 h.h2 = h2;
225 h.h3 = h3; 239 h.h3 = h3;
226 return h; 240 return h;
227 } 241 }
228 242
229 debug (UnitTest) { 243 debug (UnitTest)
244 {
230 // Found in Tango <3 245 // Found in Tango <3
231 unittest { 246 unittest
247 {
232 static const char[][] test_inputs = [ 248 static const char[][] test_inputs = [
233 "", 249 "",
234 "a", 250 "a",
235 "abc", 251 "abc",
236 "message digest", 252 "message digest",
248 "d174ab98d277d9f5a5611c2c9f419d9f", 264 "d174ab98d277d9f5a5611c2c9f419d9f",
249 "57edf4a22be3c955ac49da2e2107b67a" 265 "57edf4a22be3c955ac49da2e2107b67a"
250 ]; 266 ];
251 267
252 MD5 h = new MD5(); 268 MD5 h = new MD5();
253 foreach (uint i, char[] input; test_inputs) { 269 foreach (uint i, char[] input; test_inputs)
270 {
254 h.update(input); 271 h.update(input);
255 char[] digest = h.hexDigest(); 272 char[] digest = h.hexDigest();
256 assert(digest == test_results[i], 273 assert(digest == test_results[i],
257 h.name~": ("~digest~") != ("~test_results[i]~")"); 274 h.name~": ("~digest~") != ("~test_results[i]~")");
258 } 275 }