edouard@3940: /* MD5 edouard@3940: converted to C++ class by Frank Thilo (thilo@unix-ag.org) edouard@3940: for bzflag (http://www.bzflag.org) edouard@3940: edouard@3940: based on: edouard@3940: edouard@3940: md5.h and md5.c edouard@3940: reference implemantion of RFC 1321 edouard@3940: edouard@3940: Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All edouard@3940: rights reserved. edouard@3940: edouard@3940: License to copy and use this software is granted provided that it edouard@3940: is identified as the "RSA Data Security, Inc. MD5 Message-Digest edouard@3940: Algorithm" in all material mentioning or referencing this software edouard@3940: or this function. edouard@3940: edouard@3940: License is also granted to make and use derivative works provided edouard@3940: that such works are identified as "derived from the RSA Data edouard@3940: Security, Inc. MD5 Message-Digest Algorithm" in all material edouard@3940: mentioning or referencing the derived work. edouard@3940: edouard@3940: RSA Data Security, Inc. makes no representations concerning either edouard@3940: the merchantability of this software or the suitability of this edouard@3940: software for any particular purpose. It is provided "as is" edouard@3940: without express or implied warranty of any kind. edouard@3940: edouard@3940: These notices must be retained in any copies of any part of this edouard@3940: documentation and/or software. edouard@3940: edouard@3940: */ edouard@3940: edouard@3940: #include edouard@3940: #include edouard@3940: edouard@3940: /* interface header */ edouard@3940: #include "md5.hpp" edouard@3940: edouard@3940: // Constants for MD5Transform routine. edouard@3940: #define S11 7 edouard@3940: #define S12 12 edouard@3940: #define S13 17 edouard@3940: #define S14 22 edouard@3940: #define S21 5 edouard@3940: #define S22 9 edouard@3940: #define S23 14 edouard@3940: #define S24 20 edouard@3940: #define S31 4 edouard@3940: #define S32 11 edouard@3940: #define S33 16 edouard@3940: #define S34 23 edouard@3940: #define S41 6 edouard@3940: #define S42 10 edouard@3940: #define S43 15 edouard@3940: #define S44 21 edouard@3940: edouard@3940: /////////////////////////////////////////////// edouard@3940: edouard@3940: // F, G, H and I are basic MD5 functions. edouard@3940: inline uint32_t MD5::F(uint32_t x, uint32_t y, uint32_t z) edouard@3940: { edouard@3940: return x & y | ~x & z; edouard@3940: } edouard@3940: edouard@3940: inline uint32_t MD5::G(uint32_t x, uint32_t y, uint32_t z) edouard@3940: { edouard@3940: return x & z | y & ~z; edouard@3940: } edouard@3940: edouard@3940: inline uint32_t MD5::H(uint32_t x, uint32_t y, uint32_t z) edouard@3940: { edouard@3940: return x ^ y ^ z; edouard@3940: } edouard@3940: edouard@3940: inline uint32_t MD5::I(uint32_t x, uint32_t y, uint32_t z) edouard@3940: { edouard@3940: return y ^ (x | ~z); edouard@3940: } edouard@3940: edouard@3940: // rotate_left rotates x left n bits. edouard@3940: inline uint32_t MD5::rotate_left(uint32_t x, int n) edouard@3940: { edouard@3940: return (x << n) | (x >> (32 - n)); edouard@3940: } edouard@3940: edouard@3940: // FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. edouard@3940: // Rotation is separate from addition to prevent recomputation. edouard@3940: inline void MD5::FF(uint32_t &a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac) edouard@3940: { edouard@3940: a = rotate_left(a + F(b, c, d) + x + ac, s) + b; edouard@3940: } edouard@3940: edouard@3940: inline void MD5::GG(uint32_t &a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac) edouard@3940: { edouard@3940: a = rotate_left(a + G(b, c, d) + x + ac, s) + b; edouard@3940: } edouard@3940: edouard@3940: inline void MD5::HH(uint32_t &a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac) edouard@3940: { edouard@3940: a = rotate_left(a + H(b, c, d) + x + ac, s) + b; edouard@3940: } edouard@3940: edouard@3940: inline void MD5::II(uint32_t &a, uint32_t b, uint32_t c, uint32_t d, uint32_t x, uint32_t s, uint32_t ac) edouard@3940: { edouard@3940: a = rotate_left(a + I(b, c, d) + x + ac, s) + b; edouard@3940: } edouard@3940: edouard@3940: ////////////////////////////////////////////// edouard@3940: edouard@3940: // default ctor, just initailize edouard@3940: MD5::MD5() edouard@3940: { edouard@3940: init(); edouard@3940: } edouard@3940: edouard@3940: ////////////////////////////// edouard@3940: edouard@3940: void MD5::init() edouard@3940: { edouard@3940: count[0] = 0; edouard@3940: count[1] = 0; edouard@3940: edouard@3940: // load magic initialization constants. edouard@3940: state[0] = 0x67452301; edouard@3940: state[1] = 0xefcdab89; edouard@3940: state[2] = 0x98badcfe; edouard@3940: state[3] = 0x10325476; edouard@3940: } edouard@3940: edouard@3940: ////////////////////////////// edouard@3940: edouard@3940: // decodes input (unsigned char) into output (uint32_t). Assumes len is a multiple of 4. edouard@3940: void MD5::decode(uint32_t output[], const uint8_t input[], size_type len) edouard@3940: { edouard@3940: for (unsigned int i = 0, j = 0; j < len; i++, j += 4) edouard@3940: output[i] = ((uint32_t)input[j]) | (((uint32_t)input[j + 1]) << 8) | edouard@3940: (((uint32_t)input[j + 2]) << 16) | (((uint32_t)input[j + 3]) << 24); edouard@3940: } edouard@3940: edouard@3940: ////////////////////////////// edouard@3940: edouard@3940: // encodes input (uint32_t) into output (unsigned char). Assumes len is edouard@3940: // a multiple of 4. edouard@3940: void MD5::encode(uint8_t output[], const uint32_t input[], size_type len) edouard@3940: { edouard@3940: for (size_type i = 0, j = 0; j < len; i++, j += 4) edouard@3940: { edouard@3940: output[j] = input[i] & 0xff; edouard@3940: output[j + 1] = (input[i] >> 8) & 0xff; edouard@3940: output[j + 2] = (input[i] >> 16) & 0xff; edouard@3940: output[j + 3] = (input[i] >> 24) & 0xff; edouard@3940: } edouard@3940: } edouard@3940: edouard@3940: ////////////////////////////// edouard@3940: edouard@3940: // apply MD5 algo on a block edouard@3940: void MD5::transform(const uint8_t block[blocksize]) edouard@3940: { edouard@3940: uint32_t a = state[0], b = state[1], c = state[2], d = state[3], x[16]; edouard@3940: decode(x, block, blocksize); edouard@3940: edouard@3940: /* Round 1 */ edouard@3940: FF(a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */ edouard@3940: FF(d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */ edouard@3940: FF(c, d, a, b, x[2], S13, 0x242070db); /* 3 */ edouard@3940: FF(b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */ edouard@3940: FF(a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */ edouard@3940: FF(d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */ edouard@3940: FF(c, d, a, b, x[6], S13, 0xa8304613); /* 7 */ edouard@3940: FF(b, c, d, a, x[7], S14, 0xfd469501); /* 8 */ edouard@3940: FF(a, b, c, d, x[8], S11, 0x698098d8); /* 9 */ edouard@3940: FF(d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */ edouard@3940: FF(c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ edouard@3940: FF(b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ edouard@3940: FF(a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ edouard@3940: FF(d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ edouard@3940: FF(c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ edouard@3940: FF(b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ edouard@3940: edouard@3940: /* Round 2 */ edouard@3940: GG(a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */ edouard@3940: GG(d, a, b, c, x[6], S22, 0xc040b340); /* 18 */ edouard@3940: GG(c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ edouard@3940: GG(b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */ edouard@3940: GG(a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */ edouard@3940: GG(d, a, b, c, x[10], S22, 0x2441453); /* 22 */ edouard@3940: GG(c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ edouard@3940: GG(b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */ edouard@3940: GG(a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */ edouard@3940: GG(d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ edouard@3940: GG(c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */ edouard@3940: GG(b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */ edouard@3940: GG(a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ edouard@3940: GG(d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */ edouard@3940: GG(c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */ edouard@3940: GG(b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ edouard@3940: edouard@3940: /* Round 3 */ edouard@3940: HH(a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */ edouard@3940: HH(d, a, b, c, x[8], S32, 0x8771f681); /* 34 */ edouard@3940: HH(c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ edouard@3940: HH(b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ edouard@3940: HH(a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */ edouard@3940: HH(d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */ edouard@3940: HH(c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */ edouard@3940: HH(b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ edouard@3940: HH(a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ edouard@3940: HH(d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */ edouard@3940: HH(c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */ edouard@3940: HH(b, c, d, a, x[6], S34, 0x4881d05); /* 44 */ edouard@3940: HH(a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */ edouard@3940: HH(d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ edouard@3940: HH(c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ edouard@3940: HH(b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */ edouard@3940: edouard@3940: /* Round 4 */ edouard@3940: II(a, b, c, d, x[0], S41, 0xf4292244); /* 49 */ edouard@3940: II(d, a, b, c, x[7], S42, 0x432aff97); /* 50 */ edouard@3940: II(c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ edouard@3940: II(b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */ edouard@3940: II(a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ edouard@3940: II(d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */ edouard@3940: II(c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ edouard@3940: II(b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */ edouard@3940: II(a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */ edouard@3940: II(d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ edouard@3940: II(c, d, a, b, x[6], S43, 0xa3014314); /* 59 */ edouard@3940: II(b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ edouard@3940: II(a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */ edouard@3940: II(d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ edouard@3940: II(c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */ edouard@3940: II(b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */ edouard@3940: edouard@3940: state[0] += a; edouard@3940: state[1] += b; edouard@3940: state[2] += c; edouard@3940: state[3] += d; edouard@3940: edouard@3940: // Zeroize sensitive information. edouard@3940: memset(x, 0, sizeof x); edouard@3940: } edouard@3940: edouard@3940: ////////////////////////////// edouard@3940: edouard@3940: // MD5 block update operation. Continues an MD5 message-digest edouard@3940: // operation, processing another message block edouard@3940: void MD5::update(const unsigned char input[], size_type length) edouard@3940: { edouard@3940: // compute number of bytes mod 64 edouard@3940: size_type index = count[0] / 8 % blocksize; edouard@3940: edouard@3940: // Update number of bits edouard@3940: if ((count[0] += (length << 3)) < (length << 3)) edouard@3940: count[1]++; edouard@3940: count[1] += (length >> 29); edouard@3940: edouard@3940: // number of bytes we need to fill in buffer edouard@3940: size_type firstpart = 64 - index; edouard@3940: edouard@3940: size_type i; edouard@3940: edouard@3940: // transform as many times as possible. edouard@3940: if (length >= firstpart) edouard@3940: { edouard@3940: // fill buffer first, transform edouard@3940: memcpy(&buffer[index], input, firstpart); edouard@3940: transform(buffer); edouard@3940: edouard@3940: // transform chunks of blocksize (64 bytes) edouard@3940: for (i = firstpart; i + blocksize <= length; i += blocksize) edouard@3940: transform(&input[i]); edouard@3940: edouard@3940: index = 0; edouard@3940: } edouard@3940: else edouard@3940: i = 0; edouard@3940: edouard@3940: // buffer remaining input edouard@3940: memcpy(&buffer[index], &input[i], length - i); edouard@3940: } edouard@3940: edouard@3940: ////////////////////////////// edouard@3940: edouard@3940: edouard@3940: MD5::digest_t MD5::digest() edouard@3940: { edouard@3940: static const unsigned char padding[64] = { edouard@3940: 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, edouard@3940: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, edouard@3940: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; edouard@3940: edouard@3940: // Copies of hash state edouard@3940: uint8_t _buffer[blocksize]; edouard@3940: uint32_t _count[2]; edouard@3940: uint32_t _state[4]; edouard@3940: edouard@3940: // Backup hash state at previous block boundary edouard@3940: memcpy(_buffer, buffer, blocksize); edouard@3940: memcpy(_count, count, 8); edouard@3940: memcpy(_state, state, 16); edouard@3940: edouard@3940: // Save number of bits edouard@3940: unsigned char bits[8]; edouard@3940: encode(bits, count, 8); edouard@3940: edouard@3940: // pad out to 56 mod 64. edouard@3940: size_type index = count[0] / 8 % 64; edouard@3940: size_type padLen = (index < 56) ? (56 - index) : (120 - index); edouard@3940: update(padding, padLen); edouard@3940: edouard@3940: // Append length (before padding) edouard@3940: update(bits, 8); edouard@3940: edouard@3940: // Store state in digest edouard@3940: digest_t result; edouard@3940: encode(result.data, state, 16); edouard@3940: edouard@3940: // revert hash state to previous hash boundary edouard@3940: memcpy(buffer, _buffer, blocksize); edouard@3940: memcpy(count, _count, 8); edouard@3940: memcpy(state, _state, 16); edouard@3940: edouard@3940: return result; edouard@3940: }