comparison tango/tango/io/digest/Md4.d @ 132:1700239cab2e trunk

[svn r136] MAJOR UNSTABLE UPDATE!!! Initial commit after moving to Tango instead of Phobos. Lots of bugfixes... This build is not suitable for most things.
author lindquist
date Fri, 11 Jan 2008 17:57:40 +0100
parents
children
comparison
equal deleted inserted replaced
131:5825d48b27d1 132:1700239cab2e
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 MD4 Message Digest Algorithm as described
12 by RFC 1320 The MD4 Message-Digest Algorithm. R. Rivest. April 1992.
13
14 *******************************************************************************/
15
16 module tango.io.digest.Md4;
17
18 public import tango.io.digest.Digest;
19
20 private import tango.io.digest.MerkleDamgard;
21
22 /*******************************************************************************
23
24 *******************************************************************************/
25
26 class Md4 : MerkleDamgard
27 {
28 protected uint[4] context;
29 private const ubyte padChar = 0x80;
30
31 /***********************************************************************
32
33 Construct an Md4
34
35 ***********************************************************************/
36
37 this() { }
38
39 /***********************************************************************
40
41 The MD 4 digest size is 16 bytes
42
43 ***********************************************************************/
44
45 uint digestSize() { return 16; }
46
47 /***********************************************************************
48
49 Initialize the cipher
50
51 Remarks:
52 Returns the cipher state to it's initial value
53
54 ***********************************************************************/
55
56 override void reset()
57 {
58 super.reset();
59 context[] = initial[];
60 }
61
62 /***********************************************************************
63
64 Obtain the digest
65
66 Returns:
67 the digest
68
69 Remarks:
70 Returns a digest of the current cipher state, this may be the
71 final digest, or a digest of the state between calls to update()
72
73 ***********************************************************************/
74
75 override void createDigest(ubyte[] buf)
76 {
77 version (BigEndian)
78 ByteSwap.swap32 (context.ptr, context.length * uint.sizeof);
79
80 buf[] = cast(ubyte[]) context;
81 }
82
83 /***********************************************************************
84
85 block size
86
87 Returns:
88 the block size
89
90 Remarks:
91 Specifies the size (in bytes) of the block of data to pass to
92 each call to transform(). For MD4 the blockSize is 64.
93
94 ***********************************************************************/
95
96 protected override uint blockSize() { return 64; }
97
98 /***********************************************************************
99
100 Length padding size
101
102 Returns:
103 the length padding size
104
105 Remarks:
106 Specifies the size (in bytes) of the padding which uses the
107 length of the data which has been ciphered, this padding is
108 carried out by the padLength method. For MD4 the addSize is 8.
109
110 ***********************************************************************/
111
112 protected override uint addSize() { return 8; }
113
114 /***********************************************************************
115
116 Pads the cipher data
117
118 Params:
119 data = a slice of the cipher buffer to fill with padding
120
121 Remarks:
122 Fills the passed buffer slice with the appropriate padding for
123 the final call to transform(). This padding will fill the cipher
124 buffer up to blockSize()-addSize().
125
126 ***********************************************************************/
127
128 protected override void padMessage(ubyte[] data)
129 {
130 data[0] = padChar;
131 data[1..$] = 0;
132 }
133
134 /***********************************************************************
135
136 Performs the length padding
137
138 Params:
139 data = the slice of the cipher buffer to fill with padding
140 length = the length of the data which has been ciphered
141
142 Remarks:
143 Fills the passed buffer slice with addSize() bytes of padding
144 based on the length in bytes of the input data which has been
145 ciphered.
146
147 ***********************************************************************/
148
149 protected override void padLength(ubyte[] data, ulong length)
150 {
151 length <<= 3;
152 littleEndian64((cast(ubyte*)&length)[0..8],cast(ulong[]) data);
153 }
154
155 /***********************************************************************
156
157 Performs the cipher on a block of data
158
159 Params:
160 data = the block of data to cipher
161
162 Remarks:
163 The actual cipher algorithm is carried out by this method on
164 the passed block of data. This method is called for every
165 blockSize() bytes of input data and once more with the remaining
166 data padded to blockSize().
167
168 ***********************************************************************/
169
170 protected override void transform(ubyte[] input)
171 {
172 uint a,b,c,d;
173 uint[16] x;
174
175 littleEndian32(input,x);
176
177 a = context[0];
178 b = context[1];
179 c = context[2];
180 d = context[3];
181
182 /* Round 1 */
183 ff(a, b, c, d, x[ 0], S11, 0); /* 1 */
184 ff(d, a, b, c, x[ 1], S12, 0); /* 2 */
185 ff(c, d, a, b, x[ 2], S13, 0); /* 3 */
186 ff(b, c, d, a, x[ 3], S14, 0); /* 4 */
187 ff(a, b, c, d, x[ 4], S11, 0); /* 5 */
188 ff(d, a, b, c, x[ 5], S12, 0); /* 6 */
189 ff(c, d, a, b, x[ 6], S13, 0); /* 7 */
190 ff(b, c, d, a, x[ 7], S14, 0); /* 8 */
191 ff(a, b, c, d, x[ 8], S11, 0); /* 9 */
192 ff(d, a, b, c, x[ 9], S12, 0); /* 10 */
193 ff(c, d, a, b, x[10], S13, 0); /* 11 */
194 ff(b, c, d, a, x[11], S14, 0); /* 12 */
195 ff(a, b, c, d, x[12], S11, 0); /* 13 */
196 ff(d, a, b, c, x[13], S12, 0); /* 14 */
197 ff(c, d, a, b, x[14], S13, 0); /* 15 */
198 ff(b, c, d, a, x[15], S14, 0); /* 16 */
199
200 /* Round 2 */
201 gg(a, b, c, d, x[ 0], S21, 0x5a827999); /* 17 */
202 gg(d, a, b, c, x[ 4], S22, 0x5a827999); /* 18 */
203 gg(c, d, a, b, x[ 8], S23, 0x5a827999); /* 19 */
204 gg(b, c, d, a, x[12], S24, 0x5a827999); /* 20 */
205 gg(a, b, c, d, x[ 1], S21, 0x5a827999); /* 21 */
206 gg(d, a, b, c, x[ 5], S22, 0x5a827999); /* 22 */
207 gg(c, d, a, b, x[ 9], S23, 0x5a827999); /* 23 */
208 gg(b, c, d, a, x[13], S24, 0x5a827999); /* 24 */
209 gg(a, b, c, d, x[ 2], S21, 0x5a827999); /* 25 */
210 gg(d, a, b, c, x[ 6], S22, 0x5a827999); /* 26 */
211 gg(c, d, a, b, x[10], S23, 0x5a827999); /* 27 */
212 gg(b, c, d, a, x[14], S24, 0x5a827999); /* 28 */
213 gg(a, b, c, d, x[ 3], S21, 0x5a827999); /* 29 */
214 gg(d, a, b, c, x[ 7], S22, 0x5a827999); /* 30 */
215 gg(c, d, a, b, x[11], S23, 0x5a827999); /* 31 */
216 gg(b, c, d, a, x[15], S24, 0x5a827999); /* 32 */
217
218 /* Round 3 */
219 hh(a, b, c, d, x[ 0], S31, 0x6ed9eba1); /* 33 */
220 hh(d, a, b, c, x[ 8], S32, 0x6ed9eba1); /* 34 */
221 hh(c, d, a, b, x[ 4], S33, 0x6ed9eba1); /* 35 */
222 hh(b, c, d, a, x[12], S34, 0x6ed9eba1); /* 36 */
223 hh(a, b, c, d, x[ 2], S31, 0x6ed9eba1); /* 37 */
224 hh(d, a, b, c, x[10], S32, 0x6ed9eba1); /* 38 */
225 hh(c, d, a, b, x[ 6], S33, 0x6ed9eba1); /* 39 */
226 hh(b, c, d, a, x[14], S34, 0x6ed9eba1); /* 40 */
227 hh(a, b, c, d, x[ 1], S31, 0x6ed9eba1); /* 41 */
228 hh(d, a, b, c, x[ 9], S32, 0x6ed9eba1); /* 42 */
229 hh(c, d, a, b, x[ 5], S33, 0x6ed9eba1); /* 43 */
230 hh(b, c, d, a, x[13], S34, 0x6ed9eba1); /* 44 */
231 hh(a, b, c, d, x[ 3], S31, 0x6ed9eba1); /* 45 */
232 hh(d, a, b, c, x[11], S32, 0x6ed9eba1); /* 46 */
233 hh(c, d, a, b, x[ 7], S33, 0x6ed9eba1); /* 47 */
234 hh(b, c, d, a, x[15], S34, 0x6ed9eba1); /* 48 */
235
236 context[0] += a;
237 context[1] += b;
238 context[2] += c;
239 context[3] += d;
240
241 x[] = 0;
242 }
243
244 /***********************************************************************
245
246 ***********************************************************************/
247
248 protected static uint f(uint x, uint y, uint z)
249 {
250 return (x&y)|(~x&z);
251 }
252
253 /***********************************************************************
254
255 ***********************************************************************/
256
257 protected static uint h(uint x, uint y, uint z)
258 {
259 return x^y^z;
260 }
261
262 /***********************************************************************
263
264 ***********************************************************************/
265
266 private static uint g(uint x, uint y, uint z)
267 {
268 return (x&y)|(x&z)|(y&z);
269 }
270
271 /***********************************************************************
272
273 ***********************************************************************/
274
275 private static void ff(inout uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
276 {
277 a += f(b, c, d) + x + ac;
278 a = rotateLeft(a, s);
279 }
280
281 /***********************************************************************
282
283 ***********************************************************************/
284
285 private static void gg(inout uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
286 {
287 a += g(b, c, d) + x + ac;
288 a = rotateLeft(a, s);
289 }
290
291 /***********************************************************************
292
293 ***********************************************************************/
294
295 private static void hh(inout uint a, uint b, uint c, uint d, uint x, uint s, uint ac)
296 {
297 a += h(b, c, d) + x + ac;
298 a = rotateLeft(a, s);
299 }
300
301 /***********************************************************************
302
303 ***********************************************************************/
304
305 private static const uint[4] initial =
306 [
307 0x67452301,
308 0xefcdab89,
309 0x98badcfe,
310 0x10325476
311 ];
312
313 /***********************************************************************
314
315 ***********************************************************************/
316
317 private static enum
318 {
319 S11 = 3,
320 S12 = 7,
321 S13 = 11,
322 S14 = 19,
323 S21 = 3,
324 S22 = 5,
325 S23 = 9,
326 S24 = 13,
327 S31 = 3,
328 S32 = 9,
329 S33 = 11,
330 S34 = 15,
331 }
332 }
333
334
335 /*******************************************************************************
336
337 *******************************************************************************/
338
339 version (UnitTest)
340 {
341 unittest
342 {
343 static char[][] strings =
344 [
345 "",
346 "a",
347 "abc",
348 "message digest",
349 "abcdefghijklmnopqrstuvwxyz",
350 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
351 "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
352 ];
353
354 static char[][] results =
355 [
356 "31d6cfe0d16ae931b73c59d7e0c089c0",
357 "bde52cb31de33e46245e05fbdbd6fb24",
358 "a448017aaf21d8525fc10ae87aa6729d",
359 "d9130a8164549fe818874806e1c7014b",
360 "d79e1c308aa5bbcdeea8ed63df412da9",
361 "043f8582f241db351ce627e153e7f0e4",
362 "e33b4ddc9c38f2199c3e7b164fcc0536"
363 ];
364
365 Md4 h = new Md4();
366
367 foreach (int i, char[] s; strings)
368 {
369 h.update(s);
370 char[] d = h.hexDigest;
371 assert(d == results[i],":("~s~")("~d~")!=("~results[i]~")");
372 }
373 }
374 }
375