132
|
1 /*******************************************************************************
|
|
2
|
|
3 copyright: Copyright (c) 2006 Tango. All rights reserved
|
|
4
|
|
5 license: BSD style: see doc/license.txt for details
|
|
6
|
|
7 version: Initial release: Feb 2006
|
|
8
|
|
9 author: Regan Heath, Oskar Linde
|
|
10
|
|
11 This module implements the MD4 Message Digest Algorithm as described
|
|
12 by RFC 1320 The MD4 Message-Digest Algorithm. R. Rivest. April 1992.
|
|
13
|
|
14 *******************************************************************************/
|
|
15
|
|
16 module tango.io.digest.Md4;
|
|
17
|
|
18 public import tango.io.digest.Digest;
|
|
19
|
|
20 private import tango.io.digest.MerkleDamgard;
|
|
21
|
|
22 /*******************************************************************************
|
|
23
|
|
24 *******************************************************************************/
|
|
25
|
|
26 class Md4 : MerkleDamgard
|
|
27 {
|
|
28 protected uint[4] context;
|
|
29 private const ubyte padChar = 0x80;
|
|
30
|
|
31 /***********************************************************************
|
|
32
|
|
33 Construct an Md4
|
|
34
|
|
35 ***********************************************************************/
|
|
36
|
|
37 this() { }
|
|
38
|
|
39 /***********************************************************************
|
|
40
|
|
41 The MD 4 digest size is 16 bytes
|
|
42
|
|
43 ***********************************************************************/
|
|
44
|
|
45 uint digestSize() { return 16; }
|
|
46
|
|
47 /***********************************************************************
|
|
48
|
|
49 Initialize the cipher
|
|
50
|
|
51 Remarks:
|
|
52 Returns the cipher state to it's initial value
|
|
53
|
|
54 ***********************************************************************/
|
|
55
|
|
56 override void reset()
|
|
57 {
|
|
58 super.reset();
|
|
59 context[] = initial[];
|
|
60 }
|
|
61
|
|
62 /***********************************************************************
|
|
63
|
|
64 Obtain the digest
|
|
65
|
|
66 Returns:
|
|
67 the digest
|
|
68
|
|
69 Remarks:
|
|
70 Returns a digest of the current cipher state, this may be the
|
|
71 final digest, or a digest of the state between calls to update()
|
|
72
|
|
73 ***********************************************************************/
|
|
74
|
|
75 override void createDigest(ubyte[] buf)
|
|
76 {
|
|
77 version (BigEndian)
|
|
78 ByteSwap.swap32 (context.ptr, context.length * uint.sizeof);
|
|
79
|
|
80 buf[] = cast(ubyte[]) context;
|
|
81 }
|
|
82
|
|
83 /***********************************************************************
|
|
84
|
|
85 block size
|
|
86
|
|
87 Returns:
|
|
88 the block size
|
|
89
|
|
90 Remarks:
|
|
91 Specifies the size (in bytes) of the block of data to pass to
|
|
92 each call to transform(). For MD4 the blockSize is 64.
|
|
93
|
|
94 ***********************************************************************/
|
|
95
|
|
96 protected override uint blockSize() { return 64; }
|
|
97
|
|
98 /***********************************************************************
|
|
99
|
|
100 Length padding size
|
|
101
|
|
102 Returns:
|
|
103 the length padding size
|
|
104
|
|
105 Remarks:
|
|
106 Specifies the size (in bytes) of the padding which uses the
|
|
107 length of the data which has been ciphered, this padding is
|
|
108 carried out by the padLength method. For MD4 the addSize is 8.
|
|
109
|
|
110 ***********************************************************************/
|
|
111
|
|
112 protected override uint addSize() { return 8; }
|
|
113
|
|
114 /***********************************************************************
|
|
115
|
|
116 Pads the cipher data
|
|
117
|
|
118 Params:
|
|
119 data = a slice of the cipher buffer to fill with padding
|
|
120
|
|
121 Remarks:
|
|
122 Fills the passed buffer slice with the appropriate padding for
|
|
123 the final call to transform(). This padding will fill the cipher
|
|
124 buffer up to blockSize()-addSize().
|
|
125
|
|
126 ***********************************************************************/
|
|
127
|
|
128 protected override void padMessage(ubyte[] data)
|
|
129 {
|
|
130 data[0] = padChar;
|
|
131 data[1..$] = 0;
|
|
132 }
|
|
133
|
|
134 /***********************************************************************
|
|
135
|
|
136 Performs the length padding
|
|
137
|
|
138 Params:
|
|
139 data = the slice of the cipher buffer to fill with padding
|
|
140 length = the length of the data which has been ciphered
|
|
141
|
|
142 Remarks:
|
|
143 Fills the passed buffer slice with addSize() bytes of padding
|
|
144 based on the length in bytes of the input data which has been
|
|
145 ciphered.
|
|
146
|
|
147 ***********************************************************************/
|
|
148
|
|
149 protected override void padLength(ubyte[] data, ulong length)
|
|
150 {
|
|
151 length <<= 3;
|
|
152 littleEndian64((cast(ubyte*)&length)[0..8],cast(ulong[]) data);
|
|
153 }
|
|
154
|
|
155 /***********************************************************************
|
|
156
|
|
157 Performs the cipher on a block of data
|
|
158
|
|
159 Params:
|
|
160 data = the block of data to cipher
|
|
161
|
|
162 Remarks:
|
|
163 The actual cipher algorithm is carried out by this method on
|
|
164 the passed block of data. This method is called for every
|
|
165 blockSize() bytes of input data and once more with the remaining
|
|
166 data padded to blockSize().
|
|
167
|
|
168 ***********************************************************************/
|
|
169
|
|
170 protected override void transform(ubyte[] input)
|
|
171 {
|
|
172 uint a,b,c,d;
|
|
173 uint[16] x;
|
|
174
|
|
175 littleEndian32(input,x);
|
|
176
|
|
177 a = context[0];
|
|
178 b = context[1];
|
|
179 c = context[2];
|
|
180 d = context[3];
|
|
181
|
|
182 /* Round 1 */
|
|
183 ff(a, b, c, d, x[ 0], S11, 0); /* 1 */
|
|
184 ff(d, a, b, c, x[ 1], S12, 0); /* 2 */
|
|
185 ff(c, d, a, b, x[ 2], S13, 0); /* 3 */
|
|
186 ff(b, c, d, a, x[ 3], S14, 0); /* 4 */
|
|
187 ff(a, b, c, d, x[ 4], S11, 0); /* 5 */
|
|
188 ff(d, a, b, c, x[ 5], S12, 0); /* 6 */
|
|
189 ff(c, d, a, b, x[ 6], S13, 0); /* 7 */
|
|
190 ff(b, c, d, a, x[ 7], S14, 0); /* 8 */
|
|
191 ff(a, b, c, d, x[ 8], S11, 0); /* 9 */
|
|
192 ff(d, a, b, c, x[ 9], S12, 0); /* 10 */
|
|
193 ff(c, d, a, b, x[10], S13, 0); /* 11 */
|
|
194 ff(b, c, d, a, x[11], S14, 0); /* 12 */
|
|
195 ff(a, b, c, d, x[12], S11, 0); /* 13 */
|
|
196 ff(d, a, b, c, x[13], S12, 0); /* 14 */
|
|
197 ff(c, d, a, b, x[14], S13, 0); /* 15 */
|
|
198 ff(b, c, d, a, x[15], S14, 0); /* 16 */
|
|
199
|
|
200 /* Round 2 */
|
|
201 gg(a, b, c, d, x[ 0], S21, 0x5a827999); /* 17 */
|
|
202 gg(d, a, b, c, x[ 4], S22, 0x5a827999); /* 18 */
|
|
203 gg(c, d, a, b, x[ 8], S23, 0x5a827999); /* 19 */
|
|
204 gg(b, c, d, a, x[12], S24, 0x5a827999); /* 20 */
|
|
205 gg(a, b, c, d, x[ 1], S21, 0x5a827999); /* 21 */
|
|
206 gg(d, a, b, c, x[ 5], S22, 0x5a827999); /* 22 */
|
|
207 gg(c, d, a, b, x[ 9], S23, 0x5a827999); /* 23 */
|
|
208 gg(b, c, d, a, x[13], S24, 0x5a827999); /* 24 */
|
|
209 gg(a, b, c, d, x[ 2], S21, 0x5a827999); /* 25 */
|
|
210 gg(d, a, b, c, x[ 6], S22, 0x5a827999); /* 26 */
|
|
211 gg(c, d, a, b, x[10], S23, 0x5a827999); /* 27 */
|
|
212 gg(b, c, d, a, x[14], S24, 0x5a827999); /* 28 */
|
|
213 gg(a, b, c, d, x[ 3], S21, 0x5a827999); /* 29 */
|
|
214 gg(d, a, b, c, x[ 7], S22, 0x5a827999); /* 30 */
|
|
215 gg(c, d, a, b, x[11], S23, 0x5a827999); /* 31 */
|
|
216 gg(b, c, d, a, x[15], S24, 0x5a827999); /* 32 */
|
|
217
|
|
218 /* Round 3 */
|
|
219 hh(a, b, c, d, x[ 0], S31, 0x6ed9eba1); /* 33 */
|
|
220 hh(d, a, b, c, x[ 8], S32, 0x6ed9eba1); /* 34 */
|
|
221 hh(c, d, a, b, x[ 4], S33, 0x6ed9eba1); /* 35 */
|
|
222 hh(b, c, d, a, x[12], S34, 0x6ed9eba1); /* 36 */
|
|
223 hh(a, b, c, d, x[ 2], S31, 0x6ed9eba1); /* 37 */
|
|
224 hh(d, a, b, c, x[10], S32, 0x6ed9eba1); /* 38 */
|
|
225 hh(c, d, a, b, x[ 6], S33, 0x6ed9eba1); /* 39 */
|
|
226 hh(b, c, d, a, x[14], S34, 0x6ed9eba1); /* 40 */
|
|
227 hh(a, b, c, d, x[ 1], S31, 0x6ed9eba1); /* 41 */
|
|
228 hh(d, a, b, c, x[ 9], S32, 0x6ed9eba1); /* 42 */
|
|
229 hh(c, d, a, b, x[ 5], S33, 0x6ed9eba1); /* 43 */
|
|
230 hh(b, c, d, a, x[13], S34, 0x6ed9eba1); /* 44 */
|
|
231 hh(a, b, c, d, x[ 3], S31, 0x6ed9eba1); /* 45 */
|
|
232 hh(d, a, b, c, x[11], S32, 0x6ed9eba1); /* 46 */
|
|
233 hh(c, d, a, b, x[ 7], S33, 0x6ed9eba1); /* 47 */
|
|
234 hh(b, c, d, a, x[15], S34, 0x6ed9eba1); /* 48 */
|
|
235
|
|
236 context[0] += a;
|
|
237 context[1] += b;
|
|
238 context[2] += c;
|
|
239 context[3] += d;
|
|
240
|
|
241 x[] = 0;
|
|
242 }
|
|
243
|
|
244 /***********************************************************************
|
|
245
|
|
246 ***********************************************************************/
|
|
247
|
|
248 protected static uint f(uint x, uint y, uint z)
|
|
249 {
|
|
250 return (x&y)|(~x&z);
|
|
251 }
|
|
252
|
|
253 /***********************************************************************
|
|
254
|
|
255 ***********************************************************************/
|
|
256
|
|
257 protected static uint h(uint x, uint y, uint z)
|
|
258 {
|
|
259 return x^y^z;
|
|
260 }
|
|
261
|
|
262 /***********************************************************************
|
|
263
|
|
264 ***********************************************************************/
|
|
265
|
|
266 private static uint g(uint x, uint y, uint z)
|
|
267 {
|
|
268 return (x&y)|(x&z)|(y&z);
|
|
269 }
|
|
270
|
|
271 /***********************************************************************
|
|
272
|
|
273 ***********************************************************************/
|
|
274
|
|
275 private static void ff(inout uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
|
|
276 {
|
|
277 a += f(b, c, d) + x + ac;
|
|
278 a = rotateLeft(a, s);
|
|
279 }
|
|
280
|
|
281 /***********************************************************************
|
|
282
|
|
283 ***********************************************************************/
|
|
284
|
|
285 private static void gg(inout uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
|
|
286 {
|
|
287 a += g(b, c, d) + x + ac;
|
|
288 a = rotateLeft(a, s);
|
|
289 }
|
|
290
|
|
291 /***********************************************************************
|
|
292
|
|
293 ***********************************************************************/
|
|
294
|
|
295 private static void hh(inout uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
|
|
296 {
|
|
297 a += h(b, c, d) + x + ac;
|
|
298 a = rotateLeft(a, s);
|
|
299 }
|
|
300
|
|
301 /***********************************************************************
|
|
302
|
|
303 ***********************************************************************/
|
|
304
|
|
305 private static const uint[4] initial =
|
|
306 [
|
|
307 0x67452301,
|
|
308 0xefcdab89,
|
|
309 0x98badcfe,
|
|
310 0x10325476
|
|
311 ];
|
|
312
|
|
313 /***********************************************************************
|
|
314
|
|
315 ***********************************************************************/
|
|
316
|
|
317 private static enum
|
|
318 {
|
|
319 S11 = 3,
|
|
320 S12 = 7,
|
|
321 S13 = 11,
|
|
322 S14 = 19,
|
|
323 S21 = 3,
|
|
324 S22 = 5,
|
|
325 S23 = 9,
|
|
326 S24 = 13,
|
|
327 S31 = 3,
|
|
328 S32 = 9,
|
|
329 S33 = 11,
|
|
330 S34 = 15,
|
|
331 }
|
|
332 }
|
|
333
|
|
334
|
|
335 /*******************************************************************************
|
|
336
|
|
337 *******************************************************************************/
|
|
338
|
|
339 version (UnitTest)
|
|
340 {
|
|
341 unittest
|
|
342 {
|
|
343 static char[][] strings =
|
|
344 [
|
|
345 "",
|
|
346 "a",
|
|
347 "abc",
|
|
348 "message digest",
|
|
349 "abcdefghijklmnopqrstuvwxyz",
|
|
350 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
|
|
351 "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
|
|
352 ];
|
|
353
|
|
354 static char[][] results =
|
|
355 [
|
|
356 "31d6cfe0d16ae931b73c59d7e0c089c0",
|
|
357 "bde52cb31de33e46245e05fbdbd6fb24",
|
|
358 "a448017aaf21d8525fc10ae87aa6729d",
|
|
359 "d9130a8164549fe818874806e1c7014b",
|
|
360 "d79e1c308aa5bbcdeea8ed63df412da9",
|
|
361 "043f8582f241db351ce627e153e7f0e4",
|
|
362 "e33b4ddc9c38f2199c3e7b164fcc0536"
|
|
363 ];
|
|
364
|
|
365 Md4 h = new Md4();
|
|
366
|
|
367 foreach (int i, char[] s; strings)
|
|
368 {
|
|
369 h.update(s);
|
|
370 char[] d = h.hexDigest;
|
|
371 assert(d == results[i],":("~s~")("~d~")!=("~results[i]~")");
|
|
372 }
|
|
373 }
|
|
374 }
|
|
375
|