xref: /freebsd-src/contrib/wpa/src/crypto/md4-internal.c (revision 7648bc9fee8dec6cb3c4941e0165a930fbe8dcb0)
1e28a4053SRui Paulo /*
2e28a4053SRui Paulo  * MD4 hash implementation
3e28a4053SRui Paulo  * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
4e28a4053SRui Paulo  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
7e28a4053SRui Paulo  */
8e28a4053SRui Paulo 
9e28a4053SRui Paulo #include "includes.h"
10e28a4053SRui Paulo 
11e28a4053SRui Paulo #include "common.h"
12e28a4053SRui Paulo #include "crypto.h"
13e28a4053SRui Paulo 
14e28a4053SRui Paulo #define	MD4_BLOCK_LENGTH		64
15e28a4053SRui Paulo #define	MD4_DIGEST_LENGTH		16
16e28a4053SRui Paulo 
17e28a4053SRui Paulo typedef struct MD4Context {
18e28a4053SRui Paulo 	u32 state[4];			/* state */
19e28a4053SRui Paulo 	u64 count;			/* number of bits, mod 2^64 */
20e28a4053SRui Paulo 	u8 buffer[MD4_BLOCK_LENGTH];	/* input buffer */
21e28a4053SRui Paulo } MD4_CTX;
22e28a4053SRui Paulo 
23e28a4053SRui Paulo 
24e28a4053SRui Paulo static void MD4Init(MD4_CTX *ctx);
25e28a4053SRui Paulo static void MD4Update(MD4_CTX *ctx, const unsigned char *input, size_t len);
26e28a4053SRui Paulo static void MD4Final(unsigned char digest[MD4_DIGEST_LENGTH], MD4_CTX *ctx);
27e28a4053SRui Paulo 
28e28a4053SRui Paulo 
md4_vector(size_t num_elem,const u8 * addr[],const size_t * len,u8 * mac)29e28a4053SRui Paulo int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
30e28a4053SRui Paulo {
31e28a4053SRui Paulo 	MD4_CTX ctx;
32e28a4053SRui Paulo 	size_t i;
33e28a4053SRui Paulo 
34780fb4a2SCy Schubert 	if (TEST_FAIL())
35780fb4a2SCy Schubert 		return -1;
36780fb4a2SCy Schubert 
37e28a4053SRui Paulo 	MD4Init(&ctx);
38e28a4053SRui Paulo 	for (i = 0; i < num_elem; i++)
39e28a4053SRui Paulo 		MD4Update(&ctx, addr[i], len[i]);
40e28a4053SRui Paulo 	MD4Final(mac, &ctx);
41e28a4053SRui Paulo 	return 0;
42e28a4053SRui Paulo }
43e28a4053SRui Paulo 
44e28a4053SRui Paulo 
45e28a4053SRui Paulo /* ===== start - public domain MD4 implementation ===== */
46e28a4053SRui Paulo /*	$OpenBSD: md4.c,v 1.7 2005/08/08 08:05:35 espie Exp $	*/
47e28a4053SRui Paulo 
48e28a4053SRui Paulo /*
49e28a4053SRui Paulo  * This code implements the MD4 message-digest algorithm.
50e28a4053SRui Paulo  * The algorithm is due to Ron Rivest.	This code was
51e28a4053SRui Paulo  * written by Colin Plumb in 1993, no copyright is claimed.
52e28a4053SRui Paulo  * This code is in the public domain; do with it what you wish.
53e28a4053SRui Paulo  * Todd C. Miller modified the MD5 code to do MD4 based on RFC 1186.
54e28a4053SRui Paulo  *
55e28a4053SRui Paulo  * Equivalent code is available from RSA Data Security, Inc.
56e28a4053SRui Paulo  * This code has been tested against that, and is equivalent,
57e28a4053SRui Paulo  * except that you don't need to include two pages of legalese
58e28a4053SRui Paulo  * with every copy.
59e28a4053SRui Paulo  *
60e28a4053SRui Paulo  * To compute the message digest of a chunk of bytes, declare an
61e28a4053SRui Paulo  * MD4Context structure, pass it to MD4Init, call MD4Update as
62e28a4053SRui Paulo  * needed on buffers full of bytes, and then call MD4Final, which
63e28a4053SRui Paulo  * will fill a supplied 16-byte array with the digest.
64e28a4053SRui Paulo  */
65e28a4053SRui Paulo 
66e28a4053SRui Paulo #define	MD4_DIGEST_STRING_LENGTH	(MD4_DIGEST_LENGTH * 2 + 1)
67e28a4053SRui Paulo 
68e28a4053SRui Paulo 
69e28a4053SRui Paulo static void
70e28a4053SRui Paulo MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH]);
71e28a4053SRui Paulo 
72e28a4053SRui Paulo #define PUT_64BIT_LE(cp, value) do {					\
73e28a4053SRui Paulo 	(cp)[7] = (value) >> 56;					\
74e28a4053SRui Paulo 	(cp)[6] = (value) >> 48;					\
75e28a4053SRui Paulo 	(cp)[5] = (value) >> 40;					\
76e28a4053SRui Paulo 	(cp)[4] = (value) >> 32;					\
77e28a4053SRui Paulo 	(cp)[3] = (value) >> 24;					\
78e28a4053SRui Paulo 	(cp)[2] = (value) >> 16;					\
79e28a4053SRui Paulo 	(cp)[1] = (value) >> 8;						\
80e28a4053SRui Paulo 	(cp)[0] = (value); } while (0)
81e28a4053SRui Paulo 
82e28a4053SRui Paulo #define PUT_32BIT_LE(cp, value) do {					\
83e28a4053SRui Paulo 	(cp)[3] = (value) >> 24;					\
84e28a4053SRui Paulo 	(cp)[2] = (value) >> 16;					\
85e28a4053SRui Paulo 	(cp)[1] = (value) >> 8;						\
86e28a4053SRui Paulo 	(cp)[0] = (value); } while (0)
87e28a4053SRui Paulo 
88*4bc52338SCy Schubert static const u8 PADDING[MD4_BLOCK_LENGTH] = {
89e28a4053SRui Paulo 	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
90e28a4053SRui Paulo 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
91e28a4053SRui Paulo 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
92e28a4053SRui Paulo };
93e28a4053SRui Paulo 
94e28a4053SRui Paulo /*
95e28a4053SRui Paulo  * Start MD4 accumulation.
96e28a4053SRui Paulo  * Set bit count to 0 and buffer to mysterious initialization constants.
97e28a4053SRui Paulo  */
MD4Init(MD4_CTX * ctx)98e28a4053SRui Paulo static void MD4Init(MD4_CTX *ctx)
99e28a4053SRui Paulo {
100e28a4053SRui Paulo 	ctx->count = 0;
101e28a4053SRui Paulo 	ctx->state[0] = 0x67452301;
102e28a4053SRui Paulo 	ctx->state[1] = 0xefcdab89;
103e28a4053SRui Paulo 	ctx->state[2] = 0x98badcfe;
104e28a4053SRui Paulo 	ctx->state[3] = 0x10325476;
105e28a4053SRui Paulo }
106e28a4053SRui Paulo 
107e28a4053SRui Paulo /*
108e28a4053SRui Paulo  * Update context to reflect the concatenation of another buffer full
109e28a4053SRui Paulo  * of bytes.
110e28a4053SRui Paulo  */
MD4Update(MD4_CTX * ctx,const unsigned char * input,size_t len)111e28a4053SRui Paulo static void MD4Update(MD4_CTX *ctx, const unsigned char *input, size_t len)
112e28a4053SRui Paulo {
113e28a4053SRui Paulo 	size_t have, need;
114e28a4053SRui Paulo 
115e28a4053SRui Paulo 	/* Check how many bytes we already have and how many more we need. */
116e28a4053SRui Paulo 	have = (size_t)((ctx->count >> 3) & (MD4_BLOCK_LENGTH - 1));
117e28a4053SRui Paulo 	need = MD4_BLOCK_LENGTH - have;
118e28a4053SRui Paulo 
119e28a4053SRui Paulo 	/* Update bitcount */
120e28a4053SRui Paulo 	ctx->count += (u64)len << 3;
121e28a4053SRui Paulo 
122e28a4053SRui Paulo 	if (len >= need) {
123e28a4053SRui Paulo 		if (have != 0) {
124e28a4053SRui Paulo 			os_memcpy(ctx->buffer + have, input, need);
125e28a4053SRui Paulo 			MD4Transform(ctx->state, ctx->buffer);
126e28a4053SRui Paulo 			input += need;
127e28a4053SRui Paulo 			len -= need;
128e28a4053SRui Paulo 			have = 0;
129e28a4053SRui Paulo 		}
130e28a4053SRui Paulo 
131e28a4053SRui Paulo 		/* Process data in MD4_BLOCK_LENGTH-byte chunks. */
132e28a4053SRui Paulo 		while (len >= MD4_BLOCK_LENGTH) {
133e28a4053SRui Paulo 			MD4Transform(ctx->state, input);
134e28a4053SRui Paulo 			input += MD4_BLOCK_LENGTH;
135e28a4053SRui Paulo 			len -= MD4_BLOCK_LENGTH;
136e28a4053SRui Paulo 		}
137e28a4053SRui Paulo 	}
138e28a4053SRui Paulo 
139e28a4053SRui Paulo 	/* Handle any remaining bytes of data. */
140e28a4053SRui Paulo 	if (len != 0)
141e28a4053SRui Paulo 		os_memcpy(ctx->buffer + have, input, len);
142e28a4053SRui Paulo }
143e28a4053SRui Paulo 
144e28a4053SRui Paulo /*
145e28a4053SRui Paulo  * Pad pad to 64-byte boundary with the bit pattern
146e28a4053SRui Paulo  * 1 0* (64-bit count of bits processed, MSB-first)
147e28a4053SRui Paulo  */
MD4Pad(MD4_CTX * ctx)148e28a4053SRui Paulo static void MD4Pad(MD4_CTX *ctx)
149e28a4053SRui Paulo {
150e28a4053SRui Paulo 	u8 count[8];
151e28a4053SRui Paulo 	size_t padlen;
152e28a4053SRui Paulo 
153e28a4053SRui Paulo 	/* Convert count to 8 bytes in little endian order. */
154e28a4053SRui Paulo 	PUT_64BIT_LE(count, ctx->count);
155e28a4053SRui Paulo 
156e28a4053SRui Paulo 	/* Pad out to 56 mod 64. */
157e28a4053SRui Paulo 	padlen = MD4_BLOCK_LENGTH -
158e28a4053SRui Paulo 	    ((ctx->count >> 3) & (MD4_BLOCK_LENGTH - 1));
159e28a4053SRui Paulo 	if (padlen < 1 + 8)
160e28a4053SRui Paulo 		padlen += MD4_BLOCK_LENGTH;
161e28a4053SRui Paulo 	MD4Update(ctx, PADDING, padlen - 8);		/* padlen - 8 <= 64 */
162e28a4053SRui Paulo 	MD4Update(ctx, count, 8);
163e28a4053SRui Paulo }
164e28a4053SRui Paulo 
165e28a4053SRui Paulo /*
166e28a4053SRui Paulo  * Final wrapup--call MD4Pad, fill in digest and zero out ctx.
167e28a4053SRui Paulo  */
MD4Final(unsigned char digest[MD4_DIGEST_LENGTH],MD4_CTX * ctx)168e28a4053SRui Paulo static void MD4Final(unsigned char digest[MD4_DIGEST_LENGTH], MD4_CTX *ctx)
169e28a4053SRui Paulo {
170e28a4053SRui Paulo 	int i;
171e28a4053SRui Paulo 
172e28a4053SRui Paulo 	MD4Pad(ctx);
173e28a4053SRui Paulo 	if (digest != NULL) {
174e28a4053SRui Paulo 		for (i = 0; i < 4; i++)
175e28a4053SRui Paulo 			PUT_32BIT_LE(digest + i * 4, ctx->state[i]);
176e28a4053SRui Paulo 		os_memset(ctx, 0, sizeof(*ctx));
177e28a4053SRui Paulo 	}
178e28a4053SRui Paulo }
179e28a4053SRui Paulo 
180e28a4053SRui Paulo 
181e28a4053SRui Paulo /* The three core functions - F1 is optimized somewhat */
182e28a4053SRui Paulo 
183e28a4053SRui Paulo /* #define F1(x, y, z) (x & y | ~x & z) */
184e28a4053SRui Paulo #define F1(x, y, z) (z ^ (x & (y ^ z)))
185e28a4053SRui Paulo #define F2(x, y, z) ((x & y) | (x & z) | (y & z))
186e28a4053SRui Paulo #define F3(x, y, z) (x ^ y ^ z)
187e28a4053SRui Paulo 
188e28a4053SRui Paulo /* This is the central step in the MD4 algorithm. */
189e28a4053SRui Paulo #define MD4STEP(f, w, x, y, z, data, s) \
190e28a4053SRui Paulo 	( w += f(x, y, z) + data,  w = w<<s | w>>(32-s) )
191e28a4053SRui Paulo 
192e28a4053SRui Paulo /*
193e28a4053SRui Paulo  * The core of the MD4 algorithm, this alters an existing MD4 hash to
194e28a4053SRui Paulo  * reflect the addition of 16 longwords of new data.  MD4Update blocks
195e28a4053SRui Paulo  * the data and converts bytes into longwords for this routine.
196e28a4053SRui Paulo  */
197e28a4053SRui Paulo static void
MD4Transform(u32 state[4],const u8 block[MD4_BLOCK_LENGTH])198e28a4053SRui Paulo MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH])
199e28a4053SRui Paulo {
200e28a4053SRui Paulo 	u32 a, b, c, d, in[MD4_BLOCK_LENGTH / 4];
201e28a4053SRui Paulo 
202e28a4053SRui Paulo #if BYTE_ORDER == LITTLE_ENDIAN
203e28a4053SRui Paulo 	os_memcpy(in, block, sizeof(in));
204e28a4053SRui Paulo #else
205e28a4053SRui Paulo 	for (a = 0; a < MD4_BLOCK_LENGTH / 4; a++) {
206e28a4053SRui Paulo 		in[a] = (u32)(
207e28a4053SRui Paulo 		    (u32)(block[a * 4 + 0]) |
208e28a4053SRui Paulo 		    (u32)(block[a * 4 + 1]) <<  8 |
209e28a4053SRui Paulo 		    (u32)(block[a * 4 + 2]) << 16 |
210e28a4053SRui Paulo 		    (u32)(block[a * 4 + 3]) << 24);
211e28a4053SRui Paulo 	}
212e28a4053SRui Paulo #endif
213e28a4053SRui Paulo 
214e28a4053SRui Paulo 	a = state[0];
215e28a4053SRui Paulo 	b = state[1];
216e28a4053SRui Paulo 	c = state[2];
217e28a4053SRui Paulo 	d = state[3];
218e28a4053SRui Paulo 
219e28a4053SRui Paulo 	MD4STEP(F1, a, b, c, d, in[ 0],  3);
220e28a4053SRui Paulo 	MD4STEP(F1, d, a, b, c, in[ 1],  7);
221e28a4053SRui Paulo 	MD4STEP(F1, c, d, a, b, in[ 2], 11);
222e28a4053SRui Paulo 	MD4STEP(F1, b, c, d, a, in[ 3], 19);
223e28a4053SRui Paulo 	MD4STEP(F1, a, b, c, d, in[ 4],  3);
224e28a4053SRui Paulo 	MD4STEP(F1, d, a, b, c, in[ 5],  7);
225e28a4053SRui Paulo 	MD4STEP(F1, c, d, a, b, in[ 6], 11);
226e28a4053SRui Paulo 	MD4STEP(F1, b, c, d, a, in[ 7], 19);
227e28a4053SRui Paulo 	MD4STEP(F1, a, b, c, d, in[ 8],  3);
228e28a4053SRui Paulo 	MD4STEP(F1, d, a, b, c, in[ 9],  7);
229e28a4053SRui Paulo 	MD4STEP(F1, c, d, a, b, in[10], 11);
230e28a4053SRui Paulo 	MD4STEP(F1, b, c, d, a, in[11], 19);
231e28a4053SRui Paulo 	MD4STEP(F1, a, b, c, d, in[12],  3);
232e28a4053SRui Paulo 	MD4STEP(F1, d, a, b, c, in[13],  7);
233e28a4053SRui Paulo 	MD4STEP(F1, c, d, a, b, in[14], 11);
234e28a4053SRui Paulo 	MD4STEP(F1, b, c, d, a, in[15], 19);
235e28a4053SRui Paulo 
236e28a4053SRui Paulo 	MD4STEP(F2, a, b, c, d, in[ 0] + 0x5a827999,  3);
237e28a4053SRui Paulo 	MD4STEP(F2, d, a, b, c, in[ 4] + 0x5a827999,  5);
238e28a4053SRui Paulo 	MD4STEP(F2, c, d, a, b, in[ 8] + 0x5a827999,  9);
239e28a4053SRui Paulo 	MD4STEP(F2, b, c, d, a, in[12] + 0x5a827999, 13);
240e28a4053SRui Paulo 	MD4STEP(F2, a, b, c, d, in[ 1] + 0x5a827999,  3);
241e28a4053SRui Paulo 	MD4STEP(F2, d, a, b, c, in[ 5] + 0x5a827999,  5);
242e28a4053SRui Paulo 	MD4STEP(F2, c, d, a, b, in[ 9] + 0x5a827999,  9);
243e28a4053SRui Paulo 	MD4STEP(F2, b, c, d, a, in[13] + 0x5a827999, 13);
244e28a4053SRui Paulo 	MD4STEP(F2, a, b, c, d, in[ 2] + 0x5a827999,  3);
245e28a4053SRui Paulo 	MD4STEP(F2, d, a, b, c, in[ 6] + 0x5a827999,  5);
246e28a4053SRui Paulo 	MD4STEP(F2, c, d, a, b, in[10] + 0x5a827999,  9);
247e28a4053SRui Paulo 	MD4STEP(F2, b, c, d, a, in[14] + 0x5a827999, 13);
248e28a4053SRui Paulo 	MD4STEP(F2, a, b, c, d, in[ 3] + 0x5a827999,  3);
249e28a4053SRui Paulo 	MD4STEP(F2, d, a, b, c, in[ 7] + 0x5a827999,  5);
250e28a4053SRui Paulo 	MD4STEP(F2, c, d, a, b, in[11] + 0x5a827999,  9);
251e28a4053SRui Paulo 	MD4STEP(F2, b, c, d, a, in[15] + 0x5a827999, 13);
252e28a4053SRui Paulo 
253e28a4053SRui Paulo 	MD4STEP(F3, a, b, c, d, in[ 0] + 0x6ed9eba1,  3);
254e28a4053SRui Paulo 	MD4STEP(F3, d, a, b, c, in[ 8] + 0x6ed9eba1,  9);
255e28a4053SRui Paulo 	MD4STEP(F3, c, d, a, b, in[ 4] + 0x6ed9eba1, 11);
256e28a4053SRui Paulo 	MD4STEP(F3, b, c, d, a, in[12] + 0x6ed9eba1, 15);
257e28a4053SRui Paulo 	MD4STEP(F3, a, b, c, d, in[ 2] + 0x6ed9eba1,  3);
258e28a4053SRui Paulo 	MD4STEP(F3, d, a, b, c, in[10] + 0x6ed9eba1,  9);
259e28a4053SRui Paulo 	MD4STEP(F3, c, d, a, b, in[ 6] + 0x6ed9eba1, 11);
260e28a4053SRui Paulo 	MD4STEP(F3, b, c, d, a, in[14] + 0x6ed9eba1, 15);
261e28a4053SRui Paulo 	MD4STEP(F3, a, b, c, d, in[ 1] + 0x6ed9eba1,  3);
262e28a4053SRui Paulo 	MD4STEP(F3, d, a, b, c, in[ 9] + 0x6ed9eba1,  9);
263e28a4053SRui Paulo 	MD4STEP(F3, c, d, a, b, in[ 5] + 0x6ed9eba1, 11);
264e28a4053SRui Paulo 	MD4STEP(F3, b, c, d, a, in[13] + 0x6ed9eba1, 15);
265e28a4053SRui Paulo 	MD4STEP(F3, a, b, c, d, in[ 3] + 0x6ed9eba1,  3);
266e28a4053SRui Paulo 	MD4STEP(F3, d, a, b, c, in[11] + 0x6ed9eba1,  9);
267e28a4053SRui Paulo 	MD4STEP(F3, c, d, a, b, in[ 7] + 0x6ed9eba1, 11);
268e28a4053SRui Paulo 	MD4STEP(F3, b, c, d, a, in[15] + 0x6ed9eba1, 15);
269e28a4053SRui Paulo 
270e28a4053SRui Paulo 	state[0] += a;
271e28a4053SRui Paulo 	state[1] += b;
272e28a4053SRui Paulo 	state[2] += c;
273e28a4053SRui Paulo 	state[3] += d;
274e28a4053SRui Paulo }
275e28a4053SRui Paulo /* ===== end - public domain MD4 implementation ===== */
276