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.util.digest.Md4;
17 
18 public  import tango.util.digest.Digest;
19 
20 private import tango.util.digest.MerkleDamgard;
21 
22 /*******************************************************************************
23 
24 *******************************************************************************/
25 
26 class Md4 : MerkleDamgard
27 {
28         protected uint[4]       context;
29         private enum 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         override 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(const(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(ref 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(ref 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(ref 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 debug(UnitTest)
340 {
341         unittest 
342         {
343         __gshared immutable immutable(char)[][] strings = 
344         [
345                 "",
346                 "a",
347                 "abc",
348                 "message digest",
349                 "abcdefghijklmnopqrstuvwxyz",
350                 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
351                 "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
352         ];
353 
354         __gshared immutable immutable(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, immutable(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