1 #include "stdafx.h"
2 /*
3 * Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm
4 * and modified slightly to be functionally identical but condensed into control structures.
5 */
6
7 #include "md5.h"
8
9 /*
10 * Constants defined by the MD5 algorithm
11 */
12 #define A 0x67452301
13 #define B 0xefcdab89
14 #define C 0x98badcfe
15 #define D 0x10325476
16 #define BLOCK_SIZE 64
17 #define DIGEST_LENGTH 16
18
19 static uint32_t s[] = { 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
20 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
21 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
22 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21 };
23
24 static uint32_t K[] = { 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
25 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
26 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
27 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
28 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
29 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
30 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
31 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
32 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
33 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
34 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
35 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
36 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
37 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
38 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
39 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 };
40
readUint32LE(uint8_t * ptr,size_t pos)41 uint32_t readUint32LE(uint8_t* ptr, size_t pos) {
42 return ((int32_t)ptr[pos + 3] << 24) | ((int32_t)ptr[pos + 2] << 16) | ((int32_t)ptr[pos + 1] << 8) | (int32_t)ptr[pos];
43 }
44
writeUint32LE(uint32_t value,uint8_t * out,size_t offset=0)45 void writeUint32LE(uint32_t value, uint8_t* out, size_t offset = 0) {
46 out[offset] = value;
47 out[offset + 1] = value >> 8;
48 out[offset + 2] = value >> 16;
49 out[offset + 3] = value >> 24;
50 }
51
md5Hash(MD5Context * ctx,uint8_t * p,size_t pos,size_t len)52 size_t md5Hash(MD5Context* ctx, uint8_t* p, size_t pos, size_t len) {
53 uint32_t* w = ctx->temp;
54 uint32_t* v = ctx->state;
55 while (len >= 64) {
56 auto a = v[0];
57 auto b = v[1];
58 auto c = v[2];
59 auto d = v[3];
60 for (auto i = 0; i < 16; i++) {
61 size_t j = pos + (size_t)i * 4;
62 w[i] = readUint32LE(p, j);
63 }
64 for (auto i = 0; i < 64; i++) {
65 uint32_t F = 0, g = 0;
66 if (i >= 0 && i <= 15) {
67 F = d ^ (b & (c ^ d));
68 g = i;
69 } else if (i >= 16 && i <= 31) {
70 F = c ^ (d & (b ^ c));
71 g = (5 * i + 1) % 16;
72 } else if (i >= 32 && i <= 47) {
73 F = b ^ c ^ d;
74 g = (3 * i + 5) % 16;
75 } else {
76 F = c ^ (b | ~d);
77 g = (7 * i) % 16;
78 }
79 F = F + a + K[i] + w[g];
80 a = d;
81 d = c;
82 c = b;
83 b = b + rotateLeft(F, s[i]);
84 }
85 v[0] = v[0] + a;
86 v[1] = v[1] + b;
87 v[2] = v[2] + c;
88 v[3] = v[3] + d;
89 pos += 64;
90 len -= 64;
91 }
92 return pos;
93 }
94
95 /*
96 * Initialize a context
97 */
md5Init(MD5Context * ctx)98 void md5Init(MD5Context* ctx) {
99 ctx->bytesHashed = 0;
100 ctx->bufferLength = 0;
101
102 ctx->state[0] = (uint32_t)A;
103 ctx->state[1] = (uint32_t)B;
104 ctx->state[2] = (uint32_t)C;
105 ctx->state[3] = (uint32_t)D;
106 }
107
108 /*
109 * Add some amount of input to the context
110 *
111 * If the input fills out a block of 512 bits, apply the algorithm (md5Step)
112 * and save the result in the buffer. Also updates the overall size.
113 */
md5Update(MD5Context * ctx,uint8_t * data,size_t dataLength)114 void md5Update(MD5Context* ctx, uint8_t* data, size_t dataLength) {
115 size_t dataPos = 0;
116 ctx->bytesHashed += dataLength;
117 if (ctx->bufferLength > 0) {
118 while (ctx->bufferLength < BLOCK_SIZE && dataLength > 0) {
119 ctx->buffer[ctx->bufferLength++] = data[dataPos++];
120 dataLength--;
121 }
122 if (ctx->bufferLength == BLOCK_SIZE) {
123 md5Hash(ctx, ctx->buffer, 0, BLOCK_SIZE);
124 ctx->bufferLength = 0;
125 }
126 }
127 if (dataLength >= BLOCK_SIZE) {
128 dataPos = md5Hash(ctx, data, dataPos, dataLength);
129 dataLength %= BLOCK_SIZE;
130 }
131 while (dataLength > 0) {
132 ctx->buffer[ctx->bufferLength++] = data[dataPos++];
133 dataLength--;
134 }
135 }
136
137 /*
138 * Pad the current input to get to 448 bytes, append the size in bits to the very end,
139 * and save the result of the final iteration into digest.
140 */
md5Finalize(MD5Context * ctx)141 void md5Finalize(MD5Context* ctx) {
142 uint32_t bitLenHi = (ctx->bytesHashed / 0x20000000) | 0;
143 uint32_t bitLenLo = ctx->bytesHashed << 3;
144 size_t padLength = ((ctx->bytesHashed) % 64 < 56) ? 64 : 128;
145 ctx->buffer[ctx->bufferLength] = 0x80;
146 for (size_t i = ctx->bufferLength + 1; i < padLength - 8; i++) {
147 ctx->buffer[i] = 0;
148 }
149 writeUint32LE(bitLenLo, ctx->buffer, padLength - 8);
150 writeUint32LE(bitLenHi, ctx->buffer, padLength - 4);
151 md5Hash(ctx, ctx->buffer, 0, padLength);
152 for (auto i = 0; i < DIGEST_LENGTH / 4; i++) {
153 writeUint32LE(ctx->state[i], ctx->digest, (size_t)i * 4);
154 }
155 }
156
157 /*
158 * Rotates a 32-bit word left by n bits
159 */
rotateLeft(uint32_t x,uint32_t n)160 uint32_t rotateLeft(uint32_t x, uint32_t n) {
161 return (x << n) | (x >> (32 - n));
162 }
163
MD5()164 MD5::MD5() {
165 md5Init(&ctx);
166 m_finalized = false;
167 }
168
Digest()169 std::string MD5::Digest() {
170 if (!m_finalized) {
171 Finalize();
172 }
173 return std::string((char*)ctx.digest, 16);
174 }
175
Finalize()176 void MD5::Finalize() {
177 md5Finalize(&ctx);
178 m_finalized = true;
179 }
180
str_hex(std::string input)181 std::string str_hex(std::string input) {
182 if (input.empty()) return "";
183 const char* t = "0123456789abcdef";
184 std::string output;
185 for (auto i = input.begin(); i != input.end(); i++) {
186 unsigned char c = *i;
187 output += t[c / 16];
188 output += t[c % 16];
189 }
190 return output;
191 }
192
HexDigest()193 std::string MD5::HexDigest() {
194 return str_hex(Digest());
195 }
196
Update(std::string data)197 void MD5::Update(std::string data) {
198 if (m_finalized) {
199 return;
200 }
201 md5Update(&ctx, (uint8_t*)data.c_str(), data.size());
202 }
203
Update(std::wstring data,CodeType code,bool * char_cannot_convert)204 void MD5::Update(std::wstring data, CodeType code, bool* char_cannot_convert) {
205 Update(CCommon::UnicodeToStr(data, code, char_cannot_convert));
206 }
207