blocxx

MD5.cpp

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