CMSDK 2.0.1
Cross-platform C++ base library and SDK for the Psyclone AIOS platform
Loading...
Searching...
No Matches
md5.cpp
Go to the documentation of this file.
1
6// //////////////////////////////////////////////////////////
7// md5.cpp
8// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
9// see http://create.stephan-brumme.com/disclaimer.html
10//
11
12#include "hash/md5.h"
14
15#ifndef _MSC_VER
16#ifndef __APPLE__
17#include <endian.h>
18#endif
19#endif
20
21// Added namespace to avoid clash with OpenSSL
22namespace hash {
23
26{
27 reset();
28}
29
30
32void MD5::reset()
33{
34 m_numBytes = 0;
35 m_bufferSize = 0;
36
37 // according to RFC 1321
38 m_hash[0] = 0x67452301;
39 m_hash[1] = 0xefcdab89;
40 m_hash[2] = 0x98badcfe;
41 m_hash[3] = 0x10325476;
42}
43
44
45namespace
46{
47 // mix functions for processBlock()
48 inline uint32_t f1(uint32_t b, uint32_t c, uint32_t d)
49 {
50 return d ^ (b & (c ^ d)); // original: f = (b & c) | ((~b) & d);
51 }
52
53 inline uint32_t f2(uint32_t b, uint32_t c, uint32_t d)
54 {
55 return c ^ (d & (b ^ c)); // original: f = (b & d) | (c & (~d));
56 }
57
58 inline uint32_t f3(uint32_t b, uint32_t c, uint32_t d)
59 {
60 return b ^ c ^ d;
61 }
62
63 inline uint32_t f4(uint32_t b, uint32_t c, uint32_t d)
64 {
65 return c ^ (b | ~d);
66 }
67
68 inline uint32_t rotate(uint32_t a, uint32_t c)
69 {
70 return (a << c) | (a >> (32 - c));
71 }
72
73#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN)
74 inline uint32_t swap(uint32_t x)
75 {
76#if defined(__GNUC__) || defined(__clang__)
77 return __builtin_bswap32(x);
78#endif
79#ifdef MSC_VER
80 return _byteswap_ulong(x);
81#endif
82
83 return (x >> 24) |
84 ((x >> 8) & 0x0000FF00) |
85 ((x << 8) & 0x00FF0000) |
86 (x << 24);
87 }
88#endif
89}
90
91
93void MD5::processBlock(const void* data)
94{
95 // get last hash
96 uint32_t a = m_hash[0];
97 uint32_t b = m_hash[1];
98 uint32_t c = m_hash[2];
99 uint32_t d = m_hash[3];
100
101 // data represented as 16x 32-bit words
102 const uint32_t* words = (uint32_t*) data;
103
104 // computations are little endian, swap data if necessary
105#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN)
106#define LITTLEENDIAN(x) swap(x)
107#else
108#define LITTLEENDIAN(x) (x)
109#endif
110
111 // first round
112 uint32_t word0 = LITTLEENDIAN(words[ 0]);
113 a = rotate(a + f1(b,c,d) + word0 + 0xd76aa478, 7) + b;
114 uint32_t word1 = LITTLEENDIAN(words[ 1]);
115 d = rotate(d + f1(a,b,c) + word1 + 0xe8c7b756, 12) + a;
116 uint32_t word2 = LITTLEENDIAN(words[ 2]);
117 c = rotate(c + f1(d,a,b) + word2 + 0x242070db, 17) + d;
118 uint32_t word3 = LITTLEENDIAN(words[ 3]);
119 b = rotate(b + f1(c,d,a) + word3 + 0xc1bdceee, 22) + c;
120
121 uint32_t word4 = LITTLEENDIAN(words[ 4]);
122 a = rotate(a + f1(b,c,d) + word4 + 0xf57c0faf, 7) + b;
123 uint32_t word5 = LITTLEENDIAN(words[ 5]);
124 d = rotate(d + f1(a,b,c) + word5 + 0x4787c62a, 12) + a;
125 uint32_t word6 = LITTLEENDIAN(words[ 6]);
126 c = rotate(c + f1(d,a,b) + word6 + 0xa8304613, 17) + d;
127 uint32_t word7 = LITTLEENDIAN(words[ 7]);
128 b = rotate(b + f1(c,d,a) + word7 + 0xfd469501, 22) + c;
129
130 uint32_t word8 = LITTLEENDIAN(words[ 8]);
131 a = rotate(a + f1(b,c,d) + word8 + 0x698098d8, 7) + b;
132 uint32_t word9 = LITTLEENDIAN(words[ 9]);
133 d = rotate(d + f1(a,b,c) + word9 + 0x8b44f7af, 12) + a;
134 uint32_t word10 = LITTLEENDIAN(words[10]);
135 c = rotate(c + f1(d,a,b) + word10 + 0xffff5bb1, 17) + d;
136 uint32_t word11 = LITTLEENDIAN(words[11]);
137 b = rotate(b + f1(c,d,a) + word11 + 0x895cd7be, 22) + c;
138
139 uint32_t word12 = LITTLEENDIAN(words[12]);
140 a = rotate(a + f1(b,c,d) + word12 + 0x6b901122, 7) + b;
141 uint32_t word13 = LITTLEENDIAN(words[13]);
142 d = rotate(d + f1(a,b,c) + word13 + 0xfd987193, 12) + a;
143 uint32_t word14 = LITTLEENDIAN(words[14]);
144 c = rotate(c + f1(d,a,b) + word14 + 0xa679438e, 17) + d;
145 uint32_t word15 = LITTLEENDIAN(words[15]);
146 b = rotate(b + f1(c,d,a) + word15 + 0x49b40821, 22) + c;
147
148 // second round
149 a = rotate(a + f2(b,c,d) + word1 + 0xf61e2562, 5) + b;
150 d = rotate(d + f2(a,b,c) + word6 + 0xc040b340, 9) + a;
151 c = rotate(c + f2(d,a,b) + word11 + 0x265e5a51, 14) + d;
152 b = rotate(b + f2(c,d,a) + word0 + 0xe9b6c7aa, 20) + c;
153
154 a = rotate(a + f2(b,c,d) + word5 + 0xd62f105d, 5) + b;
155 d = rotate(d + f2(a,b,c) + word10 + 0x02441453, 9) + a;
156 c = rotate(c + f2(d,a,b) + word15 + 0xd8a1e681, 14) + d;
157 b = rotate(b + f2(c,d,a) + word4 + 0xe7d3fbc8, 20) + c;
158
159 a = rotate(a + f2(b,c,d) + word9 + 0x21e1cde6, 5) + b;
160 d = rotate(d + f2(a,b,c) + word14 + 0xc33707d6, 9) + a;
161 c = rotate(c + f2(d,a,b) + word3 + 0xf4d50d87, 14) + d;
162 b = rotate(b + f2(c,d,a) + word8 + 0x455a14ed, 20) + c;
163
164 a = rotate(a + f2(b,c,d) + word13 + 0xa9e3e905, 5) + b;
165 d = rotate(d + f2(a,b,c) + word2 + 0xfcefa3f8, 9) + a;
166 c = rotate(c + f2(d,a,b) + word7 + 0x676f02d9, 14) + d;
167 b = rotate(b + f2(c,d,a) + word12 + 0x8d2a4c8a, 20) + c;
168
169 // third round
170 a = rotate(a + f3(b,c,d) + word5 + 0xfffa3942, 4) + b;
171 d = rotate(d + f3(a,b,c) + word8 + 0x8771f681, 11) + a;
172 c = rotate(c + f3(d,a,b) + word11 + 0x6d9d6122, 16) + d;
173 b = rotate(b + f3(c,d,a) + word14 + 0xfde5380c, 23) + c;
174
175 a = rotate(a + f3(b,c,d) + word1 + 0xa4beea44, 4) + b;
176 d = rotate(d + f3(a,b,c) + word4 + 0x4bdecfa9, 11) + a;
177 c = rotate(c + f3(d,a,b) + word7 + 0xf6bb4b60, 16) + d;
178 b = rotate(b + f3(c,d,a) + word10 + 0xbebfbc70, 23) + c;
179
180 a = rotate(a + f3(b,c,d) + word13 + 0x289b7ec6, 4) + b;
181 d = rotate(d + f3(a,b,c) + word0 + 0xeaa127fa, 11) + a;
182 c = rotate(c + f3(d,a,b) + word3 + 0xd4ef3085, 16) + d;
183 b = rotate(b + f3(c,d,a) + word6 + 0x04881d05, 23) + c;
184
185 a = rotate(a + f3(b,c,d) + word9 + 0xd9d4d039, 4) + b;
186 d = rotate(d + f3(a,b,c) + word12 + 0xe6db99e5, 11) + a;
187 c = rotate(c + f3(d,a,b) + word15 + 0x1fa27cf8, 16) + d;
188 b = rotate(b + f3(c,d,a) + word2 + 0xc4ac5665, 23) + c;
189
190 // fourth round
191 a = rotate(a + f4(b,c,d) + word0 + 0xf4292244, 6) + b;
192 d = rotate(d + f4(a,b,c) + word7 + 0x432aff97, 10) + a;
193 c = rotate(c + f4(d,a,b) + word14 + 0xab9423a7, 15) + d;
194 b = rotate(b + f4(c,d,a) + word5 + 0xfc93a039, 21) + c;
195
196 a = rotate(a + f4(b,c,d) + word12 + 0x655b59c3, 6) + b;
197 d = rotate(d + f4(a,b,c) + word3 + 0x8f0ccc92, 10) + a;
198 c = rotate(c + f4(d,a,b) + word10 + 0xffeff47d, 15) + d;
199 b = rotate(b + f4(c,d,a) + word1 + 0x85845dd1, 21) + c;
200
201 a = rotate(a + f4(b,c,d) + word8 + 0x6fa87e4f, 6) + b;
202 d = rotate(d + f4(a,b,c) + word15 + 0xfe2ce6e0, 10) + a;
203 c = rotate(c + f4(d,a,b) + word6 + 0xa3014314, 15) + d;
204 b = rotate(b + f4(c,d,a) + word13 + 0x4e0811a1, 21) + c;
205
206 a = rotate(a + f4(b,c,d) + word4 + 0xf7537e82, 6) + b;
207 d = rotate(d + f4(a,b,c) + word11 + 0xbd3af235, 10) + a;
208 c = rotate(c + f4(d,a,b) + word2 + 0x2ad7d2bb, 15) + d;
209 b = rotate(b + f4(c,d,a) + word9 + 0xeb86d391, 21) + c;
210
211 // update hash
212 m_hash[0] += a;
213 m_hash[1] += b;
214 m_hash[2] += c;
215 m_hash[3] += d;
216}
217
218
220void MD5::add(const void* data, size_t numBytes)
221{
222 const uint8_t* current = (const uint8_t*) data;
223
224 if (m_bufferSize > 0)
225 {
226 while (numBytes > 0 && m_bufferSize < BlockSize)
227 {
228 m_buffer[m_bufferSize++] = *current++;
229 numBytes--;
230 }
231 }
232
233 // full buffer
234 if (m_bufferSize == BlockSize)
235 {
236 processBlock(m_buffer);
237 m_numBytes += BlockSize;
238 m_bufferSize = 0;
239 }
240
241 // no more data ?
242 if (numBytes == 0)
243 return;
244
245 // process full blocks
246 while (numBytes >= BlockSize)
247 {
248 processBlock(current);
249 current += BlockSize;
250 m_numBytes += BlockSize;
251 numBytes -= BlockSize;
252 }
253
254 // keep remaining bytes in buffer
255 while (numBytes > 0)
256 {
257 m_buffer[m_bufferSize++] = *current++;
258 numBytes--;
259 }
260}
261
262
264void MD5::processBuffer()
265{
266 // the input bytes are considered as bits strings, where the first bit is the most significant bit of the byte
267
268 // - append "1" bit to message
269 // - append "0" bits until message length in bit mod 512 is 448
270 // - append length as 64 bit integer
271
272 // number of bits
273 size_t paddedLength = m_bufferSize * 8;
274
275 // plus one bit set to 1 (always appended)
276 paddedLength++;
277
278 // number of bits must be (numBits % 512) = 448
279 size_t lower11Bits = paddedLength & 511;
280 if (lower11Bits <= 448)
281 paddedLength += 448 - lower11Bits;
282 else
283 paddedLength += 512 + 448 - lower11Bits;
284 // convert from bits to bytes
285 paddedLength /= 8;
286
287 // only needed if additional data flows over into a second block
288 unsigned char extra[BlockSize];
289
290 // append a "1" bit, 128 => binary 10000000
291 if (m_bufferSize < BlockSize)
292 m_buffer[m_bufferSize] = 128;
293 else
294 extra[0] = 128;
295
296 size_t i;
297 for (i = m_bufferSize + 1; i < BlockSize; i++)
298 m_buffer[i] = 0;
299 for (; i < paddedLength; i++)
300 extra[i - BlockSize] = 0;
301
302 // add message length in bits as 64 bit number
303 uint64_t msgBits = 8 * (m_numBytes + m_bufferSize);
304 // find right position
305 unsigned char* addLength;
306 if (paddedLength < BlockSize)
307 addLength = m_buffer + paddedLength;
308 else
309 addLength = extra + paddedLength - BlockSize;
310
311 // must be little endian
312 *addLength++ = msgBits & 0xFF; msgBits >>= 8;
313 *addLength++ = msgBits & 0xFF; msgBits >>= 8;
314 *addLength++ = msgBits & 0xFF; msgBits >>= 8;
315 *addLength++ = msgBits & 0xFF; msgBits >>= 8;
316 *addLength++ = msgBits & 0xFF; msgBits >>= 8;
317 *addLength++ = msgBits & 0xFF; msgBits >>= 8;
318 *addLength++ = msgBits & 0xFF; msgBits >>= 8;
319 *addLength++ = msgBits & 0xFF;
320
321 // process blocks
322 processBlock(m_buffer);
323 // flowed over into a second block ?
324 if (paddedLength > BlockSize)
325 processBlock(extra);
326}
327
328
330std::string MD5::getHash()
331{
332 // compute hash (as raw bytes)
333 unsigned char rawHash[HashBytes];
334 getHash(rawHash);
335
336 // convert to hex string
337 std::string result;
338 result.reserve(2 * HashBytes);
339 for (int i = 0; i < HashBytes; i++)
340 {
341 static const char dec2hex[16+1] = "0123456789abcdef";
342 result += dec2hex[(rawHash[i] >> 4) & 15];
343 result += dec2hex[ rawHash[i] & 15];
344 }
345
346 return result;
347}
348
349
351void MD5::getHash(unsigned char buffer[MD5::HashBytes])
352{
353 // save old hash if buffer is partially filled
354 uint32_t oldHash[HashValues];
355 for (int i = 0; i < HashValues; i++)
356 oldHash[i] = m_hash[i];
357
358 // process remaining bytes
359 processBuffer();
360
361 unsigned char* current = buffer;
362 for (int i = 0; i < HashValues; i++)
363 {
364 *current++ = m_hash[i] & 0xFF;
365 *current++ = (m_hash[i] >> 8) & 0xFF;
366 *current++ = (m_hash[i] >> 16) & 0xFF;
367 *current++ = (m_hash[i] >> 24) & 0xFF;
368
369 // restore old hash
370 m_hash[i] = oldHash[i];
371 }
372}
373
374
376std::string MD5::operator()(const void* data, size_t numBytes)
377{
378 reset();
379 add(data, numBytes);
380 return getHash();
381}
382
383
385std::string MD5::operator()(const std::string& text)
386{
387 reset();
388 add(text.c_str(), text.size());
389 return getHash();
390}
391
392} // namespace hash
std::string operator()(const void *data, size_t numBytes)
compute MD5 of a memory block
@ BlockSize
Definition md5.h:48
@ HashBytes
Definition md5.h:48
MD5()
same as reset()
void add(const void *data, size_t numBytes)
add arbitrary number of bytes
void reset()
restart
std::string getHash()
return latest hash as 32 hex characters
#define LITTLEENDIAN(x)
Third-party (vendored): MD5 hash from Stephan Brumme's portable hashing library (create....
Usage: std::string msg = "The quick brown fox jumps over the lazy dog"; std::string key = "key"; std:...
Definition crc32.h:28