1/* md4c.c: "RSA Data Security, Inc. MD4 Message-Digest Algorithm"
2
3%%% portions-copyright-cmetz-96
4Portions of this software are Copyright 1996-1999 by Craig Metz, All Rights
5Reserved. The Inner Net License Version 2 applies to these portions of
6the software.
7You should have received a copy of the license with this software. If
8you didn't get a copy, you may request one from <license@inner.net>.
9
10Portions of this software are Copyright 1995 by Randall Atkinson and Dan
11McDonald, All Rights Reserved. All Rights under this copyright are assigned
12to the U.S. Naval Research Laboratory (NRL). The NRL Copyright Notice and
13License Agreement applies to this software.
14
15	History:
16
17	Modified by cmetz for OPIE 2.2. Use FUNCTION declaration et al.
18              Use the real memcpy() and memset(). Use unified context
19              structure.
20	Modified at NRL for OPIE 2.0.
21	Originally from RSADSI reference code.
22*/
23/* Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.
24
25   License to copy and use this software is granted provided that it
26   is identified as the "RSA Data Security, Inc. MD4 Message-Digest
27   Algorithm" in all material mentioning or referencing this software
28   or this function.
29
30   License is also granted to make and use derivative works provided
31   that such works are identified as "derived from the RSA Data
32   Security, Inc. MD4 Message-Digest Algorithm" in all material
33   mentioning or referencing the derived work.
34
35   RSA Data Security, Inc. makes no representations concerning either
36   the merchantability of this software or the suitability of this
37   software for any particular purpose. It is provided "as is"
38   without express or implied warranty of any kind.
39
40   These notices must be retained in any copies of any part of this
41   documentation and/or software.
42 */
43
44#include "opie_cfg.h"
45#include "opie.h"
46
47/* Constants for MD4Transform routine.
48 */
49#define S11 3
50#define S12 7
51#define S13 11
52#define S14 19
53#define S21 3
54#define S22 5
55#define S23 9
56#define S24 13
57#define S31 3
58#define S32 9
59#define S33 11
60#define S34 15
61
62static VOIDRET MD4Transform __P((UINT4[4], unsigned char[64]));
63static VOIDRET Encode __P((unsigned char *, UINT4 *, unsigned int));
64static VOIDRET Decode __P((UINT4 *, unsigned char *, unsigned int));
65
66static unsigned char PADDING[64] =
67{
68  0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
69  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
70  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
71};
72
73/* F, G and H are basic MD4 functions.
74 */
75#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
76#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
77#define H(x, y, z) ((x) ^ (y) ^ (z))
78
79/* ROTATE_LEFT rotates x left n bits.
80 */
81#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
82
83/* FF, GG and HH are transformations for rounds 1, 2 and 3 */
84/* Rotation is separate from addition to prevent recomputation */
85
86#define FF(a, b, c, d, x, s) { \
87    (a) += F ((b), (c), (d)) + (x); \
88    (a) = ROTATE_LEFT ((a), (s)); \
89  }
90#define GG(a, b, c, d, x, s) { \
91    (a) += G ((b), (c), (d)) + (x) + (UINT4)0x5a827999; \
92    (a) = ROTATE_LEFT ((a), (s)); \
93  }
94#define HH(a, b, c, d, x, s) { \
95    (a) += H ((b), (c), (d)) + (x) + (UINT4)0x6ed9eba1; \
96    (a) = ROTATE_LEFT ((a), (s)); \
97  }
98
99/* MD4 initialization. Begins an MD4 operation, writing a new context.
100 */
101VOIDRET opiemd4init FUNCTION((context), struct opiemdx_ctx *context)
102{
103  context->count[0] = context->count[1] = 0;
104
105  /* Load magic initialization constants. */
106  context->state[0] = 0x67452301;
107  context->state[1] = 0xefcdab89;
108  context->state[2] = 0x98badcfe;
109  context->state[3] = 0x10325476;
110}
111
112/* MD4 block update operation. Continues an MD4 message-digest
113   operation, processing another message block, and updating the
114   context.
115 */
116VOIDRET opiemd4update FUNCTION((context, input, inputLen), struct opiemdx_ctx *context AND unsigned char *input AND unsigned int inputLen)
117{
118  unsigned int i, index, partLen;
119
120  /* Compute number of bytes mod 64 */
121  index = (unsigned int) ((context->count[0] >> 3) & 0x3F);
122  /* Update number of bits */
123  if ((context->count[0] += ((UINT4) inputLen << 3))
124      < ((UINT4) inputLen << 3))
125    context->count[1]++;
126  context->count[1] += ((UINT4) inputLen >> 29);
127
128  partLen = 64 - index;
129
130  /* Transform as many times as possible. */
131  if (inputLen >= partLen) {
132    memcpy((POINTER) & context->buffer[index], (POINTER) input, partLen);
133    MD4Transform(context->state, context->buffer);
134
135    for (i = partLen; i + 63 < inputLen; i += 64)
136      MD4Transform(context->state, &input[i]);
137
138    index = 0;
139  } else
140    i = 0;
141
142  /* Buffer remaining input */
143  memcpy((POINTER) & context->buffer[index], (POINTER) & input[i], inputLen - i);
144}
145
146/* MD4 finalization. Ends an MD4 message-digest operation, writing the
147   the message digest and zeroizing the context.
148 */
149VOIDRET opiemd4final FUNCTION((digest, context), unsigned char *digest AND struct opiemdx_ctx *context)
150{
151  unsigned char bits[8];
152  unsigned int index, padLen;
153
154  /* Save number of bits */
155  Encode(bits, context->count, 8);
156
157  /* Pad out to 56 mod 64. */
158  index = (unsigned int) ((context->count[0] >> 3) & 0x3f);
159  padLen = (index < 56) ? (56 - index) : (120 - index);
160  opiemd4update(context, PADDING, padLen);
161
162  /* Append length (before padding) */
163  opiemd4update(context, bits, 8);
164  /* Store state in digest */
165  Encode(digest, context->state, 16);
166
167  /* Zeroize sensitive information. */
168  memset((POINTER) context, 0, sizeof(*context));
169}
170
171/* MD4 basic transformation. Transforms state based on block.
172 */
173static VOIDRET MD4Transform FUNCTION((state, block), UINT4 state[4] AND unsigned char block[64])
174{
175  UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
176
177  Decode(x, block, 64);
178
179  /* Round 1 */
180  FF(a, b, c, d, x[0], S11);	/* 1 */
181  FF(d, a, b, c, x[1], S12);	/* 2 */
182  FF(c, d, a, b, x[2], S13);	/* 3 */
183  FF(b, c, d, a, x[3], S14);	/* 4 */
184  FF(a, b, c, d, x[4], S11);	/* 5 */
185  FF(d, a, b, c, x[5], S12);	/* 6 */
186  FF(c, d, a, b, x[6], S13);	/* 7 */
187  FF(b, c, d, a, x[7], S14);	/* 8 */
188  FF(a, b, c, d, x[8], S11);	/* 9 */
189  FF(d, a, b, c, x[9], S12);	/* 10 */
190  FF(c, d, a, b, x[10], S13);	/* 11 */
191  FF(b, c, d, a, x[11], S14);	/* 12 */
192  FF(a, b, c, d, x[12], S11);	/* 13 */
193  FF(d, a, b, c, x[13], S12);	/* 14 */
194  FF(c, d, a, b, x[14], S13);	/* 15 */
195  FF(b, c, d, a, x[15], S14);	/* 16 */
196
197  /* Round 2 */
198  GG(a, b, c, d, x[0], S21);	/* 17 */
199  GG(d, a, b, c, x[4], S22);	/* 18 */
200  GG(c, d, a, b, x[8], S23);	/* 19 */
201  GG(b, c, d, a, x[12], S24);	/* 20 */
202  GG(a, b, c, d, x[1], S21);	/* 21 */
203  GG(d, a, b, c, x[5], S22);	/* 22 */
204  GG(c, d, a, b, x[9], S23);	/* 23 */
205  GG(b, c, d, a, x[13], S24);	/* 24 */
206  GG(a, b, c, d, x[2], S21);	/* 25 */
207  GG(d, a, b, c, x[6], S22);	/* 26 */
208  GG(c, d, a, b, x[10], S23);	/* 27 */
209  GG(b, c, d, a, x[14], S24);	/* 28 */
210  GG(a, b, c, d, x[3], S21);	/* 29 */
211  GG(d, a, b, c, x[7], S22);	/* 30 */
212  GG(c, d, a, b, x[11], S23);	/* 31 */
213  GG(b, c, d, a, x[15], S24);	/* 32 */
214
215  /* Round 3 */
216  HH(a, b, c, d, x[0], S31);	/* 33 */
217  HH(d, a, b, c, x[8], S32);	/* 34 */
218  HH(c, d, a, b, x[4], S33);	/* 35 */
219  HH(b, c, d, a, x[12], S34);	/* 36 */
220  HH(a, b, c, d, x[2], S31);	/* 37 */
221  HH(d, a, b, c, x[10], S32);	/* 38 */
222  HH(c, d, a, b, x[6], S33);	/* 39 */
223  HH(b, c, d, a, x[14], S34);	/* 40 */
224  HH(a, b, c, d, x[1], S31);	/* 41 */
225  HH(d, a, b, c, x[9], S32);	/* 42 */
226  HH(c, d, a, b, x[5], S33);	/* 43 */
227  HH(b, c, d, a, x[13], S34);	/* 44 */
228  HH(a, b, c, d, x[3], S31);	/* 45 */
229  HH(d, a, b, c, x[11], S32);	/* 46 */
230  HH(c, d, a, b, x[7], S33);	/* 47 */
231  HH(b, c, d, a, x[15], S34);	/* 48 */
232
233  state[0] += a;
234  state[1] += b;
235  state[2] += c;
236  state[3] += d;
237
238  /* Zeroize sensitive information. */
239  memset((POINTER) x, 0, sizeof(x));
240}
241
242/* Encodes input (UINT4) into output (unsigned char). Assumes len is
243   a multiple of 4.
244 */
245static VOIDRET Encode FUNCTION((output, input, len), unsigned char *output AND UINT4 *input AND unsigned int len)
246{
247  unsigned int i, j;
248
249  for (i = 0, j = 0; j < len; i++, j += 4) {
250    output[j] = (unsigned char) (input[i] & 0xff);
251    output[j + 1] = (unsigned char) ((input[i] >> 8) & 0xff);
252    output[j + 2] = (unsigned char) ((input[i] >> 16) & 0xff);
253    output[j + 3] = (unsigned char) ((input[i] >> 24) & 0xff);
254  }
255}
256
257/* Decodes input (unsigned char) into output (UINT4). Assumes len is
258   a multiple of 4.
259 */
260static VOIDRET Decode FUNCTION((output, input, len), UINT4 *output AND unsigned char *input AND unsigned int len)
261{
262  unsigned int i, j;
263
264  for (i = 0, j = 0; j < len; i++, j += 4)
265    output[i] = ((UINT4) input[j]) | (((UINT4) input[j + 1]) << 8) |
266      (((UINT4) input[j + 2]) << 16) | (((UINT4) input[j + 3]) << 24);
267}
268