0
|
1 /**
|
|
2 * This file is part of the dcrypt project.
|
|
3 *
|
|
4 * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved.
|
|
5 * License: MIT
|
|
6 * Authors: Thomas Dixon
|
|
7 */
|
|
8
|
|
9 module dcrypt.crypto.hashes.MD5;
|
|
10
|
|
11 public import dcrypt.crypto.Hash;
|
|
12
|
|
13 /** Implementation of Ron Rivest's MD5. */
|
|
14 class MD5 : Hash {
|
|
15 private uint h0, h1, h2, h3;
|
|
16
|
|
17 // Shift amounts
|
|
18 private enum {
|
|
19 S11 = 7,
|
|
20 S12 = 12,
|
|
21 S13 = 17,
|
|
22 S14 = 22,
|
|
23
|
|
24 S21 = 5,
|
|
25 S22 = 9,
|
|
26 S23 = 14,
|
|
27 S24 = 20,
|
|
28
|
|
29 S31 = 4,
|
|
30 S32 = 11,
|
|
31 S33 = 16,
|
|
32 S34 = 23,
|
|
33
|
|
34 S41 = 6,
|
|
35 S42 = 10,
|
|
36 S43 = 15,
|
|
37 S44 = 21
|
|
38 };
|
|
39
|
|
40 this (void[] input_=null) {
|
|
41 reset();
|
|
42 super(input_);
|
|
43 }
|
|
44
|
|
45 uint blockSize() {
|
|
46 return 64;
|
|
47 }
|
|
48
|
|
49 uint digestSize() {
|
|
50 return 16;
|
|
51 }
|
|
52
|
|
53 char[] name() {
|
|
54 return "MD5";
|
|
55 }
|
|
56
|
|
57 void transform(ubyte[] input) {
|
|
58 uint[] w = new uint[16];
|
|
59
|
|
60 for (int i = 0, j = 0; i < 16; i++,j+=4)
|
|
61 w[i] = Util.ubytesToUintLittle(input, j);
|
|
62
|
|
63 uint a = h0,
|
|
64 b = h1,
|
|
65 c = h2,
|
|
66 d = h3;
|
|
67
|
|
68 // Round 1 -- FIGHT!
|
|
69 ff(a, b, c, d, w[ 0], S11, 3614090360); /* 1 */
|
|
70 ff(d, a, b, c, w[ 1], S12, 3905402710); /* 2 */
|
|
71 ff(c, d, a, b, w[ 2], S13, 606105819); /* 3 */
|
|
72 ff(b, c, d, a, w[ 3], S14, 3250441966); /* 4 */
|
|
73 ff(a, b, c, d, w[ 4], S11, 4118548399); /* 5 */
|
|
74 ff(d, a, b, c, w[ 5], S12, 1200080426); /* 6 */
|
|
75 ff(c, d, a, b, w[ 6], S13, 2821735955); /* 7 */
|
|
76 ff(b, c, d, a, w[ 7], S14, 4249261313); /* 8 */
|
|
77 ff(a, b, c, d, w[ 8], S11, 1770035416); /* 9 */
|
|
78 ff(d, a, b, c, w[ 9], S12, 2336552879); /* 10 */
|
|
79 ff(c, d, a, b, w[10], S13, 4294925233); /* 11 */
|
|
80 ff(b, c, d, a, w[11], S14, 2304563134); /* 12 */
|
|
81 ff(a, b, c, d, w[12], S11, 1804603682); /* 13 */
|
|
82 ff(d, a, b, c, w[13], S12, 4254626195); /* 14 */
|
|
83 ff(c, d, a, b, w[14], S13, 2792965006); /* 15 */
|
|
84 ff(b, c, d, a, w[15], S14, 1236535329); /* 16 */
|
|
85
|
|
86 // Round 2
|
|
87 gg(a, b, c, d, w[ 1], S21, 4129170786); /* 17 */
|
|
88 gg(d, a, b, c, w[ 6], S22, 3225465664); /* 18 */
|
|
89 gg(c, d, a, b, w[11], S23, 643717713); /* 19 */
|
|
90 gg(b, c, d, a, w[ 0], S24, 3921069994); /* 20 */
|
|
91 gg(a, b, c, d, w[ 5], S21, 3593408605); /* 21 */
|
|
92 gg(d, a, b, c, w[10], S22, 38016083); /* 22 */
|
|
93 gg(c, d, a, b, w[15], S23, 3634488961); /* 23 */
|
|
94 gg(b, c, d, a, w[ 4], S24, 3889429448); /* 24 */
|
|
95 gg(a, b, c, d, w[ 9], S21, 568446438); /* 25 */
|
|
96 gg(d, a, b, c, w[14], S22, 3275163606); /* 26 */
|
|
97 gg(c, d, a, b, w[ 3], S23, 4107603335); /* 27 */
|
|
98 gg(b, c, d, a, w[ 8], S24, 1163531501); /* 28 */
|
|
99 gg(a, b, c, d, w[13], S21, 2850285829); /* 29 */
|
|
100 gg(d, a, b, c, w[ 2], S22, 4243563512); /* 30 */
|
|
101 gg(c, d, a, b, w[ 7], S23, 1735328473); /* 31 */
|
|
102 gg(b, c, d, a, w[12], S24, 2368359562); /* 32 */
|
|
103
|
|
104 // Round 3
|
|
105 hh(a, b, c, d, w[ 5], S31, 4294588738); /* 33 */
|
|
106 hh(d, a, b, c, w[ 8], S32, 2272392833); /* 34 */
|
|
107 hh(c, d, a, b, w[11], S33, 1839030562); /* 35 */
|
|
108 hh(b, c, d, a, w[14], S34, 4259657740); /* 36 */
|
|
109 hh(a, b, c, d, w[ 1], S31, 2763975236); /* 37 */
|
|
110 hh(d, a, b, c, w[ 4], S32, 1272893353); /* 38 */
|
|
111 hh(c, d, a, b, w[ 7], S33, 4139469664); /* 39 */
|
|
112 hh(b, c, d, a, w[10], S34, 3200236656); /* 40 */
|
|
113 hh(a, b, c, d, w[13], S31, 681279174); /* 41 */
|
|
114 hh(d, a, b, c, w[ 0], S32, 3936430074); /* 42 */
|
|
115 hh(c, d, a, b, w[ 3], S33, 3572445317); /* 43 */
|
|
116 hh(b, c, d, a, w[ 6], S34, 76029189); /* 44 */
|
|
117 hh(a, b, c, d, w[ 9], S31, 3654602809); /* 45 */
|
|
118 hh(d, a, b, c, w[12], S32, 3873151461); /* 46 */
|
|
119 hh(c, d, a, b, w[15], S33, 530742520); /* 47 */
|
|
120 hh(b, c, d, a, w[ 2], S34, 3299628645); /* 48 */
|
|
121
|
|
122 // Round 4
|
|
123 ii(a, b, c, d, w[ 0], S41, 4096336452); /* 49 */
|
|
124 ii(d, a, b, c, w[ 7], S42, 1126891415); /* 50 */
|
|
125 ii(c, d, a, b, w[14], S43, 2878612391); /* 51 */
|
|
126 ii(b, c, d, a, w[ 5], S44, 4237533241); /* 52 */
|
|
127 ii(a, b, c, d, w[12], S41, 1700485571); /* 53 */
|
|
128 ii(d, a, b, c, w[ 3], S42, 2399980690); /* 54 */
|
|
129 ii(c, d, a, b, w[10], S43, 4293915773); /* 55 */
|
|
130 ii(b, c, d, a, w[ 1], S44, 2240044497); /* 56 */
|
|
131 ii(a, b, c, d, w[ 8], S41, 1873313359); /* 57 */
|
|
132 ii(d, a, b, c, w[15], S42, 4264355552); /* 58 */
|
|
133 ii(c, d, a, b, w[ 6], S43, 2734768916); /* 59 */
|
|
134 ii(b, c, d, a, w[13], S44, 1309151649); /* 60 */
|
|
135 ii(a, b, c, d, w[ 4], S41, 4149444226); /* 61 */
|
|
136 ii(d, a, b, c, w[11], S42, 3174756917); /* 62 */
|
|
137 ii(c, d, a, b, w[ 2], S43, 718787259); /* 63 */
|
|
138 ii(b, c, d, a, w[ 9], S44, 3951481745); /* 64 */
|
|
139
|
|
140 // FINISH HIM!
|
|
141 h0 += a;
|
|
142 h1 += b;
|
|
143 h2 += c;
|
|
144 h3 += d;
|
|
145 // FATALITY! MD5 Wins. \o/ ('cept not because it's insecure, but whatev)
|
|
146 }
|
|
147
|
|
148 private uint f(uint x, uint y, uint z) {
|
|
149 return (x&y)|(~x&z);
|
|
150 }
|
|
151
|
|
152 private uint h(uint x, uint y, uint z) {
|
|
153 return x^y^z;
|
|
154 }
|
|
155
|
|
156 private uint g(uint x, uint y, uint z) {
|
|
157 return (x&z)|(y&~z);
|
|
158 }
|
|
159
|
|
160 private uint i(uint x, uint y, uint z) {
|
|
161 return y^(x|~z);
|
|
162 }
|
|
163
|
|
164 private void ff(ref uint a, uint b, uint c,
|
|
165 uint d, uint x, uint s, uint ac) {
|
|
166 a += f(b, c, d) + x + ac;
|
|
167 a = Util.rotateLeft(a, s);
|
|
168 a += b;
|
|
169 }
|
|
170
|
|
171 private void gg(ref uint a, uint b, uint c,
|
|
172 uint d, uint x, uint s, uint ac) {
|
|
173 a += g(b, c, d) + x + ac;
|
|
174 a = Util.rotateLeft(a, s);
|
|
175 a += b;
|
|
176 }
|
|
177
|
|
178 private void hh(ref uint a, uint b, uint c,
|
|
179 uint d, uint x, uint s, uint ac) {
|
|
180 a += h(b, c, d) + x + ac;
|
|
181 a = Util.rotateLeft(a, s);
|
|
182 a += b;
|
|
183 }
|
|
184
|
|
185 private void ii(ref uint a, uint b, uint c,
|
|
186 uint d, uint x, uint s, uint ac) {
|
|
187 a += i(b, c, d) + x + ac;
|
|
188 a = Util.rotateLeft(a, s);
|
|
189 a += b;
|
|
190 }
|
|
191
|
|
192 ubyte[] digest() {
|
|
193 padMessage(MODE_MD);
|
|
194 ubyte[] result = new ubyte[digestSize];
|
|
195
|
|
196 Util.uintToUbytesLittle(h0, result, 0);
|
|
197 Util.uintToUbytesLittle(h1, result, 4);
|
|
198 Util.uintToUbytesLittle(h2, result, 8);
|
|
199 Util.uintToUbytesLittle(h3, result, 12);
|
|
200
|
|
201 reset();
|
|
202 return result;
|
|
203 }
|
|
204
|
|
205 void reset() {
|
|
206 super.reset();
|
|
207 h0 = 0x67452301u,
|
|
208 h1 = 0xefcdab89u,
|
|
209 h2 = 0x98badcfeu,
|
|
210 h3 = 0x10325476u;
|
|
211 }
|
|
212
|
|
213 version (UnitTest) {
|
|
214 // Found in Tango <3
|
|
215 unittest {
|
|
216 static const char[][] test_inputs = [
|
|
217 "",
|
|
218 "a",
|
|
219 "abc",
|
|
220 "message digest",
|
|
221 "abcdefghijklmnopqrstuvwxyz",
|
|
222 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
|
|
223 "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
|
|
224 ];
|
|
225
|
|
226 static const char[][] test_results = [
|
|
227 "d41d8cd98f00b204e9800998ecf8427e",
|
|
228 "0cc175b9c0f1b6a831c399e269772661",
|
|
229 "900150983cd24fb0d6963f7d28e17f72",
|
|
230 "f96b697d7cb7938d525a2f31aaf161d0",
|
|
231 "c3fcd3d76192e4007dfb496cca67e13b",
|
|
232 "d174ab98d277d9f5a5611c2c9f419d9f",
|
|
233 "57edf4a22be3c955ac49da2e2107b67a"
|
|
234 ];
|
|
235
|
|
236 MD5 h = new MD5();
|
|
237 foreach (uint i, char[] input; test_inputs) {
|
|
238 h.update(input);
|
|
239 char[] digest = h.hexDigest();
|
|
240 assert(digest == test_results[i],
|
|
241 h.name()~": ("~digest~") != ("~test_results[i]~")");
|
|
242 }
|
|
243 }
|
|
244 }
|
|
245 }
|