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