libxcks  0.1.0.1
md5.cpp
Go to the documentation of this file.
1 /*
2  * libxcks
3  * Copyright (C) 2022 Julien Couot
4  *
5  * This program is free software: you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or (at your
8  * option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
13  * License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with this program. If not, see <https://www.gnu.org/licenses/>.
17  */
18 
24 //---------------------------------------------------------------------------
25 #include <cstring>
26 
27 #include "md5.hpp"
28 //---------------------------------------------------------------------------
29 
31 using namespace std;
32 //---------------------------------------------------------------------------
33 
34 
35 namespace libxcks
36 {
37 // For doxygen
51 //---------------------------------------------------------------------------
52 
53 
54 /*
55  * Default constructor.
56  */
57 MD5::MD5()
58 {
59  reset();
60 }
61 //---------------------------------------------------------------------------
62 
63 
64 /*
65  * Resets the MD5 hash to initial value.
66  */
67 void MD5::reset()
68 {
69  A_ = 0x67452301;
70  B_ = 0xefcdab89;
71  C_ = 0x98badcfe;
72  D_ = 0x10325476;
73 
74  nblocks = 0;
75  count = 0;
76 }
77 //---------------------------------------------------------------------------
78 
79 
80 /*
81  * Process the remaining bytes in the internal buffer and the usual
82  * prolog according to the standard.
83  */
84 void MD5::finish()
85 {
86  uint32_t t, msb, lsb;
87  uint8_t *p;
88 
89  update(nullptr, 0); // flush
90 
91  t = nblocks;
92  // multiply by 64 to make a byte count
93  lsb = t << 6;
94  msb = t >> 26;
95  // add the count
96  t = lsb;
97  if ((lsb += count) < t)
98  msb++;
99  // multiply by 8 to make a bit count
100  t = lsb;
101  lsb <<= 3;
102  msb <<= 3;
103  msb |= t >> 29;
104 
105  if (count < 56) // enough room
106  {
107  ibuffer[count++] = 0x80; // pad
108  while (count < 56)
109  ibuffer[count++] = 0; // pad
110  }
111  else // need one extra block
112  {
113  ibuffer[count++] = 0x80; // pad character
114  while (count < 64)
115  ibuffer[count++] = 0;
116  update(nullptr, 0); // flush
117  memset(ibuffer, 0, 56); // fill next block with zeroes
118  }
119  /* append the 64 bit count */
120  ibuffer[56] = lsb;
121  ibuffer[57] = lsb >> 8;
122  ibuffer[58] = lsb >> 16;
123  ibuffer[59] = lsb >> 24;
124  ibuffer[60] = msb;
125  ibuffer[61] = msb >> 8;
126  ibuffer[62] = msb >> 16;
127  ibuffer[63] = msb >> 24;
128  transform(ibuffer);
129  //_gcry_burn_stack (80+6*sizeof(void*));
130 
131  p = ibuffer;
132  #if (LIBXCKS_BYTE_ORDER == LIBXCKS_LITTLE_ENDIAN)
133  #define X(a) do { *(uint32_t*)p = a ; p += 4; } while(0)
134  #else /* big endian */
135  #define X(a) do { *p++ = a; *p++ = a >> 8; \
136  *p++ = a >> 16; *p++ = a >> 24; } while(0)
137  #endif
138  X(A_);
139  X(B_);
140  X(C_);
141  X(D_);
142  #undef X
143 }
144 //---------------------------------------------------------------------------
145 
146 
147 /*
148  * Updates the MD5 hash with specified array of bytes.
149  */
150 void MD5::update(const uint8_t* buf, size_t len)
151 {
152  if (count == 64) // flush the buffer
153  {
154  transform(ibuffer);
155  // _gcry_burn_stack (80+6*sizeof(void*));
156  count = 0;
157  nblocks++;
158  }
159  if (buf == nullptr)
160  return;
161 
162  if (count != 0)
163  {
164  for (; len && count < 64; len--)
165  ibuffer[count++] = *buf++;
166  update(nullptr, 0);
167  if (len == 0)
168  return;
169  }
170 
171  while (len >= 64)
172  {
173  uint8_t tmpBuf[sizeof(uint32_t) * 16];
174  memcpy(tmpBuf, buf, sizeof(uint32_t) * 16);
175  transform(tmpBuf);
176  count = 0;
177  nblocks++;
178  len -= 64;
179  buf += 64;
180  }
181  //_gcry_burn_stack (80+6*sizeof(void*));
182  for(; len && count < 64; len--)
183  ibuffer[count++] = *buf++;
184 }
185 //---------------------------------------------------------------------------
186 
187 
188 // These are the four functions used in the four steps of the MD5 algorithm
189 // and defined in the RFC 1321. The first function is a little bit optimized
190 // (as found in Colin Plumbs public domain implementation).
191 // #define FF(b, c, d) ((b & c) | (~b & d))
192 #define FF(b, c, d) (d ^ (b & (c ^ d)))
193 #define FG(b, c, d) FF (d, b, c)
194 #define FH(b, c, d) (b ^ c ^ d)
195 #define FI(b, c, d) (c ^ (b | ~d))
196 
197 /*
198  * Process [len] bytes of [buf], accumulating context in [this].
199  * It is assumed that len % 64 == 0.
200  */
201 void MD5::transform(uint8_t* data)
202 {
203  uint32_t correct_words[16];
204  uint32_t A = A_;
205  uint32_t B = B_;
206  uint32_t C = C_;
207  uint32_t D = D_;
208  uint32_t* cwp = correct_words;
209 
210  #if (LIBXCKS_BYTE_ORDER == LIBXCKS_BIG_ENDIAN)
211  {
212  int i;
213  uint8_t *p2, *p1;
214  for (i = 0, p1 = data, p2 = (uint8_t*)correct_words; i < 16; i++, p2 += 4)
215  {
216  p2[3] = *p1++;
217  p2[2] = *p1++;
218  p2[1] = *p1++;
219  p2[0] = *p1++;
220  }
221  }
222  #else
223  memcpy(correct_words, data, 64);
224  #endif
225 
226 
227  // First round: using the given function, the context and a constant the
228  // next context is computed. Because the algorithms processing unit is a
229  // 32-bit word and it is determined to work on words in little endian byte
230  // order we perhaps have to change the byte order before the computation.
231  // To reduce the work for the next steps we store the swapped words in the
232  // array CORRECT_WORDS.
233  #define OP(a, b, c, d, s, T) \
234  do \
235  { \
236  a += FF(b, c, d) + (*cwp++) + T; \
237  a = rol(a, s); \
238  a += b; \
239  } \
240  while (0)
241 
242  // Before we start, one word to the strange constants.
243  // They are defined in RFC 1321 as
244  //
245  // T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64, or
246  // perl -e 'foreach(1..64){printf "0x%08x\n", int (4294967296 * abs (sin $_))}'
247 
248  // Round 1.
249  OP(A, B, C, D, 7, 0xd76aa478);
250  OP(D, A, B, C, 12, 0xe8c7b756);
251  OP(C, D, A, B, 17, 0x242070db);
252  OP(B, C, D, A, 22, 0xc1bdceee);
253  OP(A, B, C, D, 7, 0xf57c0faf);
254  OP(D, A, B, C, 12, 0x4787c62a);
255  OP(C, D, A, B, 17, 0xa8304613);
256  OP(B, C, D, A, 22, 0xfd469501);
257  OP(A, B, C, D, 7, 0x698098d8);
258  OP(D, A, B, C, 12, 0x8b44f7af);
259  OP(C, D, A, B, 17, 0xffff5bb1);
260  OP(B, C, D, A, 22, 0x895cd7be);
261  OP(A, B, C, D, 7, 0x6b901122);
262  OP(D, A, B, C, 12, 0xfd987193);
263  OP(C, D, A, B, 17, 0xa679438e);
264  OP(B, C, D, A, 22, 0x49b40821);
265 
266  // For the second to fourth round we have the possibly swapped words
267  // in CORRECT_WORDS. Redefine the macro to take an additional first
268  // argument specifying the function to use.
269  #undef OP
271  #define OP(f, a, b, c, d, k, s, T) \
272  do \
273  { \
274  a += f (b, c, d) + correct_words[k] + T; \
275  a = rol (a, s); \
276  a += b; \
277  } \
278  while (0)
279 
280  // Round 2.
281  OP(FG, A, B, C, D, 1, 5, 0xf61e2562);
282  OP(FG, D, A, B, C, 6, 9, 0xc040b340);
283  OP(FG, C, D, A, B, 11, 14, 0x265e5a51);
284  OP(FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
285  OP(FG, A, B, C, D, 5, 5, 0xd62f105d);
286  OP(FG, D, A, B, C, 10, 9, 0x02441453);
287  OP(FG, C, D, A, B, 15, 14, 0xd8a1e681);
288  OP(FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
289  OP(FG, A, B, C, D, 9, 5, 0x21e1cde6);
290  OP(FG, D, A, B, C, 14, 9, 0xc33707d6);
291  OP(FG, C, D, A, B, 3, 14, 0xf4d50d87);
292  OP(FG, B, C, D, A, 8, 20, 0x455a14ed);
293  OP(FG, A, B, C, D, 13, 5, 0xa9e3e905);
294  OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8);
295  OP(FG, C, D, A, B, 7, 14, 0x676f02d9);
296  OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
297 
298  // Round 3.
299  OP(FH, A, B, C, D, 5, 4, 0xfffa3942);
300  OP(FH, D, A, B, C, 8, 11, 0x8771f681);
301  OP(FH, C, D, A, B, 11, 16, 0x6d9d6122);
302  OP(FH, B, C, D, A, 14, 23, 0xfde5380c);
303  OP(FH, A, B, C, D, 1, 4, 0xa4beea44);
304  OP(FH, D, A, B, C, 4, 11, 0x4bdecfa9);
305  OP(FH, C, D, A, B, 7, 16, 0xf6bb4b60);
306  OP(FH, B, C, D, A, 10, 23, 0xbebfbc70);
307  OP(FH, A, B, C, D, 13, 4, 0x289b7ec6);
308  OP(FH, D, A, B, C, 0, 11, 0xeaa127fa);
309  OP(FH, C, D, A, B, 3, 16, 0xd4ef3085);
310  OP(FH, B, C, D, A, 6, 23, 0x04881d05);
311  OP(FH, A, B, C, D, 9, 4, 0xd9d4d039);
312  OP(FH, D, A, B, C, 12, 11, 0xe6db99e5);
313  OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8);
314  OP(FH, B, C, D, A, 2, 23, 0xc4ac5665);
315 
316  // Round 4.
317  OP(FI, A, B, C, D, 0, 6, 0xf4292244);
318  OP(FI, D, A, B, C, 7, 10, 0x432aff97);
319  OP(FI, C, D, A, B, 14, 15, 0xab9423a7);
320  OP(FI, B, C, D, A, 5, 21, 0xfc93a039);
321  OP(FI, A, B, C, D, 12, 6, 0x655b59c3);
322  OP(FI, D, A, B, C, 3, 10, 0x8f0ccc92);
323  OP(FI, C, D, A, B, 10, 15, 0xffeff47d);
324  OP(FI, B, C, D, A, 1, 21, 0x85845dd1);
325  OP(FI, A, B, C, D, 8, 6, 0x6fa87e4f);
326  OP(FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
327  OP(FI, C, D, A, B, 6, 15, 0xa3014314);
328  OP(FI, B, C, D, A, 13, 21, 0x4e0811a1);
329  OP(FI, A, B, C, D, 4, 6, 0xf7537e82);
330  OP(FI, D, A, B, C, 11, 10, 0xbd3af235);
331  OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
332  OP(FI, B, C, D, A, 9, 21, 0xeb86d391);
333 
334 
335  // Put hash in the local context.
336  A_ += A;
337  B_ += B;
338  C_ += C;
339  D_ += D;
340 }
341 //---------------------------------------------------------------------------
342 
343 
344 /*
345  * Returns the MD5 hash value in the first 16 bytes of the given address.
346  */
347 uint8_t* MD5::getValue(uint8_t* buffer) const
348 {
349  MD5 md5(*this);
350  md5.finish();
351 
352  (reinterpret_cast<uint32_t*>(buffer))[0] = swapOnBE(md5.A_);
353  (reinterpret_cast<uint32_t*>(buffer))[1] = swapOnBE(md5.B_);
354  (reinterpret_cast<uint32_t*>(buffer))[2] = swapOnBE(md5.C_);
355  (reinterpret_cast<uint32_t*>(buffer))[3] = swapOnBE(md5.D_);
356 
357  return buffer;
358 }
359 //---------------------------------------------------------------------------
360 } // namespace libxcks
361 //---------------------------------------------------------------------------
Computes the MD5 hash from a byte stream.
Definition: md5.hpp:56
uint32_t B_
Second part of the state of computation.
Definition: md5.hpp:60
uint32_t C_
Third part of the state of computation.
Definition: md5.hpp:61
uint32_t A_
First part of the state of computation.
Definition: md5.hpp:59
void finish()
Process the remaining bytes in the internal buffer and the usual prolog according to the standard.
Definition: md5.cpp:84
uint32_t D_
Fourth part of the state of computation.
Definition: md5.hpp:62
#define FH(b, c, d)
Third fonction of the MD5 algorithm.
Definition: md5.cpp:194
#define FG(b, c, d)
Second fonction of the MD5 algorithm.
Definition: md5.cpp:193
#define OP(a, b, c, d, s, T)
First round.
#define FI(b, c, d)
Fourth fonction of the MD5 algorithm.
Definition: md5.cpp:195
#define X(a)
Helper function for MD5's computing.
Compute md5 hash.