libxcks  0.1.0.1
md4.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 "md4.hpp"
28 //---------------------------------------------------------------------------
29 
31 using namespace std;
32 //---------------------------------------------------------------------------
33 
34 
35 namespace libxcks
36 {
37 // For doxygen
58 //---------------------------------------------------------------------------
59 
60 
61 /*
62  * Default constructor.
63  */
64 MD4::MD4()
65 {
66  reset();
67 }
68 //---------------------------------------------------------------------------
69 
70 
71 /*
72  * Resets the MD4 hash to initial value.
73  */
74 void MD4::reset()
75 {
76  A = 0x67452301;
77  B = 0xefcdab89;
78  C = 0x98badcfe;
79  D = 0x10325476;
80  nblocks = 0;
81  count = 0;
82 }
83 //---------------------------------------------------------------------------
84 
85 
86 /*
87  * Process the remaining bytes in the internal buffer and the usual
88  * prolog according to the standard.
89  */
90 void MD4::finish()
91 {
92  uint32_t t, msb, lsb;
93  uint8_t *p;
94 
95  update(nullptr, 0); // flush
96 
97  t = nblocks;
98  // multiply by 64 to make a byte count
99  lsb = t << 6;
100  msb = t >> 26;
101  // add the count
102  t = lsb;
103  if ((lsb += count) < t)
104  msb++;
105  // multiply by 8 to make a bit count
106  t = lsb;
107  lsb <<= 3;
108  msb <<= 3;
109  msb |= t >> 29;
110 
111  if (count < 56) // enough room
112  {
113  ibuffer[count++] = 0x80; // pad
114  while (count < 56)
115  ibuffer[count++] = 0; // pad
116  }
117  else // need one extra block
118  {
119  ibuffer[count++] = 0x80; // pad character
120  while (count < 64)
121  ibuffer[count++] = 0;
122  update(nullptr, 0); // flush
123  memset(ibuffer, 0, 56 ); // fill next block with zeroes
124  }
125  // append the 64 bit count
126  ibuffer[56] = lsb ;
127  ibuffer[57] = lsb >> 8;
128  ibuffer[58] = lsb >> 16;
129  ibuffer[59] = lsb >> 24;
130  ibuffer[60] = msb ;
131  ibuffer[61] = msb >> 8;
132  ibuffer[62] = msb >> 16;
133  ibuffer[63] = msb >> 24;
134  transform(ibuffer);
135  //_gcry_burn_stack (80+6*sizeof(void*));
136 
137  p = ibuffer;
138  #if (LIBXCKS_BYTE_ORDER == LIBXCKS_BIG_ENDIAN)
139  #define X(a) do { *p++ = a ; *p++ = a >> 8; \
140  *p++ = a >> 16; *p++ = a >> 24; } while(0)
141  #else // little endian
142  #define X(a) do { *(uint32_t*)p = a ; p += 4; } while(0)
143  #endif
144  X(A);
145  X(B);
146  X(C);
147  X(D);
148  #undef X
149 }
150 //---------------------------------------------------------------------------
151 
152 
153 /*
154  * Updates the MD4 hash with specified array of bytes.
155  */
156 void MD4::update(const uint8_t* buf, size_t len)
157 {
158  if (count == 64) // flush the buffer
159  {
160  transform(ibuffer);
161  // _gcry_burn_stack (80+6*sizeof(void*));
162  count = 0;
163  nblocks++;
164  }
165  if (buf == nullptr)
166  return;
167 
168  if (count != 0)
169  {
170  for (; len && count < 64; len--)
171  ibuffer[count++] = *buf++;
172  update(nullptr, 0);
173  if (len == 0)
174  return;
175  }
176  // _gcry_burn_stack (80+6*sizeof(void*));
177 
178  while (len >= 64)
179  {
180  uint8_t tmpBuf[sizeof(uint32_t) * 16];
181  memcpy(tmpBuf, buf, sizeof(uint32_t) * 16);
182  transform(tmpBuf);
183  count = 0;
184  nblocks++;
185  len -= 64;
186  buf += 64;
187  }
188  for(; len && count < 64; len--)
189  ibuffer[count++] = *buf++;
190 }
191 //---------------------------------------------------------------------------
192 
193 
194 /*
195  * Transform the message X which consists of 16 32-bit-words.
196  */
197 void MD4::transform(uint8_t* data)
198 {
199  // Helper functions
200  #define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
201  #define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
202  #define H(x, y, z) ((x) ^ (y) ^ (z))
203 
204  uint32_t in[16];
205  uint32_t A = this->A;
206  uint32_t B = this->B;
207  uint32_t C = this->C;
208  uint32_t D = this->D;
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*)in; 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(in, data, 64);
224  #endif
225 
226  // Round 1.
227  #define function(a,b,c,d,k,s) a=rol(a+F(b,c,d)+in[k],s);
228  function(A,B,C,D, 0, 3);
229  function(D,A,B,C, 1, 7);
230  function(C,D,A,B, 2,11);
231  function(B,C,D,A, 3,19);
232  function(A,B,C,D, 4, 3);
233  function(D,A,B,C, 5, 7);
234  function(C,D,A,B, 6,11);
235  function(B,C,D,A, 7,19);
236  function(A,B,C,D, 8, 3);
237  function(D,A,B,C, 9, 7);
238  function(C,D,A,B,10,11);
239  function(B,C,D,A,11,19);
240  function(A,B,C,D,12, 3);
241  function(D,A,B,C,13, 7);
242  function(C,D,A,B,14,11);
243  function(B,C,D,A,15,19);
244 
245  #undef function
246 
247  // Round 2.
248  #define function(a,b,c,d,k,s) a=rol(a+G(b,c,d)+in[k]+0x5a827999,s);
249 
250  function(A,B,C,D, 0, 3);
251  function(D,A,B,C, 4, 5);
252  function(C,D,A,B, 8, 9);
253  function(B,C,D,A,12,13);
254  function(A,B,C,D, 1, 3);
255  function(D,A,B,C, 5, 5);
256  function(C,D,A,B, 9, 9);
257  function(B,C,D,A,13,13);
258  function(A,B,C,D, 2, 3);
259  function(D,A,B,C, 6, 5);
260  function(C,D,A,B,10, 9);
261  function(B,C,D,A,14,13);
262  function(A,B,C,D, 3, 3);
263  function(D,A,B,C, 7, 5);
264  function(C,D,A,B,11, 9);
265  function(B,C,D,A,15,13);
266 
267  #undef function
268 
269  // Round 3.
270  #define function(a,b,c,d,k,s) a=rol(a+H(b,c,d)+in[k]+0x6ed9eba1,s);
271 
272  function(A,B,C,D, 0, 3);
273  function(D,A,B,C, 8, 9);
274  function(C,D,A,B, 4,11);
275  function(B,C,D,A,12,15);
276  function(A,B,C,D, 2, 3);
277  function(D,A,B,C,10, 9);
278  function(C,D,A,B, 6,11);
279  function(B,C,D,A,14,15);
280  function(A,B,C,D, 1, 3);
281  function(D,A,B,C, 9, 9);
282  function(C,D,A,B, 5,11);
283  function(B,C,D,A,13,15);
284  function(A,B,C,D, 3, 3);
285  function(D,A,B,C,11, 9);
286  function(C,D,A,B, 7,11);
287  function(B,C,D,A,15,15);
288 
289 
290  // Put checksum in context given as argument.
291  this->A += A;
292  this->B += B;
293  this->C += C;
294  this->D += D;
295 }
296 //---------------------------------------------------------------------------
297 
298 
299 /*
300  * Returns the MD4 hash value in the first 16 bytes of the given address.
301  */
302 uint8_t* MD4::getValue(uint8_t* buffer) const
303 {
304  MD4 md4(*this);
305  md4.finish();
306 
307  memcpy(buffer, md4.ibuffer, getSize());
308 
309  return buffer;
310 }
311 //---------------------------------------------------------------------------
312 } // namespace libxcks
313 //---------------------------------------------------------------------------
Computes the MD4 hash from a byte stream.
Definition: md4.hpp:57
void finish()
Process the remaining bytes in the internal buffer and the usual prolog according to the standard.
Definition: md4.cpp:90
uint8_t ibuffer[64]
Input buffer.
Definition: md4.hpp:67
#define X(a)
Helper function for MD4's computing.
Compute md4 hash.