md5.cpp (4349B)
1 #include "md5.h" 2 3 #include <cstring> // memcpy 4 #include <iomanip> 5 #include <sstream> 6 7 #define HEXN(S, n) std::hex << std::setfill('0') << std::setw(n) << (uint32_t)S 8 9 namespace baseLib 10 { 11 // leftrotate function definition 12 uint32_t leftrotate(const uint32_t x, const uint32_t c) 13 { 14 return (((x) << (c)) | ((x) >> (32 - (c)))); 15 } 16 17 // These vars will contain the hash: h0, h1, h2, h3 18 void md5(uint32_t& _h0, uint32_t& _h1, uint32_t& _h2, uint32_t& _h3, const uint8_t *_initialMsg, const uint32_t _initialLen) 19 { 20 // Note: All variables are unsigned 32 bit and wrap modulo 2^32 when calculating 21 22 // r specifies the per-round shift amounts 23 24 constexpr uint32_t r[] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 25 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 26 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 27 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 }; 28 29 // Use binary integer part of the sines of integers (in radians) as constants// Initialize variables: 30 constexpr uint32_t k[] = { 31 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 32 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 33 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 34 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, 35 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, 36 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, 37 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, 38 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 39 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 40 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 41 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 42 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 43 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 44 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 45 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 46 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 }; 47 48 _h0 = 0x67452301; 49 _h1 = 0xefcdab89; 50 _h2 = 0x98badcfe; 51 _h3 = 0x10325476; 52 53 // Pre-processing: adding a single 1 bit 54 //append "1" bit to message 55 /* Notice: the input bytes are considered as bits strings, 56 where the first bit is the most significant bit of the byte.[37] */ 57 58 // Pre-processing: padding with zeros 59 //append "0" bit until message length in bit ≡ 448 (mod 512) 60 //append length mod (2 pow 64) to message 61 62 const uint32_t newLen = ((((_initialLen + 8) / 64) + 1) * 64) - 8; 63 64 std::vector<uint8_t> buffer; 65 buffer.resize(newLen + 64, 0); 66 auto* msg = buffer.data(); 67 memcpy(msg, _initialMsg, _initialLen); 68 msg[_initialLen] = 128; // write the "1" bit 69 70 const uint32_t bitsLen = 8 * _initialLen; // note, we append the len 71 memcpy(msg + newLen, &bitsLen, 4); // in bits at the end of the buffer 72 73 // Process the message in successive 512-bit chunks: 74 //for each 512-bit chunk of message: 75 for (uint32_t offset = 0; offset < newLen; offset += (512 / 8)) 76 { 77 // break chunk into sixteen 32-bit words w[j], 0 ≤ j ≤ 15 78 const auto* w = reinterpret_cast<uint32_t*>(msg + offset); 79 80 // Initialize hash value for this chunk: 81 uint32_t a = _h0; 82 uint32_t b = _h1; 83 uint32_t c = _h2; 84 uint32_t d = _h3; 85 86 // Main loop: 87 for (uint32_t i = 0; i < 64; i++) 88 { 89 uint32_t f, g; 90 91 if (i < 16) { 92 f = (b & c) | ((~b) & d); 93 g = i; 94 } 95 else if (i < 32) { 96 f = (d & b) | ((~d) & c); 97 g = (5 * i + 1) % 16; 98 } 99 else if (i < 48) { 100 f = b ^ c ^ d; 101 g = (3 * i + 5) % 16; 102 } 103 else { 104 f = c ^ (b | (~d)); 105 g = (7 * i) % 16; 106 } 107 108 const uint32_t temp = d; 109 d = c; 110 c = b; 111 // printf("rotateLeft(%x + %x + %x + %x, %d)\n", a, f, k[i], w[g], r[i]); 112 b = b + leftrotate((a + f + k[i] + w[g]), r[i]); 113 a = temp; 114 } 115 116 // Add this chunk's hash to result so far: 117 118 _h0 += a; 119 _h1 += b; 120 _h2 += c; 121 _h3 += d; 122 123 } 124 } 125 126 MD5::MD5(const std::vector<uint8_t>& _data) : MD5(_data.data(), static_cast<uint32_t>(_data.size())) 127 { 128 } 129 130 MD5::MD5(const uint8_t* _data, const uint32_t _size) 131 { 132 md5(m_h[0], m_h[1], m_h[2], m_h[3], _data, _size); 133 } 134 135 std::string MD5::toString() const 136 { 137 std::stringstream ss; 138 139 for (const auto& e : m_h) 140 { 141 ss << HEXN((e & 0xff), 2); 142 ss << HEXN(((e>>8u) & 0xff), 2); 143 ss << HEXN(((e>>16u) & 0xff), 2); 144 ss << HEXN(((e>>24u) & 0xff), 2); 145 } 146 return ss.str(); 147 } 148 }