Coverage Report

Created: 2023-01-17 06:15

/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
}