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.transition;
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 }