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-2011 ThePolish ( thepolish@vipmail.ru )
9///
10/// Copyright (c) 2004-2011 Marcelo Roberto Jimenez ( phoenix@amule.org )
11///
12/// Copyright (c) 2004-2011 Alo Sarv ( madcat_@users.sourceforge.net )
13///
14/// Copyright (c) 2002-2011 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////////////////////////////////////////////////////////////////////////////////
37
38
39#ifdef __BORLANDC__
40    #pragma hdrstop
41#endif
42
43// For all others, include the necessary headers
44#ifndef WX_PRECOMP
45    #include "wx/wx.h"
46#endif
47
48#include <wx/ffile.h>
49
50#include "md4.h"
51#include "bithelp.h"
52
53
54/// BIG ENDIAN byte reversing
55#if wxBYTE_ORDER == wxBIG_ENDIAN
56// Note: this code is harmless on little-endian machines.
57void MD4::byteReverse(unsigned char *buf, unsigned longs)
58{
59  uint32_t t;
60  do
61    {
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;
66    }
67  while (--longs);
68}
69#else
70#define byteReverse(buf, len)	do { } while (0)
71#endif
72
73/// Start MD4 accumulation.
74/// Set bit count to 0 and buffer to mysteriousinitialization constants.
75void MD4::MD4Init(struct MD4Context *ctx)
76{
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;
83}
84
85/// Update context to reflect the concatenation of another buffer full of bytes.
86void MD4::MD4Update(struct MD4Context *ctx, unsigned char const *buf,
87                    size_t len)
88{
89  register uint32_t t;
90
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;
96
97  t = (t >> 3) & 0x3f;	// Bytes already in shsInfo->data
98
99  // Handle any leading odd-sized chunks
100  if (t)
101    {
102      unsigned char *p = (unsigned char *) ctx->in + t;
103
104      t = 64 - t;
105      if (len < t)
106        {
107          memcpy(p, buf, len);
108          return;
109        }
110      memcpy(p, buf, t);
111      byteReverse(ctx->in, 16);
112      MD4Transform(ctx->buf, (uint32_t *) ctx->in);
113      buf += t;
114      len -= t;
115    }
116
117  // Process data in 64-byte chunks
118  while (len >= 64)
119    {
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;
125    }
126
127  //Handle any remaining bytes of data.
128  memcpy(ctx->in, buf, len);
129}
130
131
132///  Final wrapup - pad to 64-byte boundary with the bit pattern
133///  1 0* (64-bit count of bits processed, MSB-first)
134void MD4::MD4Final(struct MD4Context *ctx, unsigned char* digest)
135{
136  unsigned int count;
137  unsigned char *p;
138
139  // Compute number of bytes mod 64
140  count = (ctx->bits[0] >> 3) & 0x3F;
141
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;
146
147  // Bytes of padding needed to make 64 bytes
148  count = 64 - 1 - count;
149
150  // Pad out to 56 mod 64
151  if (count < 8)
152    {
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);
157
158      // Now fill the next block with 56 bytes
159      memset(ctx->in, 0, 56);
160    }
161  else
162    {
163      // Pad block to 56 bytes
164      memset(p, 0, count - 8);
165    }
166  byteReverse(ctx->in, 14);
167
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];
171
172  MD4Transform(ctx->buf, (uint32_t *) ctx->in);
173  byteReverse((unsigned char *) ctx->buf, 4);
174
175  if (digest!=NULL)
176    {
177      memcpy(digest, ctx->buf, 16);
178    }
179  memset(ctx, 0, sizeof(ctx));	// In case it's sensitive
180}
181
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))
186
187#define MD4_FF(a, b, c, d, x, s) { \
188    (a) += MD4_F ((b), (c), (d)) + (x); \
189    (a) = rol ((a), (s)); \
190  }
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)); \
194  }
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)); \
198  }
199
200/// The core of the MD4 algorithm
201void MD4::MD4Transform(uint32_t buf[4], uint32_t const in[16])
202{
203  register uint32_t a, b, c, d;
204
205  a = buf[0];
206  b = buf[1];
207  c = buf[2];
208  d = buf[3];
209
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 */
226
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 */
243
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 */
260
261  buf[0] += a;
262  buf[1] += b;
263  buf[2] += c;
264  buf[3] += d;
265}
266
267/// Algorithm verification
268bool MD4::selfTest()
269{
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"));
284
285  MD4 md4;
286
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;
301
302  return true;
303}
304
305/// Get Md4 hash from a string
306wxString MD4::calcMd4FromString(const wxString &buf)
307{
308  MD4Context hdc;
309  unsigned char ret[MD4_HASHLEN_BYTE];
310
311  MD4Init(&hdc);
312  MD4Update(&hdc, (const unsigned char*)buf.c_str(), buf.length());
313  MD4Final(&hdc, ret);
314
315  return charToHex((const char*)ret, MD4_HASHLEN_BYTE);
316}
317
318/// Get Md4 hash from a file
319wxString MD4::calcMd4FromFile(const wxString &filename, MD4Hook hook)
320{
321  unsigned int bufSize;
322  unsigned char ret[MD4_HASHLEN_BYTE];
323  MD4Context hdc;
324
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())
329    {
330      return wxEmptyString;
331    }
332  else
333    {
334      bufSize = calcBufSize(file.Length());
335      char *buf = new char[bufSize];
336
337      bool keep_going = true;
338      size_t read = 0;
339      size_t totalread = 0;
340
341      bool goAhead = true;
342
343      MD4Init(&hdc);
344      while (!file.Eof() && keep_going)
345        {
346          if (hook)
347            {
348              goAhead = hook( (int)((double)(100.0 * totalread) / file.Length()));
349            }
350          if (goAhead)
351            {
352              read = file.Read(buf, bufSize);
353              MD4Update(&hdc, reinterpret_cast<unsigned char const *>(buf),
354                        read );
355              totalread += read;
356            }
357          else
358            {
359              return (_("Cancelled !"));
360            }
361        }
362      MD4Final(&hdc, ret);
363
364      delete [] buf;
365
366      return charToHex(reinterpret_cast<const char *>(ret),
367                       MD4_HASHLEN_BYTE);
368    }
369}
370
371/// Convert hash to hexa string
372wxString MD4::charToHex(const char *buf, size_t len)
373{
374  size_t i;
375  wxString hexString;
376
377  for (i = 0; i < len; ++i)
378    {
379      hexString += wxString::Format(wxS("%02x"), 0xFF & *(buf + i));
380    }
381
382  // Reduce memory usage
383  hexString.Shrink();
384
385  return (hexString);
386}
387
388/// Compute Md4 buffsize
389size_t MD4::calcBufSize(size_t filesize)
390{
391  if (filesize < 100000)
392    {
393      filesize = 100000;
394    }
395  else if (filesize > 200000)
396    {
397      filesize = 200000;
398    }
399
400  return (filesize);
401}
402// File_checked_for_headers
403