Mercurial > projects > dcrypt
comparison dcrypt/crypto/hashes/MD4.d @ 27:8b5eaf3c2979
Fixed error in hash message padding reported by Glenn Haecker.
author | Thomas Dixon <reikon@reikon.us> |
---|---|
date | Sat, 09 May 2009 23:29:20 -0400 |
parents | 176c933827a8 |
children | ad687db713a4 |
comparison
equal
deleted
inserted
replaced
26:176c933827a8 | 27:8b5eaf3c2979 |
---|---|
15 * | 15 * |
16 * Conforms: RFC 1320 | 16 * Conforms: RFC 1320 |
17 * References: http://www.faqs.org/rfcs/rfc1320.html | 17 * References: http://www.faqs.org/rfcs/rfc1320.html |
18 * Bugs: MD4 is not cryptographically secure. | 18 * Bugs: MD4 is not cryptographically secure. |
19 */ | 19 */ |
20 class MD4 : Hash { | 20 class MD4 : Hash |
21 { | |
21 private uint h0, h1, h2, h3; | 22 private uint h0, h1, h2, h3; |
22 | 23 |
23 // Shift amounts | 24 // Shift amounts |
24 private enum { | 25 private enum |
26 { | |
25 S11 = 3, | 27 S11 = 3, |
26 S12 = 7, | 28 S12 = 7, |
27 S13 = 11, | 29 S13 = 11, |
28 S14 = 19, | 30 S14 = 19, |
29 | 31 |
36 S32 = 9, | 38 S32 = 9, |
37 S33 = 11, | 39 S33 = 11, |
38 S34 = 15 | 40 S34 = 15 |
39 }; | 41 }; |
40 | 42 |
41 this (void[] input_=null) { | 43 this (void[] input_=null) |
44 { | |
42 reset(); | 45 reset(); |
43 super(input_); | 46 super(input_); |
44 } | 47 } |
45 | 48 |
46 uint blockSize() { | 49 uint blockSize() |
50 { | |
47 return 64; | 51 return 64; |
48 } | 52 } |
49 | 53 |
50 uint digestSize() { | 54 uint digestSize() |
55 { | |
51 return 16; | 56 return 16; |
52 } | 57 } |
53 | 58 |
54 char[] name() { | 59 char[] name() |
60 { | |
55 return "MD4"; | 61 return "MD4"; |
56 } | 62 } |
57 | 63 |
58 void transform(ubyte[] input) { | 64 void transform(ubyte[] input) |
65 { | |
59 uint[] w = new uint[16]; | 66 uint[] w = new uint[16]; |
60 | 67 |
61 for (int i = 0, j = 0; i < 16; i++,j+=int.sizeof) | 68 for (int i = 0, j = 0; i < 16; i++,j+=int.sizeof) |
62 w[i] = ByteConverter.LittleEndian.to!(uint)(input[j..j+int.sizeof]); | 69 w[i] = ByteConverter.LittleEndian.to!(uint)(input[j..j+int.sizeof]); |
63 | 70 |
124 h1 += b; | 131 h1 += b; |
125 h2 += c; | 132 h2 += c; |
126 h3 += d; | 133 h3 += d; |
127 } | 134 } |
128 | 135 |
129 private uint f(uint x, uint y, uint z) { | 136 private uint f(uint x, uint y, uint z) |
137 { | |
130 return (x&y)|(~x&z); | 138 return (x&y)|(~x&z); |
131 } | 139 } |
132 | 140 |
133 private uint h(uint x, uint y, uint z) { | 141 private uint h(uint x, uint y, uint z) |
142 { | |
134 return x^y^z; | 143 return x^y^z; |
135 } | 144 } |
136 | 145 |
137 private uint g(uint x, uint y, uint z) { | 146 private uint g(uint x, uint y, uint z) |
147 { | |
138 return (x&y)|(x&z)|(y&z); | 148 return (x&y)|(x&z)|(y&z); |
139 } | 149 } |
140 | 150 |
141 private void ff(ref uint a, uint b, uint c, uint d, uint x, uint s) { | 151 private void ff(ref uint a, uint b, uint c, uint d, uint x, uint s) |
152 { | |
142 a += f(b, c, d) + x; | 153 a += f(b, c, d) + x; |
143 a = Bitwise.rotateLeft(a, s); | 154 a = Bitwise.rotateLeft(a, s); |
144 } | 155 } |
145 | 156 |
146 private void gg(ref uint a, uint b, uint c, uint d, uint x, uint s) { | 157 private void gg(ref uint a, uint b, uint c, uint d, uint x, uint s) |
158 { | |
147 a += g(b, c, d) + x + 0x5a827999u; | 159 a += g(b, c, d) + x + 0x5a827999u; |
148 a = Bitwise.rotateLeft(a, s); | 160 a = Bitwise.rotateLeft(a, s); |
149 } | 161 } |
150 | 162 |
151 private void hh(ref uint a, uint b, uint c, uint d, uint x, uint s) { | 163 private void hh(ref uint a, uint b, uint c, uint d, uint x, uint s) |
164 { | |
152 a += h(b, c, d) + x + 0x6ed9eba1u; | 165 a += h(b, c, d) + x + 0x6ed9eba1u; |
153 a = Bitwise.rotateLeft(a, s); | 166 a = Bitwise.rotateLeft(a, s); |
154 } | 167 } |
155 | 168 |
156 ubyte[] digest() { | 169 ubyte[] digest() |
170 { | |
157 padMessage(MODE_MD); | 171 padMessage(MODE_MD); |
158 ubyte[] result = new ubyte[digestSize]; | 172 ubyte[] result = new ubyte[digestSize]; |
159 | 173 |
160 result[0..4] = ByteConverter.LittleEndian.from!(uint)(h0); | 174 result[0..4] = ByteConverter.LittleEndian.from!(uint)(h0); |
161 result[4..8] = ByteConverter.LittleEndian.from!(uint)(h1); | 175 result[4..8] = ByteConverter.LittleEndian.from!(uint)(h1); |
164 | 178 |
165 reset(); | 179 reset(); |
166 return result; | 180 return result; |
167 } | 181 } |
168 | 182 |
169 void reset() { | 183 void reset() |
184 { | |
170 super.reset(); | 185 super.reset(); |
171 h0 = 0x67452301u; | 186 h0 = 0x67452301u; |
172 h1 = 0xefcdab89u; | 187 h1 = 0xefcdab89u; |
173 h2 = 0x98badcfeu; | 188 h2 = 0x98badcfeu; |
174 h3 = 0x10325476u; | 189 h3 = 0x10325476u; |
175 } | 190 } |
176 | 191 |
177 MD4 copy() { | 192 MD4 copy() |
193 { | |
178 MD4 h = new MD4(buffer[0..index]); | 194 MD4 h = new MD4(buffer[0..index]); |
179 h.bytes = bytes; | 195 h.bytes = bytes; |
180 h.h0 = h0; | 196 h.h0 = h0; |
181 h.h1 = h1; | 197 h.h1 = h1; |
182 h.h2 = h2; | 198 h.h2 = h2; |
183 h.h3 = h3; | 199 h.h3 = h3; |
184 return h; | 200 return h; |
185 } | 201 } |
186 | 202 |
187 debug (UnitTest) { | 203 debug (UnitTest) |
204 { | |
188 // Found in Tango <3 | 205 // Found in Tango <3 |
189 unittest { | 206 unittest |
207 { | |
190 static const char[][] test_inputs = [ | 208 static const char[][] test_inputs = [ |
191 "", | 209 "", |
192 "a", | 210 "a", |
193 "abc", | 211 "abc", |
194 "message digest", | 212 "message digest", |
206 "043f8582f241db351ce627e153e7f0e4", | 224 "043f8582f241db351ce627e153e7f0e4", |
207 "e33b4ddc9c38f2199c3e7b164fcc0536" | 225 "e33b4ddc9c38f2199c3e7b164fcc0536" |
208 ]; | 226 ]; |
209 | 227 |
210 MD4 h = new MD4(); | 228 MD4 h = new MD4(); |
211 foreach (uint i, char[] input; test_inputs) { | 229 foreach (uint i, char[] input; test_inputs) |
230 { | |
212 h.update(input); | 231 h.update(input); |
213 char[] digest = h.hexDigest(); | 232 char[] digest = h.hexDigest(); |
214 assert(digest == test_results[i], | 233 assert(digest == test_results[i], |
215 h.name~": ("~digest~") != ("~test_results[i]~")"); | 234 h.name~": ("~digest~") != ("~test_results[i]~")"); |
216 } | 235 } |