// 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_