File: md4.c

package info (click to toggle)
bglibs 2.04%2Bdfsg-8
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 3,468 kB
  • sloc: ansic: 15,821; perl: 674; sh: 63; makefile: 29
file content (334 lines) | stat: -rw-r--r-- 9,780 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
/* md4.c - Functions to compute MD4 message digest
   according to the definition of MD4 in RFC 1320 from April 1992.
   Copyright (C) 2000,2003,2005 Bruce Guenter

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.
  
   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.
  
   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, write to the Free Software
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
*/

/* Based on the GNU C Library MD5 source code,
   Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.  */

#include <sys/types.h>
#include <string.h>

#include "sysdeps.h"
#include "md4.h"
#include "uint32.h"

#ifdef ENDIAN_MSB
# define SWAP(n)							\
    (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
#else
# define SWAP(n) (n)
#endif


/* This array contains the bytes used to pad the buffer to the next
   64-byte boundary.  (RFC 1320, 3.1: Step 1)  */
static const unsigned char fillbuf[64] = { 0x80, 0 /* , 0, 0, ...  */ };


/* Initialize structure containing state of computation.
   (RFC 1320, 3.3: Step 3)  */
void
md4_init_ctx (ctx)
     struct md4_ctx *ctx;
{
  ctx->A = 0x67452301;
  ctx->B = 0xefcdab89;
  ctx->C = 0x98badcfe;
  ctx->D = 0x10325476;

  ctx->total[0] = ctx->total[1] = 0;
  ctx->buflen = 0;
}

/* Put result from CTX in first 16 bytes following RESBUF.  The result
   must be in little endian byte order.

   IMPORTANT: On some systems it is required that RESBUF is correctly
   aligned for a 32 bits value.  */
void *
md4_read_ctx (ctx, resbuf)
     const struct md4_ctx *ctx;
     void *resbuf;
{
  uint32_pack_lsb(ctx->A, resbuf);
  uint32_pack_lsb(ctx->B, resbuf + 4);
  uint32_pack_lsb(ctx->C, resbuf + 8);
  uint32_pack_lsb(ctx->D, resbuf + 12);

  return resbuf;
}

/* Process the remaining bytes in the internal buffer and the usual
   prolog according to the standard and write the result to RESBUF.

   IMPORTANT: On some systems it is required that RESBUF is correctly
   aligned for a 32 bits value.  */
void *
md4_finish_ctx (ctx, resbuf)
     struct md4_ctx *ctx;
     void *resbuf;
{
  /* Take yet unprocessed bytes into account.  */
  md4_uint32 bytes = ctx->buflen;
  md4_uint32 total0;
  md4_uint32 total1;
  
  /* Now count remaining bytes.  */
  ctx->total[0] += bytes;
  if (ctx->total[0] < bytes)
    ++ctx->total[1];
  total0 = ctx->total[0];
  total1 = ctx->total[1];
  
  if (bytes >= 56) {
    memcpy(ctx->buffer+bytes, fillbuf, 64-bytes);
    md4_process_block(ctx->buffer, ctx);
    memcpy(ctx->buffer, fillbuf+8, 56);
  }
  else
    memcpy(ctx->buffer+bytes, fillbuf, 56-bytes);

  /* Put the 64-bit file length in *bits* at the end of the buffer.  */
  uint32_pack_lsb(total0 << 3,                    (unsigned char*)&ctx->buffer[56]);
  uint32_pack_lsb((total1 << 3) | (total0 >> 29), (unsigned char*)&ctx->buffer[60]);

  /* Process last bytes.  */
  md4_process_block (ctx->buffer, ctx);

  return md4_read_ctx (ctx, resbuf);
}


void
md4_process_bytes (buffer, len, ctx)
     const void *buffer;
     size_t len;
     struct md4_ctx *ctx;
{
  /* When we already have some bits in our internal buffer concatenate
     both inputs first.  */
  if (ctx->buflen != 0)
    {
      size_t left_over = ctx->buflen;
      size_t add = 64 - left_over;
      if (add > len)
	add = len;

      memcpy (&ctx->buffer[left_over], buffer, add);

      if (left_over + add == 64)
	md4_process_block (ctx->buffer, ctx);

      ctx->buflen += add;
      buffer = (const char *) buffer + add;
      len -= add;
    }

  /* Process available complete blocks.  */
  while (len > 64)
    {
      md4_process_block (buffer, ctx);
      buffer = (const char *) buffer + 64;
      len -= 64;
    }

  /* Move remaining bytes in internal buffer.  */
  if (len > 0)
    {
      memcpy (ctx->buffer, buffer, len);
      ctx->buflen = len;
    }
}


/* Compute MD4 message digest for LEN bytes beginning at BUFFER.  The
   result is always in little endian byte order, so that a byte-wise
   output yields to the wanted ASCII representation of the message
   digest.  */
void *
md4_buffer (buffer, len, resblock)
     const char *buffer;
     size_t len;
     void *resblock;
{
  struct md4_ctx ctx;

  /* Initialize the computation context.  */
  md4_init_ctx (&ctx);

  /* Process whole buffer but last len % 64 bytes.  */
  md4_process_bytes (buffer, len, &ctx);

  /* Put result in desired memory area.  */
  return md4_finish_ctx (&ctx, resblock);
}


/* These are the four functions used in the four steps of the MD4 algorithm
   and defined in the RFC 1320.  The first function is a little bit optimized
   (as found in Colin Plumbs public domain MD5 implementation).  */
/* #define FF(X,Y,Z) ((X & Y) | (~X & Z)) */
#define FF(X,Y,Z) (Z ^ (X & (Y ^ Z)))
#define FG(X,Y,Z) ((X & Y) | (X & Z) | (Y & Z))
#define FH(X,Y,Z) (X ^ Y ^ Z)

/* Process 64 bytes of BUFFER, accumulating context into CTX. */

void
md4_process_block (buffer, ctx)
     const void *buffer;
     struct md4_ctx *ctx;
{
  md4_uint32 correct_words[16];
  const md4_uint32 *words = buffer;
  md4_uint32 A = ctx->A;
  md4_uint32 B = ctx->B;
  md4_uint32 C = ctx->C;
  md4_uint32 D = ctx->D;
  md4_uint32 *cwp = correct_words;

  /* First increment the byte count.  RFC 1320 specifies the possible
     length of the file up to 2^64 bits.  Here we only compute the
     number of bytes.  Do a double word increment.  */
  ctx->total[0] += 64;
  if (ctx->total[0] < 64)
    ++ctx->total[1];

  /* First round: using the given function, the context and a constant
     the next context is computed.  Because the algorithms processing
     unit is a 32-bit word and it is determined to work on words in
     little endian byte order we perhaps have to change the byte order
     before the computation.  To reduce the work for the next steps
     we store the swapped words in the array CORRECT_WORDS.  */

#define OP(a, b, c, d, s)						\
      do								\
        {								\
	  a += FF (b, c, d) + (*cwp++ = SWAP (*words));			\
	  ++words;							\
	  CYCLIC (a, s);						\
        }								\
      while (0)

  /* It is unfortunate that C does not provide an operator for
     cyclic rotation.  Hope the C compiler is smart enough.  */
#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))

  /* Round 1.  */
  OP(A,B,C,D, 3); OP(D,A,B,C, 7); OP(C,D,A,B,11); OP(B,C,D,A,19);
  OP(A,B,C,D, 3); OP(D,A,B,C, 7); OP(C,D,A,B,11); OP(B,C,D,A,19);
  OP(A,B,C,D, 3); OP(D,A,B,C, 7); OP(C,D,A,B,11); OP(B,C,D,A,19);
  OP(A,B,C,D, 3); OP(D,A,B,C, 7); OP(C,D,A,B,11); OP(B,C,D,A,19);
      
  /* For the second to fourth round we have the possibly swapped words
     in CORRECT_WORDS.  Redefine the macro to take an additional first
     argument specifying the function to use.  */
#undef OP
#define OP(f, a, b, c, d, k, s, T)					\
      do 								\
	{								\
	  a += f (b, c, d) + correct_words[k] + T;			\
	  CYCLIC (a, s);						\
	}								\
      while (0)

  /* Round 2.  */
#define OP2(a,b,c,d,k,s) OP(FG,a,b,c,d,k,s,0x5A827999)
  OP2 (A, B, C, D,  0,  3);
  OP2 (D, A, B, C,  4,  5);
  OP2 (C, D, A, B,  8,  9);
  OP2 (B, C, D, A, 12, 13);
  OP2 (A, B, C, D,  1,  3);
  OP2 (D, A, B, C,  5,  5);
  OP2 (C, D, A, B,  9,  9);
  OP2 (B, C, D, A, 13, 13);
  OP2 (A, B, C, D,  2,  3);
  OP2 (D, A, B, C,  6,  5);
  OP2 (C, D, A, B, 10,  9);
  OP2 (B, C, D, A, 14, 13);
  OP2 (A, B, C, D,  3,  3);
  OP2 (D, A, B, C,  7,  5);
  OP2 (C, D, A, B, 11,  9);
  OP2 (B, C, D, A, 15, 13);

  /* Round 3.  */
#define OP3(a,b,c,d,k,s) OP(FH,a,b,c,d,k,s,0x6ED9EBA1)
  OP3 (A, B, C, D,  0,  3);
  OP3 (D, A, B, C,  8,  9);
  OP3 (C, D, A, B,  4, 11);
  OP3 (B, C, D, A, 12, 15);
  OP3 (A, B, C, D,  2,  3);
  OP3 (D, A, B, C, 10,  9);
  OP3 (C, D, A, B,  6, 11);
  OP3 (B, C, D, A, 14, 15);
  OP3 (A, B, C, D,  1,  3);
  OP3 (D, A, B, C,  9,  9);
  OP3 (C, D, A, B,  5, 11);
  OP3 (B, C, D, A, 13, 15);
  OP3 (A, B, C, D,  3,  3);
  OP3 (D, A, B, C, 11,  9);
  OP3 (C, D, A, B,  7, 11);
  OP3 (B, C, D, A, 15, 15);

  /* Put checksum in context given as argument.  */
  ctx->A += A;
  ctx->B += B;
  ctx->C += C;
  ctx->D += D;
}

#ifdef SELFTEST_MAIN
#include <stdio.h>

static void MDString(const char* s)
{
  struct md4_ctx ctx;
  unsigned char digest[16];
  unsigned int len = strlen(s);
  unsigned i;
  
  md4_init_ctx(&ctx);
  md4_process_bytes(s, len, &ctx);
  md4_finish_ctx(&ctx, digest);
  printf("MD4 (\"%s\") = ", s);
  for (i = 0; i < 16; i++) printf("%02x", digest[i]);
  printf("\n");
}

MAIN
{
  MDString("");
  MDString("a");
  MDString("abc");
  MDString("message digest");
  MDString("abcdefghijklmnopqrstuvwxyz");
  MDString("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
  
  MDString("1234567890123456789012345678901234567890"
	   "1234567890123456789012345678901234567890");
}
#endif
#ifdef SELFTEST_EXP
MD4 ("") = 31d6cfe0d16ae931b73c59d7e0c089c0
MD4 ("a") = bde52cb31de33e46245e05fbdbd6fb24
MD4 ("abc") = a448017aaf21d8525fc10ae87aa6729d
MD4 ("message digest") = d9130a8164549fe818874806e1c7014b
MD4 ("abcdefghijklmnopqrstuvwxyz") = d79e1c308aa5bbcdeea8ed63df412da9
MD4 ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") = 043f8582f241db351ce627e153e7f0e4
MD4 ("12345678901234567890123456789012345678901234567890123456789012345678901234567890") = e33b4ddc9c38f2199c3e7b164fcc0536
#endif