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