comparison dcrypt/crypto/hashes/MD5.d @ 0:0e08791a1418

Initial import.
author Thomas Dixon <reikon@reikon.us>
date Sun, 10 Aug 2008 14:20:17 -0400
parents
children 71aae178f89a
comparison
equal deleted inserted replaced
-1:000000000000 0:0e08791a1418
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 }