blocxx
MD5.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2 * Copyright (C) 2005, Vintela, Inc. All rights reserved.
3 * Copyright (C) 2006, Novell, Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of
14 * Vintela, Inc.,
15 * nor Novell, Inc.,
16 * nor the names of its contributors or employees may be used to
17 * endorse or promote products derived from this software without
18 * specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 *******************************************************************************/
32 
33 
39 #include "blocxx/BLOCXX_config.h"
40 #include "blocxx/MD5.hpp"
41 #include "blocxx/String.hpp"
42 #include "blocxx/ExceptionIds.hpp"
43 
44 #include <string.h> // for memset
45 
46 #ifdef BLOCXX_WIN32
47 #pragma warning (push)
48 #pragma warning (disable: 4355)
49 #endif
50 
51 namespace BLOCXX_NAMESPACE
52 {
53 
54 const int MD5HASHHEXLEN = 32;
55 
62 int
64 {
65  unsigned char lc = c;
66  MD5::MD5Update(&(_md5->m_ctx), &lc, 1);
67  return c;
68 }
70 std::streamsize
71 MD5StreamBuffer::xsputn(const char* s, std::streamsize num)
72 {
74  reinterpret_cast<const unsigned char*>(s), num);
75  return num;
76 }
79 : MD5OStreamBase(this), std::ostream(&_buf), m_ctx(), m_finished(false)
80 {
81  MD5Init(&m_ctx);
82 }
84 void
85 MD5::init(const String& input)
86 {
87  m_finished = false;
88  MD5Init(&m_ctx);
89  update(input);
90 }
92 MD5::MD5(const String& input)
93 : MD5OStreamBase(this), std::ostream(&_buf), m_ctx(), m_finished(false)
94 {
95  MD5Init(&m_ctx);
96  update(input);
97 }
99 void
100 MD5::update(const String& input)
101 {
102  if (m_finished)
103  {
104  BLOCXX_THROW(MD5Exception, "Cannot update after a call to toString()");
105  }
106  MD5Update(&m_ctx, reinterpret_cast<const unsigned char*>(input.c_str()),
107  input.length());
108 }
110 String
112 {
113  return convertBinToHex(getDigest());
114 }
116 unsigned char*
118 {
119  if (!m_finished)
120  {
122  m_finished = true;
123  }
124  return m_digest;
125 }
127 String
128 MD5::convertBinToHex( const unsigned char* sBin)
129 {
130  unsigned short i;
131  unsigned char j;
132  char Hex[ MD5HASHHEXLEN + 1 ];
133  for ( i = 0; i < MD5HASHLEN; i++ )
134  {
135  j = (sBin[i] >> 4) & 0xf;
136  if ( j <= 9 )
137  {
138  Hex[i*2] = (j + '0');
139  }
140  else
141  {
142  Hex[i*2] = (j + 'a' - 10);
143  }
144  j = sBin[i] & 0xf;
145  if ( j <= 9 )
146  {
147  Hex[i*2+1] = (j + '0');
148  }
149  else
150  {
151  Hex[i*2+1] = (j + 'a' - 10);
152  }
153  };
154  Hex[MD5HASHHEXLEN] = '\0';
155  return String(Hex);
156 };
157 //A.3 md5c.c
158 /* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
159  */
160 /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
161 rights reserved.
162 License to copy and use this software is granted provided that it
163 is identified as the "RSA Data Security, Inc. MD5 Message-Digest
164 Algorithm" in all material mentioning or referencing this software
165 or this function.
166 License is also granted to make and use derivative works provided
167 that such works are identified as "derived from the RSA Data
168 Security, Inc. MD5 Message-Digest Algorithm" in all material
169 mentioning or referencing the derived work.
170 RSA Data Security, Inc. makes no representations concerning either
171 the merchantability of this software or the suitability of this
172 software for any particular purpose. It is provided "as is"
173 without express or implied warranty of any kind.
174 These notices must be retained in any copies of any part of this
175 documentation and/or software.
176  */
177 /* POINTER defines a generic pointer type */
178 typedef unsigned char *POINTER;
179 /* Constants for MD5Transform routine.
180  */
181 #define S11 7
182 #define S12 12
183 #define S13 17
184 #define S14 22
185 #define S21 5
186 #define S22 9
187 #define S23 14
188 #define S24 20
189 #define S31 4
190 #define S32 11
191 #define S33 16
192 #define S34 23
193 #define S41 6
194 #define S42 10
195 #define S43 15
196 #define S44 21
197 static void MD5Transform(UInt32*, const unsigned char*);
198 static void Encode(unsigned char *, UInt32 *, UInt32);
199 static void Decode(UInt32 *, const unsigned char *, UInt32);
200 //static void MD5_memcpy(POINTER, POINTER, UInt32);
201 //static void MD5_memset(POINTER, Int32, UInt32);
202 static unsigned char PADDING[64] = {
203  0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
204  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
205  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
206 };
207 /* F, G, H and I are basic MD5 functions.
208  */
209 #define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
210 #define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
211 #define H(x, y, z) ((x) ^ (y) ^ (z))
212 #define I(x, y, z) ((y) ^ ((x) | (~z)))
213 /* ROTATE_LEFT rotates x left n bits.
214  */
215 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
216 /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
217 Rotation is separate from addition to prevent recomputation.
218  */
219 #define FF(a, b, c, d, x, s, ac) { \
220  (a) += F ((b), (c), (d)) + (x) + static_cast<UInt32>(ac); \
221  (a) = ROTATE_LEFT ((a), (s)); \
222  (a) += (b); \
223  }
224 #define GG(a, b, c, d, x, s, ac) { \
225  (a) += G ((b), (c), (d)) + (x) + static_cast<UInt32>(ac); \
226  (a) = ROTATE_LEFT ((a), (s)); \
227  (a) += (b); \
228  }
229 #define HH(a, b, c, d, x, s, ac) { \
230  (a) += H ((b), (c), (d)) + (x) + static_cast<UInt32>(ac); \
231  (a) = ROTATE_LEFT ((a), (s)); \
232  (a) += (b); \
233  }
234 #define II(a, b, c, d, x, s, ac) { \
235  (a) += I ((b), (c), (d)) + (x) + static_cast<UInt32>(ac); \
236  (a) = ROTATE_LEFT ((a), (s)); \
237  (a) += (b); \
238  }
239 /* MD5 initialization. Begins an MD5 operation, writing a new context.
240  */ // STATIC
241 void
243 {
244  context->count[0] = context->count[1] = 0;
245  /* Load magic initialization constants.
246  */
247  context->state[0] = 0x67452301;
248  context->state[1] = 0xefcdab89;
249  context->state[2] = 0x98badcfe;
250  context->state[3] = 0x10325476;
251 }
252 /* MD5 block update operation. Continues an MD5 message-digest
253  operation, processing another message block, and updating the
254  context.
255  */ // STATIC
256 void
257  MD5::MD5Update(MD5_CTX* context, const unsigned char* input,
258  UInt32 inputLen)
259 {
260  UInt32 i, index, partLen;
261  /* Compute number of bytes mod 64 */
262  index = ((context->count[0] >> 3) & 0x3F);
263  /* Update number of bits */
264  if ((context->count[0] += (inputLen << 3)) < (inputLen << 3))
265  {
266  context->count[1]++;
267  }
268  context->count[1] += (inputLen >> 29);
269  partLen = 64 - index;
270  /* Transform as many times as possible.
271  */
272  if (inputLen >= partLen)
273  {
274  memcpy(static_cast<POINTER>(&context->buffer[index]),
275  static_cast<const unsigned char*>(input), partLen);
276  MD5Transform (context->state, context->buffer);
277  for (i = partLen; i + 63 < inputLen; i += 64)
278  MD5Transform (context->state, &input[i]);
279  index = 0;
280  }
281  else
282  i = 0;
283  /* Buffer remaining input */
284  memcpy
285  (static_cast<POINTER>(&context->buffer[index]),
286  static_cast<const unsigned char*>(&input[i]),
287  inputLen-i);
288 }
289 /* MD5 finalization. Ends an MD5 message-digest operation, writing the
290  the message digest and zeroizing the context.
291  */ // STATIC
292 void
293  MD5::MD5Final (unsigned char* digest, MD5_CTX* context)
294 {
295  unsigned char bits[8];
296  UInt32 index, padLen;
297  /* Save number of bits */
298  Encode (bits, context->count, 8);
299  /* Pad out to 56 mod 64.
300  */
301  index = ((context->count[0] >> 3) & 0x3f);
302  padLen = (index < 56) ? (56 - index) : (120 - index);
303  MD5Update (context, PADDING, padLen);
304  /* Append length (before padding) */
305  MD5Update (context, bits, 8);
306  /* Store state in digest */
307  Encode (digest, context->state, 16);
308  /* Zeroize sensitive information.
309  */
310  memset (reinterpret_cast<POINTER>(context), 0, sizeof (*context));
311 }
312 /* MD5 basic transformation. Transforms state based on block.
313  */
314 static void MD5Transform (UInt32* state, const unsigned char* block)
315 {
316  UInt32 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
317  Decode (x, block, 64);
318  /* Round 1 */
319  FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
320  FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
321  FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
322  FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
323  FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
324  FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
325  FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
326  FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
327  FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
328  FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
329  FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
330  FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
331  FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
332  FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
333  FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
334  FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
335  /* Round 2 */
336  GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
337  GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
338  GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
339  GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
340  GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
341  GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
342  GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
343  GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
344  GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
345  GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
346  GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
347  GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
348  GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
349  GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
350  GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
351  GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
352  /* Round 3 */
353  HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
354  HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
355  HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
356  HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
357  HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
358  HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
359  HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
360  HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
361  HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
362  HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
363  HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
364  HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
365  HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
366  HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
367  HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
368  HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
369  /* Round 4 */
370  II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
371  II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
372  II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
373  II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
374  II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
375  II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
376  II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
377  II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
378  II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
379  II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
380  II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
381  II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
382  II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
383  II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
384  II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
385  II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
386  state[0] += a;
387  state[1] += b;
388  state[2] += c;
389  state[3] += d;
390  /* Zeroize sensitive information. */
391  memset (reinterpret_cast<POINTER>(x), 0, sizeof (x));
392 }
393 /* Encodes input (UInt32) into output (unsigned char). Assumes len is
394  a multiple of 4.
395  */
396 static void Encode (unsigned char* output, UInt32* input, UInt32 len)
397 {
398  UInt32 i, j;
399  for (i = 0, j = 0; j < len; i++, j += 4)
400  {
401  output[j] = (input[i] & 0xff);
402  output[j+1] = ((input[i] >> 8) & 0xff);
403  output[j+2] = ((input[i] >> 16) & 0xff);
404  output[j+3] = ((input[i] >> 24) & 0xff);
405  }
406 }
407 /* Decodes input (unsigned char) into output (UInt32). Assumes len is
408  a multiple of 4.
409  */
410 static void Decode (UInt32* output, const unsigned char* input, UInt32 len)
411 {
412  UInt32 i, j;
413  for (i = 0, j = 0; j < len; i++, j += 4)
414  output[i] = (static_cast<UInt32>(input[j])) | ((static_cast<UInt32>(input[j+1])) << 8) |
415  ((static_cast<UInt32>(input[j+2])) << 16) | ((static_cast<UInt32>(input[j+3])) << 24);
416 }
417 /* Note: Replace "for loop" with standard memcpy if possible.
418  */
419 //static void MD5_memcpy (POINTER output, POINTER input, UInt32 len)
420 //{
421  //UInt32 i;
422  //for (i = 0; i < len; i++)
423  // output[i] = input[i];
424 //}
425 /* Note: Replace "for loop" with standard memset if possible. */
426 //static void MD5_memset (POINTER output, Int32 value, UInt32 len)
427 //{
428  //UInt32 i;
429  //for (i = 0; i < len; i++)
430  // ((char *)output)[i] = (char)value;
431 //}
432 
433 } // end namespace BLOCXX_NAMESPACE
434 
435 
436 #ifdef BLOCXX_WIN32
437 #pragma warning (pop)
438 #endif
439