gloox  1.1-svn
md4.cpp
1 /*
2  Copyright (c) 2006-2009 by Jakob Schroeter <js@camaya.net>
3  This file is part of the gloox library. http://camaya.net/gloox
4 
5  This software is distributed under a license. The full license
6  agreement can be found in the file LICENSE in this distribution.
7  This software may not be copied, modified, sold or distributed
8  other than expressed in the named license agreement.
9 
10  This software is distributed without any warranty.
11 */
12 
13 /*
14  This class is based on a C implementation of the MD5 algorithm written by
15  L. Peter Deutsch.
16  The full notice as shipped with the original verson is included below.
17 */
18 
19 /*
20  Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved.
21 
22  This software is provided 'as-is', without any express or implied
23  warranty. In no event will the authors be held liable for any damages
24  arising from the use of this software.
25 
26  Permission is granted to anyone to use this software for any purpose,
27  including commercial applications, and to alter it and redistribute it
28  freely, subject to the following restrictions:
29 
30  1. The origin of this software must not be misrepresented; you must not
31  claim that you wrote the original software. If you use this software
32  in a product, an acknowledgment in the product documentation would be
33  appreciated but is not required.
34  2. Altered source versions must be plainly marked as such, and must not be
35  misrepresented as being the original software.
36  3. This notice may not be removed or altered from any source distribution.
37 
38  L. Peter Deutsch
39  ghost@aladdin.com
40 
41  */
42 /* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */
43 /*
44  Independent implementation of MD5 (RFC 1321).
45 
46  This code implements the MD5 Algorithm defined in RFC 1321, whose
47  text is available at
48  http://www.ietf.org/rfc/rfc1321.txt
49  The code is derived from the text of the RFC, including the test suite
50  (section A.5) but excluding the rest of Appendix A. It does not include
51  any code or documentation that is identified in the RFC as being
52  copyrighted.
53 
54  The original and principal author of md5.c is L. Peter Deutsch
55  <ghost@aladdin.com>. Other authors are noted in the change history
56  that follows (in reverse chronological order):
57 
58  2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order
59  either statically or dynamically; added missing #include <string.h>
60  in library.
61  2002-03-11 lpd Corrected argument list for main(), and added int return
62  type, in test program and T value program.
63  2002-02-21 lpd Added missing #include <stdio.h> in test program.
64  2000-07-03 lpd Patched to eliminate warnings about "constant is
65  unsigned in ANSI C, signed in traditional"; made test program
66  self-checking.
67  1999-11-04 lpd Edited comments slightly for automatic TOC extraction.
68  1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).
69  1999-05-03 lpd Original version.
70  */
71 
72 #ifdef _WIN32 // to disable warning C4996 about sprintf being deprecated
73 # include "../config.h.win"
74 #elif defined( _WIN32_WCE )
75 # include "../config.h.win"
76 // #else
77 // # include "config.h"
78 #endif
79 
80 #include "md4.h"
81 
82 #include <cstdio>
83 #include <string.h>
84 
85 #include <cstdio> // [s]print[f]
86 
87 namespace gloox
88 {
89 // #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */
90 // #ifdef ARCH_IS_BIG_ENDIAN
91 // # define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1)
92 // #else
93 // # define BYTE_ORDER 0
94 // #endif
95 
96 #undef BYTE_ORDER
97 #define BYTE_ORDER 0
98 
99  const unsigned char MD4::pad[64] =
100  {
101  0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
102  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
103  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
104  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
105  };
106 
107  const std::string MD4::md4( const std::string& data )
108  {
109  MD4 md4;
110  md4.feed( data );
111  return md4.hex();
112  }
113 
115  : m_finished( false )
116  {
117  init();
118  }
119 
121  {
122  }
123 
124  void MD4::process( const unsigned char* data /*[64]*/ )
125  {
126  unsigned int a = m_state.abcd[0];
127  unsigned int b = m_state.abcd[1];
128  unsigned int c = m_state.abcd[2];
129  unsigned int d = m_state.abcd[3];
130  unsigned int t;
131 #if BYTE_ORDER > 0
132  /* Define storage only for big-endian CPUs. */
133  unsigned int X[16];
134 #else
135  /* Define storage for little-endian or both types of CPUs. */
136  unsigned int xbuf[16];
137  const unsigned int *X;
138 #endif
139 
140  {
141 #if BYTE_ORDER == 0
142  /*
143  * Determine dynamically whether this is a big-endian or
144  * little-endian machine, since we can use a more efficient
145  * algorithm on the latter.
146  */
147  static const int w = 1;
148 
149  if( *((const unsigned char *)&w) ) /* dynamic little-endian */
150 #endif
151 #if BYTE_ORDER <= 0 /* little-endian */
152  {
153  /*
154  * On little-endian machines, we can process properly aligned
155  * data without copying it.
156  */
157  if( !((data - (const unsigned char*)0) & 3) )
158  {
159  /* data are properly aligned */
160  X = (const unsigned int*)data;
161  }
162  else
163  {
164  /* not aligned */
165  memcpy( xbuf, data, 64 );
166  X = xbuf;
167  }
168  }
169 #endif
170 #if BYTE_ORDER == 0
171  else // dynamic big-endian
172 #endif
173 #if BYTE_ORDER >= 0 // big-endian
174  {
175  /*
176  * On big-endian machines, we must arrange the bytes in the
177  * right order.
178  */
179  const unsigned char* xp = data;
180  int i;
181 
182 # if BYTE_ORDER == 0
183  X = xbuf; // (dynamic only)
184 # else
185 # define xbuf X /* (static only) */
186 # endif
187  for( i = 0; i < 16; ++i, xp += 4 )
188  xbuf[i] = xp[0] + ( xp[1] << 8 ) + ( xp[2] << 16 ) + ( xp[3] << 24 );
189  }
190 #endif
191  }
192 
193 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
194 
195  /* Round 1. */
196  /* Let [abcd k s] denote the operation
197  a = (a + F(b,c,d) + X[k] <<< s). */
198 #define F(x, y, z) (((x) & (y)) | (~(x) & (z)))
199 #define SET(a, b, c, d, k, s)\
200  t = a + F(b,c,d) + X[k];\
201  a = ROTATE_LEFT(t, s)
202  /* Do the following 16 operations. */
203  SET(a, b, c, d, 0, 3);
204  SET(d, a, b, c, 1, 7);
205  SET(c, d, a, b, 2, 11);
206  SET(b, c, d, a, 3, 19);
207  SET(a, b, c, d, 4, 3);
208  SET(d, a, b, c, 5, 7);
209  SET(c, d, a, b, 6, 11);
210  SET(b, c, d, a, 7, 19);
211  SET(a, b, c, d, 8, 3);
212  SET(d, a, b, c, 9, 7);
213  SET(c, d, a, b, 10, 11);
214  SET(b, c, d, a, 11, 19);
215  SET(a, b, c, d, 12, 3);
216  SET(d, a, b, c, 13, 7);
217  SET(c, d, a, b, 14, 11);
218  SET(b, c, d, a, 15, 19);
219 #undef SET
220 
221  /* Round 2. */
222  /* Let [abcd k s ] denote the operation
223  a = (a + G(b,c,d) + X[k] + 0x5A827999) <<< s. */
224 #define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
225 #define SET(a, b, c, d, k, s)\
226  t = a + G(b,c,d) + X[k] + 0x5A827999;\
227  a = ROTATE_LEFT(t, s)
228  /* Do the following 16 operations. */
229  SET(a, b, c, d, 0, 3);
230  SET(d, a, b, c, 4, 5);
231  SET(c, d, a, b, 8, 9);
232  SET(b, c, d, a, 12, 13);
233  SET(a, b, c, d, 1, 3);
234  SET(d, a, b, c, 5, 5);
235  SET(c, d, a, b, 9, 9);
236  SET(b, c, d, a, 13, 13);
237  SET(a, b, c, d, 2, 3);
238  SET(d, a, b, c, 6, 5);
239  SET(c, d, a, b, 10, 9);
240  SET(b, c, d, a, 14, 13);
241  SET(a, b, c, d, 3, 3);
242  SET(d, a, b, c, 7, 5);
243  SET(c, d, a, b, 11, 9);
244  SET(b, c, d, a, 15, 13);
245 #undef SET
246 
247  /* Round 3. */
248  /* Let [abcd k s t] denote the operation
249  a = (a + H(b,c,d) + X[k] + 0x6ED9EBA1) <<< s. */
250 #define H(x, y, z) ((x) ^ (y) ^ (z))
251 #define SET(a, b, c, d, k, s)\
252  t = a + H(b,c,d) + X[k] + 0x6ED9EBA1;\
253  a = ROTATE_LEFT(t, s)
254  /* Do the following 16 operations. */
255  SET(a, b, c, d, 0, 3);
256  SET(d, a, b, c, 8, 9);
257  SET(c, d, a, b, 4, 11);
258  SET(b, c, d, a, 12, 15);
259  SET(a, b, c, d, 2, 3);
260  SET(d, a, b, c, 10, 9);
261  SET(c, d, a, b, 6, 11);
262  SET(b, c, d, a, 14, 15);
263  SET(a, b, c, d, 1, 3);
264  SET(d, a, b, c, 9, 9);
265  SET(c, d, a, b, 5, 11);
266  SET(b, c, d, a, 13, 15);
267  SET(a, b, c, d, 3, 3);
268  SET(d, a, b, c, 11, 9);
269  SET(c, d, a, b, 7, 11);
270  SET(b, c, d, a, 15, 15);
271 #undef SET
272 
273 
274  /* Then perform the following additions. (That is increment each
275  of the four registers by the value it had before this block
276  was started.) */
277  m_state.abcd[0] += a;
278  m_state.abcd[1] += b;
279  m_state.abcd[2] += c;
280  m_state.abcd[3] += d;
281  }
282 
283  void MD4::init()
284  {
285  m_finished = false;
286  m_state.count[0] = 0;
287  m_state.count[1] = 0;
288  m_state.abcd[0] = 0x67452301;
289  m_state.abcd[1] = 0xefcdab89;
290  m_state.abcd[2] = 0x98badcfe;
291  m_state.abcd[3] = 0x10325476;
292  }
293 
294  void MD4::feed( const std::string& data )
295  {
296  feed( (const unsigned char*)data.c_str(), (int)data.length() );
297  }
298 
299  void MD4::feed( const unsigned char* data, int bytes )
300  {
301  const unsigned char* p = data;
302  int left = bytes;
303  int offset = ( m_state.count[0] >> 3 ) & 63;
304  unsigned int nbits = (unsigned int)( bytes << 3 );
305 
306  if( bytes <= 0 )
307  return;
308 
309  /* Update the message length. */
310  m_state.count[1] += bytes >> 29;
311  m_state.count[0] += nbits;
312  if( m_state.count[0] < nbits )
313  m_state.count[1]++;
314 
315  /* Process an initial partial block. */
316  if( offset )
317  {
318  int copy = ( offset + bytes > 64 ? 64 - offset : bytes );
319 
320  memcpy( m_state.buf + offset, p, copy );
321  if( offset + copy < 64 )
322  return;
323  p += copy;
324  left -= copy;
325  process( m_state.buf );
326  }
327 
328  /* Process full blocks. */
329  for( ; left >= 64; p += 64, left -= 64 )
330  process( p );
331 
332  /* Process a final partial block. */
333  if( left )
334  memcpy( m_state.buf, p, left );
335  }
336 
338  {
339  if( m_finished )
340  return;
341 
342  unsigned char data[8];
343 
344  /* Save the length before padding. */
345  for( int i = 0; i < 8; ++i )
346  data[i] = (unsigned char)( m_state.count[i >> 2] >> ( ( i & 3 ) << 3 ) );
347 
348  /* Pad to 56 bytes mod 64. */
349  feed( pad, ( ( 55 - ( m_state.count[0] >> 3 ) ) & 63 ) + 1 );
350 
351  /* Append the length. */
352  feed( data, 8 );
353 
354  m_finished = true;
355  }
356 
357  const std::string MD4::hex()
358  {
359  if( !m_finished )
360  finalize();
361 
362  char buf[33];
363 
364  for( int i = 0; i < 16; ++i )
365  sprintf( buf + i * 2, "%02x", (unsigned char)( m_state.abcd[i >> 2] >> ( ( i & 3 ) << 3 ) ) );
366 
367  return std::string( buf, 32 );
368  }
369 
370  const std::string MD4::binary()
371  {
372  if( !m_finished )
373  finalize();
374 
375  unsigned char digest[16];
376  for( int i = 0; i < 16; ++i )
377  digest[i] = (unsigned char)( m_state.abcd[i >> 2] >> ( ( i & 3 ) << 3 ) );
378 
379  return std::string( (char*)digest, 16 );
380  }
381 
382  void MD4::reset()
383  {
384  init();
385  }
386 
387 }