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