MD5.cpp

Go to the documentation of this file.
00001 /*******************************************************************************
00002 * Copyright (C) 2004 Vintela, Inc. All rights reserved.
00003 * Copyright (C) 2005 Novell, Inc. All rights reserved.
00004 *
00005 * Redistribution and use in source and binary forms, with or without
00006 * modification, are permitted provided that the following conditions are met:
00007 *
00008 *  - Redistributions of source code must retain the above copyright notice,
00009 *    this list of conditions and the following disclaimer.
00010 *
00011 *  - Redistributions in binary form must reproduce the above copyright notice,
00012 *    this list of conditions and the following disclaimer in the documentation
00013 *    and/or other materials provided with the distribution.
00014 *
00015 *  - Neither the name of Vintela, Inc., Novell, Inc., nor the names of its
00016 *    contributors may be used to endorse or promote products derived from this
00017 *    software without specific prior written permission.
00018 *
00019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
00020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00021 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00022 * ARE DISCLAIMED. IN NO EVENT SHALL Vintela, Inc., Novell, Inc., OR THE 
00023 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
00024 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
00025 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
00026 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
00027 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
00028 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
00029 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00030 *******************************************************************************/
00031 
00032 
00038 #include "blocxx/BLOCXX_config.h"
00039 #include "blocxx/MD5.hpp"
00040 #include "blocxx/String.hpp"
00041 #include "blocxx/ExceptionIds.hpp"
00042 
00043 #include <string.h> // for memset
00044 
00045 #ifdef BLOCXX_WIN32
00046 #pragma warning (push)
00047 #pragma warning (disable: 4355)
00048 #endif
00049 
00050 namespace BLOCXX_NAMESPACE
00051 {
00052 
00053 const int MD5HASHHEXLEN = 32;
00054 
00055 BLOCXX_DEFINE_EXCEPTION_WITH_ID(MD5);
00057 MD5OStreamBase::MD5OStreamBase(MD5* md5): _buf(md5) {}
00059 MD5StreamBuffer::MD5StreamBuffer(MD5* md5): _md5(md5) {}
00061 int 
00062 MD5StreamBuffer::overflow(int c)
00063 {
00064    unsigned char lc = c;
00065    MD5::MD5Update(&(_md5->m_ctx), &lc, 1);
00066    return c;
00067 }
00069 std::streamsize 
00070 MD5StreamBuffer::xsputn(const char* s, std::streamsize num)
00071 {
00072    MD5::MD5Update(&(_md5->m_ctx), 
00073                      reinterpret_cast<const unsigned char*>(s), num);
00074    return num;
00075 }
00077 MD5::MD5()
00078 : MD5OStreamBase(this), std::ostream(&_buf), m_ctx(), m_finished(false)
00079 {
00080    MD5Init(&m_ctx);
00081 }
00083 void
00084 MD5::init(const String& input)
00085 {
00086    m_finished = false;
00087    MD5Init(&m_ctx);
00088    update(input);
00089 }
00091 MD5::MD5(const String& input)
00092 : MD5OStreamBase(this), std::ostream(&_buf), m_ctx(), m_finished(false)
00093 {
00094    MD5Init(&m_ctx);
00095    update(input);
00096 }
00098 void
00099 MD5::update(const String& input)
00100 {
00101    if (m_finished)
00102    {
00103       BLOCXX_THROW(MD5Exception, "Cannot update after a call to toString()");
00104    }
00105    MD5Update(&m_ctx, reinterpret_cast<const unsigned char*>(input.c_str()), 
00106              input.length());
00107 }
00109 String
00110 MD5::toString()
00111 {
00112    return convertBinToHex(getDigest());
00113 }
00115 unsigned char*
00116 MD5::getDigest()
00117 {
00118    if (!m_finished)
00119    {
00120       MD5Final(m_digest, &m_ctx);
00121       m_finished = true;
00122    }
00123    return m_digest;
00124 }
00126 String
00127 MD5::convertBinToHex( const unsigned char* sBin)
00128 {
00129    unsigned short i;
00130    unsigned char j;
00131    char Hex[ MD5HASHHEXLEN + 1 ];
00132    for ( i = 0; i < MD5HASHLEN; i++ )
00133    {
00134       j = (sBin[i] >> 4) & 0xf;
00135       if ( j <= 9 )
00136       {
00137          Hex[i*2] = (j + '0');
00138       }
00139       else
00140       {
00141          Hex[i*2] = (j + 'a' - 10);
00142       }
00143       j = sBin[i] & 0xf;
00144       if ( j <= 9 )
00145       {
00146          Hex[i*2+1] = (j + '0');
00147       }
00148       else
00149       {
00150          Hex[i*2+1] = (j + 'a' - 10);
00151       }
00152    };
00153    Hex[MD5HASHHEXLEN] = '\0';
00154    return String(Hex);
00155 };
00156 //A.3 md5c.c
00157 /* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
00158  */
00159 /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
00160 rights reserved.
00161 License to copy and use this software is granted provided that it
00162 is identified as the "RSA Data Security, Inc. MD5 Message-Digest
00163 Algorithm" in all material mentioning or referencing this software
00164 or this function.
00165 License is also granted to make and use derivative works provided
00166 that such works are identified as "derived from the RSA Data
00167 Security, Inc. MD5 Message-Digest Algorithm" in all material
00168 mentioning or referencing the derived work.
00169 RSA Data Security, Inc. makes no representations concerning either
00170 the merchantability of this software or the suitability of this
00171 software for any particular purpose. It is provided "as is"
00172 without express or implied warranty of any kind.
00173 These notices must be retained in any copies of any part of this
00174 documentation and/or software.
00175  */
00176 /* POINTER defines a generic pointer type */
00177 typedef unsigned char *POINTER;
00178 /* Constants for MD5Transform routine.
00179  */
00180 #define S11 7
00181 #define S12 12
00182 #define S13 17
00183 #define S14 22
00184 #define S21 5
00185 #define S22 9
00186 #define S23 14
00187 #define S24 20
00188 #define S31 4
00189 #define S32 11
00190 #define S33 16
00191 #define S34 23
00192 #define S41 6
00193 #define S42 10
00194 #define S43 15
00195 #define S44 21
00196 static void MD5Transform(UInt32*, const unsigned char*);
00197 static void Encode(unsigned char *, UInt32 *, UInt32);
00198 static void Decode(UInt32 *, const unsigned char *, UInt32);
00199 //static void MD5_memcpy(POINTER, POINTER, UInt32);
00200 //static void MD5_memset(POINTER, Int32, UInt32);
00201 static unsigned char PADDING[64] = {
00202    0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00203    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00204    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
00205 };
00206 /* F, G, H and I are basic MD5 functions.
00207  */
00208 #define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
00209 #define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
00210 #define H(x, y, z) ((x) ^ (y) ^ (z))
00211 #define I(x, y, z) ((y) ^ ((x) | (~z)))
00212 /* ROTATE_LEFT rotates x left n bits.
00213  */
00214 #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
00215 /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
00216 Rotation is separate from addition to prevent recomputation.
00217  */
00218 #define FF(a, b, c, d, x, s, ac) { \
00219  (a) += F ((b), (c), (d)) + (x) + static_cast<UInt32>(ac); \
00220  (a) = ROTATE_LEFT ((a), (s)); \
00221  (a) += (b); \
00222   }
00223 #define GG(a, b, c, d, x, s, ac) { \
00224  (a) += G ((b), (c), (d)) + (x) + static_cast<UInt32>(ac); \
00225  (a) = ROTATE_LEFT ((a), (s)); \
00226  (a) += (b); \
00227   }
00228 #define HH(a, b, c, d, x, s, ac) { \
00229  (a) += H ((b), (c), (d)) + (x) + static_cast<UInt32>(ac); \
00230  (a) = ROTATE_LEFT ((a), (s)); \
00231  (a) += (b); \
00232   }
00233 #define II(a, b, c, d, x, s, ac) { \
00234  (a) += I ((b), (c), (d)) + (x) + static_cast<UInt32>(ac); \
00235  (a) = ROTATE_LEFT ((a), (s)); \
00236  (a) += (b); \
00237   }
00238 /* MD5 initialization. Begins an MD5 operation, writing a new context.
00239  */ // STATIC
00240 void
00241    MD5::MD5Init(MD5_CTX* context)
00242 {
00243    context->count[0] = context->count[1] = 0;
00244    /* Load magic initialization constants.
00245  */
00246    context->state[0] = 0x67452301;
00247    context->state[1] = 0xefcdab89;
00248    context->state[2] = 0x98badcfe;
00249    context->state[3] = 0x10325476;
00250 }
00251 /* MD5 block update operation. Continues an MD5 message-digest
00252   operation, processing another message block, and updating the
00253   context.
00254  */ // STATIC
00255 void
00256    MD5::MD5Update(MD5_CTX* context, const unsigned char* input,
00257    UInt32 inputLen)
00258 {
00259    UInt32 i, index, partLen;
00260    /* Compute number of bytes mod 64 */
00261    index = ((context->count[0] >> 3) & 0x3F);
00262    /* Update number of bits */
00263    if ((context->count[0] += (inputLen << 3)) < (inputLen << 3))
00264    {
00265       context->count[1]++;
00266    }
00267    context->count[1] += (inputLen >> 29);
00268    partLen = 64 - index;
00269    /* Transform as many times as possible.
00270  */
00271    if (inputLen >= partLen)
00272    {
00273       memcpy(static_cast<POINTER>(&context->buffer[index]), 
00274          static_cast<const unsigned char*>(input), partLen);
00275       MD5Transform (context->state, context->buffer);
00276       for (i = partLen; i + 63 < inputLen; i += 64)
00277          MD5Transform (context->state, &input[i]);
00278       index = 0;
00279    }
00280    else
00281       i = 0;
00282    /* Buffer remaining input */
00283    memcpy
00284       (static_cast<POINTER>(&context->buffer[index]), 
00285          static_cast<const unsigned char*>(&input[i]),
00286       inputLen-i);
00287 }
00288 /* MD5 finalization. Ends an MD5 message-digest operation, writing the
00289   the message digest and zeroizing the context.
00290  */ // STATIC
00291 void
00292    MD5::MD5Final (unsigned char* digest, MD5_CTX* context)
00293 {
00294    unsigned char bits[8];
00295    UInt32 index, padLen;
00296    /* Save number of bits */
00297    Encode (bits, context->count, 8);
00298    /* Pad out to 56 mod 64.
00299  */
00300    index = ((context->count[0] >> 3) & 0x3f);
00301    padLen = (index < 56) ? (56 - index) : (120 - index);
00302    MD5Update (context, PADDING, padLen);
00303    /* Append length (before padding) */
00304    MD5Update (context, bits, 8);
00305    /* Store state in digest */
00306    Encode (digest, context->state, 16);
00307    /* Zeroize sensitive information.
00308  */
00309    memset (reinterpret_cast<POINTER>(context), 0, sizeof (*context));
00310 }
00311 /* MD5 basic transformation. Transforms state based on block.
00312  */
00313 static void MD5Transform (UInt32* state, const unsigned char* block)
00314 {
00315    UInt32 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
00316    Decode (x, block, 64);
00317    /* Round 1 */
00318    FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
00319    FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
00320    FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
00321    FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
00322    FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
00323    FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
00324    FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
00325    FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
00326    FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
00327    FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
00328    FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
00329    FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
00330    FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
00331    FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
00332    FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
00333    FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
00334    /* Round 2 */
00335    GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
00336    GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
00337    GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
00338    GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
00339    GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
00340    GG (d, a, b, c, x[10], S22,  0x2441453); /* 22 */
00341    GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
00342    GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
00343    GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
00344    GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
00345    GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
00346    GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
00347    GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
00348    GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
00349    GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
00350    GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
00351    /* Round 3 */
00352    HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
00353    HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
00354    HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
00355    HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
00356    HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
00357    HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
00358    HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
00359    HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
00360    HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
00361    HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
00362    HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
00363    HH (b, c, d, a, x[ 6], S34,  0x4881d05); /* 44 */
00364    HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
00365    HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
00366    HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
00367    HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
00368    /* Round 4 */
00369    II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
00370    II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
00371    II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
00372    II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
00373    II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
00374    II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
00375    II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
00376    II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
00377    II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
00378    II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
00379    II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
00380    II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
00381    II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
00382    II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
00383    II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
00384    II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
00385    state[0] += a;
00386    state[1] += b;
00387    state[2] += c;
00388    state[3] += d;
00389    /* Zeroize sensitive information. */
00390    memset (reinterpret_cast<POINTER>(x), 0, sizeof (x));
00391 }
00392 /* Encodes input (UInt32) into output (unsigned char). Assumes len is
00393   a multiple of 4.
00394  */
00395 static void Encode (unsigned char* output, UInt32* input, UInt32 len)
00396 {
00397    UInt32 i, j;
00398    for (i = 0, j = 0; j < len; i++, j += 4)
00399    {
00400       output[j] = (input[i] & 0xff);
00401       output[j+1] = ((input[i] >> 8) & 0xff);
00402       output[j+2] = ((input[i] >> 16) & 0xff);
00403       output[j+3] = ((input[i] >> 24) & 0xff);
00404    }
00405 }
00406 /* Decodes input (unsigned char) into output (UInt32). Assumes len is
00407   a multiple of 4.
00408  */
00409 static void Decode (UInt32* output, const unsigned char* input, UInt32 len)
00410 {
00411    UInt32 i, j;
00412    for (i = 0, j = 0; j < len; i++, j += 4)
00413       output[i] = (static_cast<UInt32>(input[j])) | ((static_cast<UInt32>(input[j+1])) << 8) |
00414          ((static_cast<UInt32>(input[j+2])) << 16) | ((static_cast<UInt32>(input[j+3])) << 24);
00415 }
00416 /* Note: Replace "for loop" with standard memcpy if possible.
00417  */
00418 //static void MD5_memcpy (POINTER output, POINTER input, UInt32 len)
00419 //{
00420    //UInt32 i;
00421    //for (i = 0; i < len; i++)
00422    // output[i] = input[i];
00423 //}
00424 /* Note: Replace "for loop" with standard memset if possible. */
00425 //static void MD5_memset (POINTER output, Int32 value, UInt32 len)
00426 //{
00427    //UInt32 i;
00428    //for (i = 0; i < len; i++)
00429    // ((char *)output)[i] = (char)value;
00430 //}
00431 
00432 } // end namespace BLOCXX_NAMESPACE
00433 
00434 
00435 #ifdef BLOCXX_WIN32
00436 #pragma warning (pop)
00437 #endif
00438 

Generated on Fri Jun 16 15:39:08 2006 for blocxx by  doxygen 1.4.6