Upstream tarball 9630
[amule.git] / src / utils / aLinkCreator / src / md4.cpp
blob1a16f3046bb966b2ec154e0ebc782204185d2a27
1 ////////////////////////////////////////////////////////////////////////////////
2 /// Name: MD4 Class
3 ///
4 /// Purpose: aMule ed2k link creator
5 ///
6 /// Last modified by: ThePolish <thepolish@vipmail.ru>
7 ///
8 /// Copyright (c) 2004-2008 ThePolish ( thepolish@vipmail.ru )
9 ///
10 /// Copyright (c) 2004-2008 Marcelo Roberto Jimenez ( phoenix@amule.org )
11 ///
12 /// Copyright (c) 2004-2008 Alo Sarv ( madcat_@users.sourceforge.net )
13 ///
14 /// Copyright (c) 2002-2008 Michael Buesch
15 /// Email: mbuesch@freenet.de
16 ///
17 /// The algorithm is due to Ron Rivest. This code is based on code
18 /// written by Colin Plumb in 1993.
19 ///
20 /// This code implements the MD4 message-digest algorithm.
21 ///
22 /// This program is free software; you can redistribute it and/or modify
23 /// it under the terms of the GNU General Public License as published by
24 /// the Free Software Foundation; either version 2 of the License, or
25 /// (at your option) any later version.
26 ///
27 /// This program is distributed in the hope that it will be useful,
28 /// but WITHOUT ANY WARRANTY; without even the implied warranty of
29 /// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 /// GNU General Public License for more details.
31 ///
32 /// You should have received a copy of the GNU General Public License
33 /// along with this program; if not, write to the
34 /// Free Software Foundation, Inc.,
35 /// 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
36 ////////////////////////////////////////////////////////////////////////////////
39 #ifdef __BORLANDC__
40 #pragma hdrstop
41 #endif
43 // For all others, include the necessary headers
44 #ifndef WX_PRECOMP
45 #include "wx/wx.h"
46 #endif
48 #include <wx/ffile.h>
50 #include "md4.h"
51 #include "bithelp.h"
54 /// BIG ENDIAN byte reversing
55 #if wxBYTE_ORDER == wxBIG_ENDIAN
56 // Note: this code is harmless on little-endian machines.
57 void MD4::byteReverse(unsigned char *buf, unsigned longs)
59 uint32_t t;
62 t = (uint32_t) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
63 ((unsigned) buf[1] << 8 | buf[0]);
64 *(uint32_t *) buf = t;
65 buf += 4;
67 while (--longs);
69 #else
70 #define byteReverse(buf, len) do { } while (0)
71 #endif
73 /// Start MD4 accumulation.
74 /// Set bit count to 0 and buffer to mysteriousinitialization constants.
75 void MD4::MD4Init(struct MD4Context *ctx)
77 ctx->buf[0] = 0x67452301;
78 ctx->buf[1] = 0xefcdab89;
79 ctx->buf[2] = 0x98badcfe;
80 ctx->buf[3] = 0x10325476;
81 ctx->bits[0] = 0;
82 ctx->bits[1] = 0;
85 /// Update context to reflect the concatenation of another buffer full of bytes.
86 void MD4::MD4Update(struct MD4Context *ctx, unsigned char const *buf,
87 size_t len)
89 register uint32_t t;
91 // Update bitcount
92 t = ctx->bits[0];
93 if ((ctx->bits[0] = t + ((uint32_t) len << 3)) < t)
94 ctx->bits[1]++; // Carry from low to high
95 ctx->bits[1] += len >> 29;
97 t = (t >> 3) & 0x3f; // Bytes already in shsInfo->data
99 // Handle any leading odd-sized chunks
100 if (t)
102 unsigned char *p = (unsigned char *) ctx->in + t;
104 t = 64 - t;
105 if (len < t)
107 memcpy(p, buf, len);
108 return;
110 memcpy(p, buf, t);
111 byteReverse(ctx->in, 16);
112 MD4Transform(ctx->buf, (uint32_t *) ctx->in);
113 buf += t;
114 len -= t;
117 // Process data in 64-byte chunks
118 while (len >= 64)
120 memcpy(ctx->in, buf, 64);
121 byteReverse(ctx->in, 16);
122 MD4Transform(ctx->buf, (uint32_t *) ctx->in);
123 buf += 64;
124 len -= 64;
127 //Handle any remaining bytes of data.
128 memcpy(ctx->in, buf, len);
132 /// Final wrapup - pad to 64-byte boundary with the bit pattern
133 /// 1 0* (64-bit count of bits processed, MSB-first)
134 void MD4::MD4Final(struct MD4Context *ctx, unsigned char* digest)
136 unsigned int count;
137 unsigned char *p;
139 // Compute number of bytes mod 64
140 count = (ctx->bits[0] >> 3) & 0x3F;
142 // Set the first char of padding to 0x80.
143 //This is safe since there is always at least one byte free
144 p = ctx->in + count;
145 *p++ = 0x80;
147 // Bytes of padding needed to make 64 bytes
148 count = 64 - 1 - count;
150 // Pad out to 56 mod 64
151 if (count < 8)
153 // Two lots of padding: Pad the first block to 64 bytes
154 memset(p, 0, count);
155 byteReverse(ctx->in, 16);
156 MD4Transform(ctx->buf, (uint32_t *) ctx->in);
158 // Now fill the next block with 56 bytes
159 memset(ctx->in, 0, 56);
161 else
163 // Pad block to 56 bytes
164 memset(p, 0, count - 8);
166 byteReverse(ctx->in, 14);
168 // Append length in bits and transform
169 ((uint32_t *) ctx->in)[14] = ctx->bits[0];
170 ((uint32_t *) ctx->in)[15] = ctx->bits[1];
172 MD4Transform(ctx->buf, (uint32_t *) ctx->in);
173 byteReverse((unsigned char *) ctx->buf, 4);
175 if (digest!=NULL)
177 memcpy(digest, ctx->buf, 16);
179 memset(ctx, 0, sizeof(ctx)); // In case it's sensitive
182 /// The three core functions
183 #define MD4_F(x, y, z) (((x) & (y)) | ((~x) & (z)))
184 #define MD4_G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
185 #define MD4__H(x, y, z) ((x) ^ (y) ^ (z))
187 #define MD4_FF(a, b, c, d, x, s) { \
188 (a) += MD4_F ((b), (c), (d)) + (x); \
189 (a) = rol ((a), (s)); \
191 #define MD4_GG(a, b, c, d, x, s) { \
192 (a) += MD4_G ((b), (c), (d)) + (x) + (uint32_t)0x5a827999; \
193 (a) = rol ((a), (s)); \
195 #define MD4_HH(a, b, c, d, x, s) { \
196 (a) += MD4__H ((b), (c), (d)) + (x) + (uint32_t)0x6ed9eba1; \
197 (a) = rol ((a), (s)); \
200 /// The core of the MD4 algorithm
201 void MD4::MD4Transform(uint32_t buf[4], uint32_t const in[16])
203 register uint32_t a, b, c, d;
205 a = buf[0];
206 b = buf[1];
207 c = buf[2];
208 d = buf[3];
210 MD4_FF(a, b, c, d, in[0], 3); /* 1 */
211 MD4_FF(d, a, b, c, in[1], 7); /* 2 */
212 MD4_FF(c, d, a, b, in[2], 11); /* 3 */
213 MD4_FF(b, c, d, a, in[3], 19); /* 4 */
214 MD4_FF(a, b, c, d, in[4], 3); /* 5 */
215 MD4_FF(d, a, b, c, in[5], 7); /* 6 */
216 MD4_FF(c, d, a, b, in[6], 11); /* 7 */
217 MD4_FF(b, c, d, a, in[7], 19); /* 8 */
218 MD4_FF(a, b, c, d, in[8], 3); /* 9 */
219 MD4_FF(d, a, b, c, in[9], 7); /* 10 */
220 MD4_FF(c, d, a, b, in[10], 11); /* 11 */
221 MD4_FF(b, c, d, a, in[11], 19); /* 12 */
222 MD4_FF(a, b, c, d, in[12], 3); /* 13 */
223 MD4_FF(d, a, b, c, in[13], 7); /* 14 */
224 MD4_FF(c, d, a, b, in[14], 11); /* 15 */
225 MD4_FF(b, c, d, a, in[15], 19); /* 16 */
227 MD4_GG(a, b, c, d, in[0], 3); /* 17 */
228 MD4_GG(d, a, b, c, in[4], 5); /* 18 */
229 MD4_GG(c, d, a, b, in[8], 9); /* 19 */
230 MD4_GG(b, c, d, a, in[12], 13); /* 20 */
231 MD4_GG(a, b, c, d, in[1], 3); /* 21 */
232 MD4_GG(d, a, b, c, in[5], 5); /* 22 */
233 MD4_GG(c, d, a, b, in[9], 9); /* 23 */
234 MD4_GG(b, c, d, a, in[13], 13); /* 24 */
235 MD4_GG(a, b, c, d, in[2], 3); /* 25 */
236 MD4_GG(d, a, b, c, in[6], 5); /* 26 */
237 MD4_GG(c, d, a, b, in[10], 9); /* 27 */
238 MD4_GG(b, c, d, a, in[14], 13); /* 28 */
239 MD4_GG(a, b, c, d, in[3], 3); /* 29 */
240 MD4_GG(d, a, b, c, in[7], 5); /* 30 */
241 MD4_GG(c, d, a, b, in[11], 9); /* 31 */
242 MD4_GG(b, c, d, a, in[15], 13); /* 32 */
244 MD4_HH(a, b, c, d, in[0], 3); /* 33 */
245 MD4_HH(d, a, b, c, in[8], 9); /* 34 */
246 MD4_HH(c, d, a, b, in[4], 11); /* 35 */
247 MD4_HH(b, c, d, a, in[12], 15); /* 36 */
248 MD4_HH(a, b, c, d, in[2], 3); /* 37 */
249 MD4_HH(d, a, b, c, in[10], 9); /* 38 */
250 MD4_HH(c, d, a, b, in[6], 11); /* 39 */
251 MD4_HH(b, c, d, a, in[14], 15); /* 40 */
252 MD4_HH(a, b, c, d, in[1], 3); /* 41 */
253 MD4_HH(d, a, b, c, in[9], 9); /* 42 */
254 MD4_HH(c, d, a, b, in[5], 11); /* 43 */
255 MD4_HH(b, c, d, a, in[13], 15); /* 44 */
256 MD4_HH(a, b, c, d, in[3], 3); /* 45 */
257 MD4_HH(d, a, b, c, in[11], 9); /* 46 */
258 MD4_HH(c, d, a, b, in[7], 11); /* 47 */
259 MD4_HH(b, c, d, a, in[15], 15); /* 48 */
261 buf[0] += a;
262 buf[1] += b;
263 buf[2] += c;
264 buf[3] += d;
267 /// Algorithm verification
268 bool MD4::selfTest()
270 wxString test1(wxEmptyString);
271 wxString test1_md(wxT("31D6CFE0D16AE931B73C59D7E0C089C0"));
272 wxString test2(wxT("a"));
273 wxString test2_md(wxT("BDE52CB31DE33E46245E05FBDBD6FB24"));
274 wxString test3(wxT("abc"));
275 wxString test3_md(wxT("A448017AAF21D8525FC10AE87AA6729D"));
276 wxString test4(wxT("message digest"));
277 wxString test4_md(wxT("D9130A8164549FE818874806E1C7014B"));
278 wxString test5(wxT("abcdefghijklmnopqrstuvwxyz"));
279 wxString test5_md(wxT("D79E1C308AA5BBCDEEA8ED63DF412DA9"));
280 wxString test6(wxT("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"));
281 wxString test6_md(wxT("043F8582F241DB351CE627E153E7F0E4"));
282 wxString test7(wxT("12345678901234567890123456789012345678901234567890123456789012345678901234567890"));
283 wxString test7_md(wxT("E33B4DDC9C38F2199C3E7B164FCC0536"));
285 MD4 md4;
287 if (md4.calcMd4FromString(test1) != test1_md)
288 return false;
289 if (md4.calcMd4FromString(test2) != test2_md)
290 return false;
291 if (md4.calcMd4FromString(test3) != test3_md)
292 return false;
293 if (md4.calcMd4FromString(test4) != test4_md)
294 return false;
295 if (md4.calcMd4FromString(test5) != test5_md)
296 return false;
297 if (md4.calcMd4FromString(test6) != test6_md)
298 return false;
299 if (md4.calcMd4FromString(test7) != test7_md)
300 return false;
302 return true;
305 /// Get Md4 hash from a string
306 wxString MD4::calcMd4FromString(const wxString &buf)
308 MD4Context hdc;
309 unsigned char ret[MD4_HASHLEN_BYTE];
311 MD4Init(&hdc);
312 MD4Update(&hdc, (const unsigned char*)buf.c_str(), buf.length());
313 MD4Final(&hdc, ret);
315 return charToHex((const char*)ret, MD4_HASHLEN_BYTE);
318 /// Get Md4 hash from a file
319 wxString MD4::calcMd4FromFile(const wxString &filename, MD4Hook hook)
321 unsigned int bufSize;
322 unsigned char ret[MD4_HASHLEN_BYTE];
323 MD4Context hdc;
325 // Open file and let wxFFile destructor close the file
326 // Closing it explicitly may crash on Win32 ...
327 wxFFile file(filename, wxS("rbS"));
328 if (! file.IsOpened())
330 return wxEmptyString;
332 else
334 bufSize = calcBufSize(file.Length());
335 char *buf = new char[bufSize];
337 bool keep_going = true;
338 size_t read = 0;
339 size_t totalread = 0;
341 bool goAhead = true;
343 MD4Init(&hdc);
344 while (!file.Eof() && keep_going)
346 if (hook)
348 goAhead = hook( (int)((double)(100.0 * totalread) / file.Length()));
350 if (goAhead)
352 read = file.Read(buf, bufSize);
353 MD4Update(&hdc, reinterpret_cast<unsigned char const *>(buf),
354 read );
355 totalread += read;
357 else
359 return (_("Cancelled !"));
362 MD4Final(&hdc, ret);
364 delete [] buf;
366 return charToHex(reinterpret_cast<const char *>(ret),
367 MD4_HASHLEN_BYTE);
371 /// Convert hash to hexa string
372 wxString MD4::charToHex(const char *buf, size_t len)
374 size_t i;
375 wxString hexString;
377 for (i = 0; i < len; ++i)
379 hexString += wxString::Format(wxS("%02x"), 0xFF & *(buf + i));
382 // Reduce memory usage
383 hexString.Shrink();
385 return (hexString);
388 /// Compute Md4 buffsize
389 size_t MD4::calcBufSize(size_t filesize)
391 if (filesize < 100000)
393 filesize = 100000;
395 else if (filesize > 200000)
397 filesize = 200000;
400 return (filesize);
402 // File_checked_for_headers