1 /*******************************************************************************
2 
3         This module implements the MD5 Message Digest Algorithm as described
4         by RFC 1321 The MD5 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.Md5;
22 
23 import ocean.meta.types.Qualifiers;
24 
25 public  import ocean.util.digest.Md4;
26 
27 import ocean.util.digest.MerkleDamgard;
28 
29 version (unittest) import ocean.core.Test;
30 
31 /*******************************************************************************
32 
33 *******************************************************************************/
34 
35 final class Md5 : Md4
36 {
37         /***********************************************************************
38 
39         ***********************************************************************/
40 
41         private enum
42         {
43                 S11 =  7,
44                 S12 = 12,
45                 S13 = 17,
46                 S14 = 22,
47                 S21 =  5,
48                 S22 =  9,
49                 S23 = 14,
50                 S24 = 20,
51                 S31 =  4,
52                 S32 = 11,
53                 S33 = 16,
54                 S34 = 23,
55                 S41 =  6,
56                 S42 = 10,
57                 S43 = 15,
58                 S44 = 21
59         };
60 
61         /***********************************************************************
62 
63                 Construct an Md5
64 
65         ***********************************************************************/
66 
67         this() { }
68 
69 
70         /***********************************************************************
71 
72                 Performs the cipher on a block of data
73 
74                 Params:
75                 input = the block of data to cipher
76 
77                 Remarks:
78                 The actual cipher algorithm is carried out by this method on
79                 the passed block of data. This method is called for every
80                 blockSize() bytes of input data and once more with the remaining
81                 data padded to blockSize().
82 
83         ***********************************************************************/
84 
85         protected override void transform(ubyte[] input)
86         {
87                 uint a,b,c,d;
88                 uint[16] x;
89 
90                 littleEndian32(input,x);
91 
92                 a = context[0];
93                 b = context[1];
94                 c = context[2];
95                 d = context[3];
96 
97                 /* Round 1 */
98                 ff(a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
99                 ff(d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
100                 ff(c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
101                 ff(b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
102                 ff(a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
103                 ff(d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
104                 ff(c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
105                 ff(b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
106                 ff(a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
107                 ff(d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
108                 ff(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
109                 ff(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
110                 ff(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
111                 ff(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
112                 ff(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
113                 ff(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
114 
115                 /* Round 2 */
116                 gg(a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
117                 gg(d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
118                 gg(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
119                 gg(b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
120                 gg(a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
121                 gg(d, a, b, c, x[10], S22,  0x2441453); /* 22 */
122                 gg(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
123                 gg(b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
124                 gg(a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
125                 gg(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
126                 gg(c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
127                 gg(b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
128                 gg(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
129                 gg(d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
130                 gg(c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
131                 gg(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
132 
133                 /* Round 3 */
134                 hh(a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
135                 hh(d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
136                 hh(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
137                 hh(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
138                 hh(a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
139                 hh(d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
140                 hh(c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
141                 hh(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
142                 hh(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
143                 hh(d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
144                 hh(c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
145                 hh(b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
146                 hh(a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
147                 hh(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
148                 hh(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
149                 hh(b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
150 
151                 /* Round 4 */ /* Md5 not md4 */
152                 ii(a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
153                 ii(d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
154                 ii(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
155                 ii(b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
156                 ii(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
157                 ii(d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
158                 ii(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
159                 ii(b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
160                 ii(a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
161                 ii(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
162                 ii(c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
163                 ii(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
164                 ii(a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
165                 ii(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
166                 ii(c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
167                 ii(b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
168 
169                 context[0] += a;
170                 context[1] += b;
171                 context[2] += c;
172                 context[3] += d;
173 
174                 x[] = 0;
175         }
176 
177         /***********************************************************************
178 
179         ***********************************************************************/
180 
181         private static uint g(uint x, uint y, uint z)
182         {
183                 return (x&z)|(y&~z);
184         }
185 
186         /***********************************************************************
187 
188         ***********************************************************************/
189 
190         private static uint i(uint x, uint y, uint z)
191         {
192                 return y^(x|~z);
193         }
194 
195         /***********************************************************************
196 
197         ***********************************************************************/
198 
199         private static void ff(ref uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
200         {
201                 a += f(b, c, d) + x + ac;
202                 a = rotateLeft(a, s);
203                 a += b;
204         }
205 
206         /***********************************************************************
207 
208         ***********************************************************************/
209 
210         private static void gg(ref uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
211         {
212                 a += g(b, c, d) + x + ac;
213                 a = rotateLeft(a, s);
214                 a += b;
215         }
216 
217         /***********************************************************************
218 
219         ***********************************************************************/
220 
221         private static void hh(ref uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
222         {
223                 a += h(b, c, d) + x + ac;
224                 a = rotateLeft(a, s);
225                 a += b;
226         }
227 
228         /***********************************************************************
229 
230         ***********************************************************************/
231 
232         private static void ii(ref uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
233         {
234                 a += i(b, c, d) + x + ac;
235                 a = rotateLeft(a, s);
236                 a += b;
237         }
238 }
239 
240 
241 /*******************************************************************************
242 
243 *******************************************************************************/
244 
245 unittest
246 {
247     static istring[] strings =
248     [
249             "",
250             "a",
251             "abc",
252             "message digest",
253             "abcdefghijklmnopqrstuvwxyz",
254             "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
255             "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
256     ];
257 
258     static istring[] results =
259     [
260             "d41d8cd98f00b204e9800998ecf8427e",
261             "0cc175b9c0f1b6a831c399e269772661",
262             "900150983cd24fb0d6963f7d28e17f72",
263             "f96b697d7cb7938d525a2f31aaf161d0",
264             "c3fcd3d76192e4007dfb496cca67e13b",
265             "d174ab98d277d9f5a5611c2c9f419d9f",
266             "57edf4a22be3c955ac49da2e2107b67a"
267     ];
268 
269     Md5 h = new Md5();
270 
271     foreach (i, s; strings)
272     {
273         h.update(cast(ubyte[]) s);
274         char[] d = h.hexDigest;
275 
276         test(d == results[i],":("~s~")("~d~")!=("~results[i]~")");
277     }
278 }