// Copyright (C) 2003 Davis E. King (davis@dlib.net) // License: Boost Software License See LICENSE.txt for the full license. #ifndef DLIB_MD5_KERNEL_1_CPp_ #define DLIB_MD5_KERNEL_1_CPp_ #include "md5_kernel_1.h" #include "../uintn.h" #include <sstream> #include <cstring> namespace dlib { // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- namespace md5_stuff { inline uint32 F ( uint32 x, uint32 y, uint32 z ) { return ( (x&y) | ((~x)&z) ); } // ------------------------------------------------------------------------------------ inline uint32 G ( uint32 x, uint32 y, uint32 z ) { return ( (x&z) | (y&(~z)) ); } // ------------------------------------------------------------------------------------ inline uint32 H ( uint32 x, uint32 y, uint32 z ) { return ( x^y^z ); } // ------------------------------------------------------------------------------------ inline uint32 I ( uint32 x, uint32 y, uint32 z ) { return ( y ^ (x|(~z)) ); } // ------------------------------------------------------------------------------------ inline uint32 rotate_left ( uint32 x, uint32 n ) { return ( (x<<n) | (x>>(32-n)) ); } // ------------------------------------------------------------------------------------ inline void FF ( uint32& a, uint32 b, uint32 c, uint32 d, uint32 x, uint32 s, uint32 ac ) { a += F(b, c, d) + x + ac; a = rotate_left(a, s); a += b; } // ------------------------------------------------------------------------------------ inline void GG ( uint32& a, uint32 b, uint32 c, uint32 d, uint32 x, uint32 s, uint32 ac ) { a += G(b, c, d) + x + ac; a = rotate_left(a, s); a += b; } // ------------------------------------------------------------------------------------ inline void HH ( uint32& a, uint32 b, uint32 c, uint32 d, uint32 x, uint32 s, uint32 ac ) { a += H(b, c, d) + x + ac; a = rotate_left(a, s); a += b; } // ------------------------------------------------------------------------------------ inline void II ( uint32& a, uint32 b, uint32 c, uint32 d, uint32 x, uint32 s, uint32 ac ) { a += I(b, c, d) + x + ac; a = rotate_left(a, s); a += b; } // ------------------------------------------------------------------------------------ void scramble_block ( uint32& a, uint32& b, uint32& c, uint32& d, uint32* x ) { const uint32 S11 = 7; const uint32 S12 = 12; const uint32 S13 = 17; const uint32 S14 = 22; const uint32 S21 = 5; const uint32 S22 = 9; const uint32 S23 = 14; const uint32 S24 = 20; const uint32 S31 = 4; const uint32 S32 = 11; const uint32 S33 = 16; const uint32 S34 = 23; const uint32 S41 = 6; const uint32 S42 = 10; const uint32 S43 = 15; const uint32 S44 = 21; // round 1 FF (a, b, c, d, x[ 0], S11, 0xd76aa478); // 1 FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); // 2 FF (c, d, a, b, x[ 2], S13, 0x242070db); // 3 FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); // 4 FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); // 5 FF (d, a, b, c, x[ 5], S12, 0x4787c62a); // 6 FF (c, d, a, b, x[ 6], S13, 0xa8304613); // 7 FF (b, c, d, a, x[ 7], S14, 0xfd469501); // 8 FF (a, b, c, d, x[ 8], S11, 0x698098d8); // 9 FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); // 10 FF (c, d, a, b, x[10], S13, 0xffff5bb1); // 11 FF (b, c, d, a, x[11], S14, 0x895cd7be); // 12 FF (a, b, c, d, x[12], S11, 0x6b901122); // 13 FF (d, a, b, c, x[13], S12, 0xfd987193); // 14 FF (c, d, a, b, x[14], S13, 0xa679438e); // 15 FF (b, c, d, a, x[15], S14, 0x49b40821); // 16 // Round 2 GG (a, b, c, d, x[ 1], S21, 0xf61e2562); // 17 GG (d, a, b, c, x[ 6], S22, 0xc040b340); // 18 GG (c, d, a, b, x[11], S23, 0x265e5a51); // 19 GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); // 20 GG (a, b, c, d, x[ 5], S21, 0xd62f105d); // 21 GG (d, a, b, c, x[10], S22, 0x2441453); // 22 GG (c, d, a, b, x[15], S23, 0xd8a1e681); // 23 GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); // 24 GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); // 25 GG (d, a, b, c, x[14], S22, 0xc33707d6); // 26 GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); // 27 GG (b, c, d, a, x[ 8], S24, 0x455a14ed); // 28 GG (a, b, c, d, x[13], S21, 0xa9e3e905); // 29 GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); // 30 GG (c, d, a, b, x[ 7], S23, 0x676f02d9); // 31 GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); // 32 // Round 3 HH (a, b, c, d, x[ 5], S31, 0xfffa3942); // 33 HH (d, a, b, c, x[ 8], S32, 0x8771f681); // 34 HH (c, d, a, b, x[11], S33, 0x6d9d6122); // 35 HH (b, c, d, a, x[14], S34, 0xfde5380c); // 36 HH (a, b, c, d, x[ 1], S31, 0xa4beea44); // 37 HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); // 38 HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); // 39 HH (b, c, d, a, x[10], S34, 0xbebfbc70); // 40 HH (a, b, c, d, x[13], S31, 0x289b7ec6); // 41 HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); // 42 HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); // 43 HH (b, c, d, a, x[ 6], S34, 0x4881d05); // 44 HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); // 45 HH (d, a, b, c, x[12], S32, 0xe6db99e5); // 46 HH (c, d, a, b, x[15], S33, 0x1fa27cf8); // 47 HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); // 48 // Round 4 II (a, b, c, d, x[ 0], S41, 0xf4292244); // 49 II (d, a, b, c, x[ 7], S42, 0x432aff97); // 50 II (c, d, a, b, x[14], S43, 0xab9423a7); // 51 II (b, c, d, a, x[ 5], S44, 0xfc93a039); // 52 II (a, b, c, d, x[12], S41, 0x655b59c3); // 53 II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); // 54 II (c, d, a, b, x[10], S43, 0xffeff47d); // 55 II (b, c, d, a, x[ 1], S44, 0x85845dd1); // 56 II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); // 57 II (d, a, b, c, x[15], S42, 0xfe2ce6e0); // 58 II (c, d, a, b, x[ 6], S43, 0xa3014314); // 59 II (b, c, d, a, x[13], S44, 0x4e0811a1); // 60 II (a, b, c, d, x[ 4], S41, 0xf7537e82); // 61 II (d, a, b, c, x[11], S42, 0xbd3af235); // 62 II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); // 63 II (b, c, d, a, x[ 9], S44, 0xeb86d391); // 64 } } // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- const std::string md5 ( const std::string& input ) { unsigned char output[16]; md5 ( reinterpret_cast<const unsigned char*>(input.data()), static_cast<unsigned long>(input.size()), output ); std::stringstream temp; for (int i = 0; i < 16; ++i) { temp.fill('0'); temp.width(2); temp << std::hex << static_cast<unsigned int>(output[i]); } return temp.str(); } // ---------------------------------------------------------------------------------------- void md5 ( const unsigned char* input, unsigned long len, unsigned char* output ) { using namespace md5_stuff; // make a temp version of input with enough space for padding and len appended unsigned long extra_len = 64-len%64; if (extra_len <= 8) extra_len += 64; unsigned char* temp = new unsigned char[extra_len + len]; // number of 16 word blocks const unsigned long N = (extra_len + len)/64; const unsigned char* input2 = input; unsigned char* temp2 = temp; unsigned char* end = temp+len; // copy input into temp while (temp2 != end) { *temp2 = *input2; ++temp2; ++input2; } // pad temp end += extra_len-8; *temp2 = static_cast<unsigned char>(0x80); ++temp2; while (temp2 != end) { *temp2 = 0; ++temp2; } // make len the number of bits in the original message // but first multiply len by 8 and since len is only 32 bits the number might // overflow so we will carry out the multiplication manually and end up with // the result in the base 65536 number with three digits // result = low + high*65536 + upper*65536*65536 unsigned long low = len & 0xFFFF; unsigned long high = len >> 16; unsigned long upper; unsigned long tmp; tmp = low * 8; low = tmp & 0xFFFF; tmp = high * 8 + (tmp>>16); high = tmp & 0xFFFF; upper = tmp >> 16; // append the length *temp2 = static_cast<unsigned char>(low&0xFF); ++temp2; *temp2 = static_cast<unsigned char>((low>>8)&0xFF); ++temp2; *temp2 = static_cast<unsigned char>((high)&0xFF); ++temp2; *temp2 = static_cast<unsigned char>((high>>8)&0xFF); ++temp2; *temp2 = static_cast<unsigned char>((upper)&0xFF);; ++temp2; *temp2 = static_cast<unsigned char>((upper>>8)&0xFF);; ++temp2; *temp2 = 0; ++temp2; *temp2 = 0; uint32 a = 0x67452301; uint32 b = 0xefcdab89; uint32 c = 0x98badcfe; uint32 d = 0x10325476; // an array of 16 words uint32 x[16]; for (unsigned long i = 0; i < N; ++i) { // copy a block of 16 words from m into x for (unsigned long j = 0; j < 16; ++j) { x[j] = ( (static_cast<uint32>(temp[4*(j + 16*i) + 3]) << 24) | (static_cast<uint32>(temp[4*(j + 16*i) + 2]) << 16) | (static_cast<uint32>(temp[4*(j + 16*i) + 1]) << 8 ) | (static_cast<uint32>(temp[4*(j + 16*i) ]) ) ); } uint32 aa = a; uint32 bb = b; uint32 cc = c; uint32 dd = d; scramble_block(a,b,c,d,x); a = a + aa; b = b + bb; c = c + cc; d = d + dd; } // put a, b, c, and d into output output[0] = static_cast<unsigned char>((a) &0xFF); output[1] = static_cast<unsigned char>((a>>8) &0xFF); output[2] = static_cast<unsigned char>((a>>16)&0xFF); output[3] = static_cast<unsigned char>((a>>24)&0xFF); output[4] = static_cast<unsigned char>((b) &0xFF); output[5] = static_cast<unsigned char>((b>>8) &0xFF); output[6] = static_cast<unsigned char>((b>>16)&0xFF); output[7] = static_cast<unsigned char>((b>>24)&0xFF); output[8] = static_cast<unsigned char>((c) &0xFF); output[9] = static_cast<unsigned char>((c>>8) &0xFF); output[10] = static_cast<unsigned char>((c>>16)&0xFF); output[11] = static_cast<unsigned char>((c>>24)&0xFF); output[12] = static_cast<unsigned char>((d) &0xFF); output[13] = static_cast<unsigned char>((d>>8) &0xFF); output[14] = static_cast<unsigned char>((d>>16)&0xFF); output[15] = static_cast<unsigned char>((d>>24)&0xFF); delete [] temp; } // ---------------------------------------------------------------------------------------- const std::string md5 ( std::istream& input ) { unsigned char output[16]; md5 ( input, output ); std::stringstream temp; for (int i = 0; i < 16; ++i) { temp.fill('0'); temp.width(2); temp << std::hex << static_cast<unsigned int>(output[i]); } return temp.str(); } // ---------------------------------------------------------------------------------------- void md5 ( std::istream& input, unsigned char* output ) { using namespace md5_stuff; uint32 a = 0x67452301; uint32 b = 0xefcdab89; uint32 c = 0x98badcfe; uint32 d = 0x10325476; std::streamsize len = 0; // an array of 16 words uint32 x[16]; unsigned char temp[64]; bool write_length = false; bool at_end = false; std::streambuf& inputbuf = *input.rdbuf(); while(!at_end) { std::streamsize num = inputbuf.sgetn(reinterpret_cast<char*>(temp),64); len += num; // if we hit the end of the stream then pad and add length if (num < 64) { at_end = true; unsigned char* temp2 = temp; unsigned char* end; if (num < 56) end = temp+56; else end = temp+64; temp2 += num; // apply padding *temp2 = 0x80; ++temp2; while (temp2 != end) { *temp2 = 0; ++temp2; } if (num < 56) { write_length = true; // make len the number of bits in the original message // but first multiply len by 8 and since len is only 32 bits the number might // overflow so we will carry out the multiplication manually and end up with // the result in the base 65536 number with three digits // result = low + high*65536 + upper*65536*65536 unsigned long low = len & 0xFFFF; unsigned long high = len >> 16; unsigned long upper; unsigned long tmp; tmp = low * 8; low = tmp & 0xFFFF; tmp = high * 8 + (tmp>>16); high = tmp & 0xFFFF; upper = tmp >> 16; // append the length *temp2 = static_cast<unsigned char>(low&0xFF); ++temp2; *temp2 = static_cast<unsigned char>((low>>8)&0xFF); ++temp2; *temp2 = static_cast<unsigned char>((high)&0xFF); ++temp2; *temp2 = static_cast<unsigned char>((high>>8)&0xFF); ++temp2; *temp2 = static_cast<unsigned char>((upper)&0xFF);; ++temp2; *temp2 = static_cast<unsigned char>((upper>>8)&0xFF);; ++temp2; *temp2 = 0; ++temp2; *temp2 = 0; } } // copy a block of 16 words from m into x for (unsigned long i = 0; i < 16; ++i) { x[i] = ( (static_cast<uint32>(temp[4*i + 3]) << 24) | (static_cast<uint32>(temp[4*i + 2]) << 16) | (static_cast<uint32>(temp[4*i + 1]) << 8 ) | (static_cast<uint32>(temp[4*i ]) ) ); } uint32 aa = a; uint32 bb = b; uint32 cc = c; uint32 dd = d; scramble_block(a,b,c,d,x); a = a + aa; b = b + bb; c = c + cc; d = d + dd; } if (!write_length) { uint64 temp = len*8; uint32 aa = a; uint32 bb = b; uint32 cc = c; uint32 dd = d; std::memset(x, 0, sizeof(x)); x[15] = (temp>>32); x[14] = (temp&0xFFFFFFFF); scramble_block(a,b,c,d,x); a = a + aa; b = b + bb; c = c + cc; d = d + dd; } // put a, b, c, and d into output output[0] = static_cast<unsigned char>((a) &0xFF); output[1] = static_cast<unsigned char>((a>>8) &0xFF); output[2] = static_cast<unsigned char>((a>>16)&0xFF); output[3] = static_cast<unsigned char>((a>>24)&0xFF); output[4] = static_cast<unsigned char>((b) &0xFF); output[5] = static_cast<unsigned char>((b>>8) &0xFF); output[6] = static_cast<unsigned char>((b>>16)&0xFF); output[7] = static_cast<unsigned char>((b>>24)&0xFF); output[8] = static_cast<unsigned char>((c) &0xFF); output[9] = static_cast<unsigned char>((c>>8) &0xFF); output[10] = static_cast<unsigned char>((c>>16)&0xFF); output[11] = static_cast<unsigned char>((c>>24)&0xFF); output[12] = static_cast<unsigned char>((d) &0xFF); output[13] = static_cast<unsigned char>((d>>8) &0xFF); output[14] = static_cast<unsigned char>((d>>16)&0xFF); output[15] = static_cast<unsigned char>((d>>24)&0xFF); input.clear(std::ios::eofbit); } // ---------------------------------------------------------------------------------------- } #endif // DLIB_MD5_KERNEL_1_CPp_