// // $Id: MD5.cpp 3659 2007-01-09 17:43:02Z bakerj $ // //****************************************************************************************// // Copyright (c) 2002-2007, The MITRE Corporation // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, are // permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, this list // of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, this // list of conditions and the following disclaimer in the documentation and/or other // materials provided with the distribution. // * Neither the name of The MITRE Corporation nor the names of its contributors may be // used to endorse or promote products derived from this software without specific // prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT // SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT // OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR // TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, // EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // //****************************************************************************************// // // MD5.cpp - source code for the C++/object oriented translation and // modification of MD5. // // Translation and modification (c) 1995 by Mordechai T. Abzug // // This translation/ modification is provided "as is," without express or // implied warranty of any kind. // // The translator/ modifier does not claim (1) that MD5 will do what you think // it does; (2) that this translation/ modification is accurate; or (3) that // this software is "merchantible." (Language for this disclaimer partially // copied from the disclaimer below). // //****************************************************************************************// // // Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All // rights reserved. // // License to copy and use this software is granted provided that it // is identified as the "RSA Data Security, Inc. MD5 Message-Digest // Algorithm" in all material mentioning or referencing this software // or this function. // // License is also granted to make and use derivative works provided // that such works are identified as "derived from the RSA Data // Security, Inc. MD5 Message-Digest Algorithm" in all material // mentioning or referencing the derived work. // // RSA Data Security, Inc. makes no representations concerning either // the merchantability of this software or the suitability of this // software for any particular purpose. It is provided "as is" // without express or implied warranty of any kind. // // These notices must be retained in any copies of any part of this // documentation and/or software. // //****************************************************************************************// #include "MD5.h" // MD5 simple initialization method MD5::MD5(){ init(); } // MD5 block update operation. Continues an MD5 message-digest // operation, processing another message block, and updating the // context. void MD5::update (uint1 *input, uint4 input_length) { uint4 input_index, buffer_index; uint4 buffer_space; // how much space is left in buffer if (finalized){ // so we can't update! cerr << "MD5::update: Can't update a finalized digest!" << endl; return; } // Compute number of bytes mod 64 buffer_index = (unsigned int)((count[0] >> 3) & 0x3F); // Update number of bits if ( (count[0] += ((uint4) input_length << 3))<((uint4) input_length << 3) ) count[1]++; count[1] += ((uint4)input_length >> 29); // SMC-AUDIT: REVIEW: buffer space calculations like this can sometimes hide overflows. // Careful mathematics is required to make sure there isn't a way to set buffer_index in // a way that screws up the resulting memcpy(). // // ARB: I assume they got it right? buffer_space = 64 - buffer_index; // how much space is left in buffer // Transform as many times as possible. if (input_length >= buffer_space) { // ie. we have enough to fill the buffer // fill the rest of the buffer and transform memcpy (buffer + buffer_index, input, buffer_space); transform (buffer); // now, transform each 64-byte piece of the input, bypassing the buffer for (input_index = buffer_space; input_index + 63 < input_length; input_index += 64) transform (input+input_index); buffer_index = 0; // so we can buffer remaining } else input_index=0; // so we can buffer the whole input // and here we do the buffering: memcpy(buffer+buffer_index, input+input_index, input_length-input_index); } // MD5 update for files. // Like above, except that it works on files (and uses above as a primitive.) void MD5::update(FILE *file){ unsigned char buffer[1024]; int len; while ((len=fread(buffer, 1, 1024, file))) update(buffer, len); fclose (file); } // MD5 finalization. Ends an MD5 message-digest operation, writing the // the message digest and zeroizing the context. void MD5::finalize (){ unsigned char bits[8]; unsigned int index, padLen; static uint1 PADDING[64]={ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; if (finalized){ cerr << "MD5::finalize: Already finalized this digest!" << endl; return; } // Save number of bits encode (bits, count, 8); // Pad out to 56 mod 64. index = (uint4) ((count[0] >> 3) & 0x3f); padLen = (index < 56) ? (56 - index) : (120 - index); update (PADDING, padLen); // Append length (before padding) update (bits, 8); // Store state in digest encode (digest, state, 16); ///////////////////////////////////////////////////////////////////////////////// // Zeroize sensitive information // // SMC-AUDIT: REVIEW: this memset only clears the first element of buffer, doesn't it? // shouldn't it be sizeof(buffer) instead? // // ARB: I would have to agree. Making the change. memset (buffer, 0, sizeof(buffer)); //memset (buffer, 0, sizeof(*buffer)); // ///////////////////////////////////////////////////////////////////////////////// finalized=1; } MD5::MD5(FILE *file){ init(); // must be called be all constructors update(file); finalize (); } unsigned char *MD5::raw_digest(){ uint1 *s = new uint1[16]; if (!finalized){ cerr << "MD5::raw_digest: Can't get digest if you haven't "<< "finalized the digest!" <> 8) & 0xff); output[j+2] = (uint1) ((input[i] >> 16) & 0xff); output[j+3] = (uint1) ((input[i] >> 24) & 0xff); } } // Decodes input (unsigned char) into output (UINT4). Assumes len is // a multiple of 4. void MD5::decode (uint4 *output, uint1 *input, uint4 len){ unsigned int i, j; for (i = 0, j = 0; j < len; i++, j += 4) output[i] = ((uint4)input[j]) | (((uint4)input[j+1]) << 8) | (((uint4)input[j+2]) << 16) | (((uint4)input[j+3]) << 24); } // Note: Replace "for loop" with standard memcpy if possible. void MD5::memcpy (uint1 *output, uint1 *input, uint4 len){ unsigned int i; for (i = 0; i < len; i++) output[i] = input[i]; } // Note: Replace "for loop" with standard memset if possible. void MD5::memset (uint1 *output, uint1 value, uint4 len){ unsigned int i; for (i = 0; i < len; i++) output[i] = value; } // ROTATE_LEFT rotates x left n bits. inline unsigned int MD5::rotate_left (uint4 x, uint4 n){ return (x << n) | (x >> (32-n)) ; } // F, G, H and I are basic MD5 functions. inline unsigned int MD5::F (uint4 x, uint4 y, uint4 z){ return (x & y) | (~x & z); } inline unsigned int MD5::G (uint4 x, uint4 y, uint4 z){ return (x & z) | (y & ~z); } inline unsigned int MD5::H (uint4 x, uint4 y, uint4 z){ return x ^ y ^ z; } inline unsigned int MD5::I (uint4 x, uint4 y, uint4 z){ return y ^ (x | ~z); } // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. // Rotation is separate from addition to prevent recomputation. inline void MD5::FF(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac){ a += F(b, c, d) + x + ac; a = rotate_left (a, s) +b; } inline void MD5::GG(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac){ a += G(b, c, d) + x + ac; a = rotate_left (a, s) +b; } inline void MD5::HH(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac){ a += H(b, c, d) + x + ac; a = rotate_left (a, s) +b; } inline void MD5::II(uint4& a, uint4 b, uint4 c, uint4 d, uint4 x, uint4 s, uint4 ac){ a += I(b, c, d) + x + ac; a = rotate_left (a, s) +b; }