comparison dcrypt/crypto/hashes/MD4.d @ 26:176c933827a8

Implemented MD4. Refactored MD5. Replaced all instances of 'version (UnitTest)' with 'debug (UnitTest)'.
author Thomas Dixon <reikon@reikon.us>
date Sun, 01 Mar 2009 13:06:48 -0500
parents
children 8b5eaf3c2979
comparison
equal deleted inserted replaced
25:528676d20398 26:176c933827a8
1 /**
2 * This file is part of the dcrypt project.
3 *
4 * Copyright: Copyright (C) dcrypt contributors 2009. All rights reserved.
5 * License: MIT
6 * Authors: Thomas Dixon
7 */
8
9 module dcrypt.crypto.hashes.MD4;
10
11 public import dcrypt.crypto.Hash;
12
13 /**
14 * Implementation of Ron Rivest's MD4.
15 *
16 * Conforms: RFC 1320
17 * References: http://www.faqs.org/rfcs/rfc1320.html
18 * Bugs: MD4 is not cryptographically secure.
19 */
20 class MD4 : Hash {
21 private uint h0, h1, h2, h3;
22
23 // Shift amounts
24 private enum {
25 S11 = 3,
26 S12 = 7,
27 S13 = 11,
28 S14 = 19,
29
30 S21 = 3,
31 S22 = 5,
32 S23 = 9,
33 S24 = 13,
34
35 S31 = 3,
36 S32 = 9,
37 S33 = 11,
38 S34 = 15
39 };
40
41 this (void[] input_=null) {
42 reset();
43 super(input_);
44 }
45
46 uint blockSize() {
47 return 64;
48 }
49
50 uint digestSize() {
51 return 16;
52 }
53
54 char[] name() {
55 return "MD4";
56 }
57
58 void transform(ubyte[] input) {
59 uint[] w = new uint[16];
60
61 for (int i = 0, j = 0; i < 16; i++,j+=int.sizeof)
62 w[i] = ByteConverter.LittleEndian.to!(uint)(input[j..j+int.sizeof]);
63
64 uint a = h0,
65 b = h1,
66 c = h2,
67 d = h3;
68
69 // Round 1
70 ff(a, b, c, d, w[ 0], S11);
71 ff(d, a, b, c, w[ 1], S12);
72 ff(c, d, a, b, w[ 2], S13);
73 ff(b, c, d, a, w[ 3], S14);
74 ff(a, b, c, d, w[ 4], S11);
75 ff(d, a, b, c, w[ 5], S12);
76 ff(c, d, a, b, w[ 6], S13);
77 ff(b, c, d, a, w[ 7], S14);
78 ff(a, b, c, d, w[ 8], S11);
79 ff(d, a, b, c, w[ 9], S12);
80 ff(c, d, a, b, w[10], S13);
81 ff(b, c, d, a, w[11], S14);
82 ff(a, b, c, d, w[12], S11);
83 ff(d, a, b, c, w[13], S12);
84 ff(c, d, a, b, w[14], S13);
85 ff(b, c, d, a, w[15], S14);
86
87 // Round 2
88 gg(a, b, c, d, w[ 0], S21);
89 gg(d, a, b, c, w[ 4], S22);
90 gg(c, d, a, b, w[ 8], S23);
91 gg(b, c, d, a, w[12], S24);
92 gg(a, b, c, d, w[ 1], S21);
93 gg(d, a, b, c, w[ 5], S22);
94 gg(c, d, a, b, w[ 9], S23);
95 gg(b, c, d, a, w[13], S24);
96 gg(a, b, c, d, w[ 2], S21);
97 gg(d, a, b, c, w[ 6], S22);
98 gg(c, d, a, b, w[10], S23);
99 gg(b, c, d, a, w[14], S24);
100 gg(a, b, c, d, w[ 3], S21);
101 gg(d, a, b, c, w[ 7], S22);
102 gg(c, d, a, b, w[11], S23);
103 gg(b, c, d, a, w[15], S24);
104
105 // Round 3
106 hh(a, b, c, d, w[ 0], S31);
107 hh(d, a, b, c, w[ 8], S32);
108 hh(c, d, a, b, w[ 4], S33);
109 hh(b, c, d, a, w[12], S34);
110 hh(a, b, c, d, w[ 2], S31);
111 hh(d, a, b, c, w[10], S32);
112 hh(c, d, a, b, w[ 6], S33);
113 hh(b, c, d, a, w[14], S34);
114 hh(a, b, c, d, w[ 1], S31);
115 hh(d, a, b, c, w[ 9], S32);
116 hh(c, d, a, b, w[ 5], S33);
117 hh(b, c, d, a, w[13], S34);
118 hh(a, b, c, d, w[ 3], S31);
119 hh(d, a, b, c, w[11], S32);
120 hh(c, d, a, b, w[ 7], S33);
121 hh(b, c, d, a, w[15], S34);
122
123 h0 += a;
124 h1 += b;
125 h2 += c;
126 h3 += d;
127 }
128
129 private uint f(uint x, uint y, uint z) {
130 return (x&y)|(~x&z);
131 }
132
133 private uint h(uint x, uint y, uint z) {
134 return x^y^z;
135 }
136
137 private uint g(uint x, uint y, uint z) {
138 return (x&y)|(x&z)|(y&z);
139 }
140
141 private void ff(ref uint a, uint b, uint c, uint d, uint x, uint s) {
142 a += f(b, c, d) + x;
143 a = Bitwise.rotateLeft(a, s);
144 }
145
146 private void gg(ref uint a, uint b, uint c, uint d, uint x, uint s) {
147 a += g(b, c, d) + x + 0x5a827999u;
148 a = Bitwise.rotateLeft(a, s);
149 }
150
151 private void hh(ref uint a, uint b, uint c, uint d, uint x, uint s) {
152 a += h(b, c, d) + x + 0x6ed9eba1u;
153 a = Bitwise.rotateLeft(a, s);
154 }
155
156 ubyte[] digest() {
157 padMessage(MODE_MD);
158 ubyte[] result = new ubyte[digestSize];
159
160 result[0..4] = ByteConverter.LittleEndian.from!(uint)(h0);
161 result[4..8] = ByteConverter.LittleEndian.from!(uint)(h1);
162 result[8..12] = ByteConverter.LittleEndian.from!(uint)(h2);
163 result[12..16] = ByteConverter.LittleEndian.from!(uint)(h3);
164
165 reset();
166 return result;
167 }
168
169 void reset() {
170 super.reset();
171 h0 = 0x67452301u;
172 h1 = 0xefcdab89u;
173 h2 = 0x98badcfeu;
174 h3 = 0x10325476u;
175 }
176
177 MD4 copy() {
178 MD4 h = new MD4(buffer[0..index]);
179 h.bytes = bytes;
180 h.h0 = h0;
181 h.h1 = h1;
182 h.h2 = h2;
183 h.h3 = h3;
184 return h;
185 }
186
187 debug (UnitTest) {
188 // Found in Tango <3
189 unittest {
190 static const char[][] test_inputs = [
191 "",
192 "a",
193 "abc",
194 "message digest",
195 "abcdefghijklmnopqrstuvwxyz",
196 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
197 "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
198 ];
199
200 static const char[][] test_results = [
201 "31d6cfe0d16ae931b73c59d7e0c089c0",
202 "bde52cb31de33e46245e05fbdbd6fb24",
203 "a448017aaf21d8525fc10ae87aa6729d",
204 "d9130a8164549fe818874806e1c7014b",
205 "d79e1c308aa5bbcdeea8ed63df412da9",
206 "043f8582f241db351ce627e153e7f0e4",
207 "e33b4ddc9c38f2199c3e7b164fcc0536"
208 ];
209
210 MD4 h = new MD4();
211 foreach (uint i, char[] input; test_inputs) {
212 h.update(input);
213 char[] digest = h.hexDigest();
214 assert(digest == test_results[i],
215 h.name~": ("~digest~") != ("~test_results[i]~")");
216 }
217 }
218 }
219 }