// This file is part of par2cmdline (a PAR 2.0 compatible file verification and // repair tool). See http://parchive.sourceforge.net for details of PAR 2.0. // // Copyright (c) 2003 Peter Brian Clements // // par2cmdline is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // par2cmdline is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA #include "par2cmdline.h" #ifdef _MSC_VER #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif #endif // Convert hash values to hex ostream& operator<<(ostream &result, const MD5Hash &h) { char buffer[33]; sprintf(buffer, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", h.hash[15], h.hash[14], h.hash[13], h.hash[12], h.hash[11], h.hash[10], h.hash[9], h.hash[8], h.hash[7], h.hash[6], h.hash[5], h.hash[4], h.hash[3], h.hash[2], h.hash[1], h.hash[0]); return result << buffer; } string MD5Hash::print(void) const { char buffer[33]; sprintf(buffer, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", hash[15], hash[14], hash[13], hash[12], hash[11], hash[10], hash[9], hash[8], hash[7], hash[6], hash[5], hash[4], hash[3], hash[2], hash[1], hash[0]); return buffer; } MD5State::MD5State(void) { Reset(); } // Initialise the 16 byte state void MD5State::Reset(void) { state[0] = 0x67452301; state[1] = 0xefcdab89; state[2] = 0x98badcfe; state[3] = 0x10325476; } // Update the state using 64 bytes of new data void MD5State::UpdateState(const u32 (&block)[16]) { // Primitive operations #define F1(x,y,z) ( ((x) & (y)) | ((~(x)) & (z)) ) #define F2(x,y,z) ( ((x) & (z)) | ((~(z)) & (y)) ) #define F3(x,y,z) ( (x) ^ (y) ^ (z) ) #define F4(x,y,z) ( (y) ^ ( (x) | ~(z) ) ) // The first version of ROL does not work on an Alpha CPU! //#define ROL(x,y) ( ((x) << (y)) | (((unsigned int)x) >> (32-y)) ) #define ROL(x,y) ( ((x) << (y)) | (((x) >> (32-y)) & ((1< 0) { size_t size = min(buffersize-used, length); Update(wordblock, size); length -= size; } // Update as many whole buffers as possible while (length >= buffersize) { Update(wordblock, buffersize); length -= buffersize; } // Update any remainder if (length > 0) { Update(wordblock, length); } } // Update using data from a buffer void MD5Context::Update(const void *buffer, size_t length) { const unsigned char *current = (const unsigned char *)buffer; // Update the total amount of data processed. bytes += length; // Process any whole blocks while (used + length >= buffersize) { size_t have = buffersize - used; memcpy(&block[used], current, have); current += have; length -= have; u32 wordblock[16]; for (int i=0; i<16; i++) { // Convert source data from little endian format to internal format if different wordblock[i] = ( ((u32)block[i*4+3]) << 24 ) | ( ((u32)block[i*4+2]) << 16 ) | ( ((u32)block[i*4+1]) << 8 ) | ( ((u32)block[i*4+0]) << 0 ); } MD5State::UpdateState(wordblock); used = 0; } // Store any remainder if (length > 0) { memcpy(&block[used], current, length); used += length; } } // Finalise the computation and extract the Hash value void MD5Context::Final(MD5Hash &output) { // Temporary work buffer u8 buffer[64]; // How many bits were processed u64 bits = bytes << 3; // Pad as much as needed so that there are exactly 8 bytes needed to fill the buffer size_t padding; if (used >= buffersize-8) { padding = buffersize-8 + buffersize - used; } else { padding = buffersize-8 - used; } memset(buffer, 0, padding); buffer[0] = 0x80; Update(buffer, padding); // Pad with an additional 8 bytes containing the bit count in little endian format buffer[7] = (unsigned char)((bits >> 56) & 0xFF); buffer[6] = (unsigned char)((bits >> 48) & 0xFF); buffer[5] = (unsigned char)((bits >> 40) & 0xFF); buffer[4] = (unsigned char)((bits >> 32) & 0xFF); buffer[3] = (unsigned char)((bits >> 24) & 0xFF); buffer[2] = (unsigned char)((bits >> 16) & 0xFF); buffer[1] = (unsigned char)((bits >> 8) & 0xFF); buffer[0] = (unsigned char)((bits >> 0) & 0xFF); Update(buffer, 8); for (int i = 0; i < 4; i++) { // Read out the state and convert it from internal format to little endian format output.hash[4*i+3] = (u8)((MD5State::state[i] >> 24) & 0xFF); output.hash[4*i+2] = (u8)((MD5State::state[i] >> 16) & 0xFF); output.hash[4*i+1] = (u8)((MD5State::state[i] >> 8) & 0xFF); output.hash[4*i+0] = (u8)((MD5State::state[i] >> 0) & 0xFF); } } // Return the Hash value MD5Hash MD5Context::Hash(void) const { MD5Hash output; for (unsigned int i = 0; i < 4; i++) { // Read out the state and convert it from internal format to little endian format output.hash[4*i+3] = (unsigned char)((MD5State::state[i] >> 24) & 0xFF); output.hash[4*i+2] = (unsigned char)((MD5State::state[i] >> 16) & 0xFF); output.hash[4*i+1] = (unsigned char)((MD5State::state[i] >> 8) & 0xFF); output.hash[4*i+0] = (unsigned char)((MD5State::state[i] >> 0) & 0xFF); } return output; } ostream& operator<<(ostream &result, const MD5Context &c) { char buffer[50]; sprintf(buffer, "%08X%08X%08X%08X:%08X%08X", c.state[3],c.state[2],c.state[1],c.state[0], (u32)((c.bytes >> 32) & 0xffffffff), (u32)(c.bytes & 0xffffffff)); return result << buffer; } string MD5Context::print(void) const { char buffer[50]; sprintf(buffer, "%08X%08X%08X%08X:%08X%08X", state[3],state[2],state[1],state[0], (u32)((bytes >> 32) & 0xffffffff), (u32)(bytes & 0xffffffff)); return buffer; }