Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "os.h"
2
#include <libsec.h>
3
 
4
/*
5
 *  This MD4 is implemented from the description in Stinson's Cryptography,
6
 *  theory and practice. -- presotto
7
 */
8
 
9
/*
10
 *	Rotate ammounts used in the algorithm
11
 */
12
enum
13
{
14
	S11=	3,
15
	S12=	7,
16
	S13=	11,
17
	S14=	19,
18
 
19
	S21=	3,
20
	S22=	5,
21
	S23=	9,
22
	S24=	13,
23
 
24
	S31=	3,
25
	S32=	9,
26
	S33=	11,
27
	S34=	15,
28
};
29
 
30
typedef struct MD4Table MD4Table;
31
struct MD4Table
32
{
33
	uchar	x;	/* index into data block */
34
	uchar	rot;	/* amount to rotate left by */
35
};
36
 
37
static MD4Table tab[] =
38
{
39
	/* round 1 */
40
/*[0]*/	{ 0,	S11},	
41
	{ 1,	S12},	
42
	{ 2,	S13},	
43
	{ 3,	S14},	
44
	{ 4,	S11},	
45
	{ 5,	S12},	
46
	{ 6,	S13},	
47
	{ 7,	S14},	
48
	{ 8,	S11},	
49
	{ 9,	S12},	
50
	{ 10,	S13},	
51
	{ 11,	S14},	
52
	{ 12,	S11},	
53
	{ 13,	S12},	
54
	{ 14,	S13},	
55
	{ 15,	S14},
56
 
57
	/* round 2 */
58
/*[16]*/{ 0,	S21},	
59
	{ 4,	S22},	
60
	{ 8,	S23},	
61
	{ 12,	S24},	
62
	{ 1,	S21},	
63
	{ 5,	S22},	
64
	{ 9,	S23},	
65
	{ 13,	S24},	
66
	{ 2,	S21},	
67
	{ 6,	S22},	
68
	{ 10,	S23},	
69
	{ 14,	S24},	
70
	{ 3,	S21},	
71
	{ 7,	S22},	
72
	{ 11,	S23},	
73
	{ 15,	S24},
74
 
75
	/* round 3 */
76
/*[32]*/{ 0,	S31},	
77
	{ 8,	S32},	
78
	{ 4,	S33},	
79
	{ 12,	S34},	
80
	{ 2,	S31},	
81
	{ 10,	S32},	
82
	{ 6,	S33},	
83
	{ 14,	S34},	
84
	{ 1,	S31},	
85
	{ 9,	S32},	
86
	{ 5,	S33},	
87
	{ 13,	S34},	
88
	{ 3,	S31},	
89
	{ 11,	S32},	
90
	{ 7,	S33},	
91
	{ 15,	S34},	
92
};
93
 
94
static void encode(uchar*, u32int*, ulong);
95
static void decode(u32int*, uchar*, ulong);
96
 
97
static void
98
md4block(uchar *p, ulong len, MD4state *s)
99
{
100
	int i;
101
	u32int a, b, c, d, tmp;
102
	MD4Table *t;
103
	uchar *end;
104
	u32int x[16];
105
 
106
	for(end = p+len; p < end; p += 64){
107
		a = s->state[0];
108
		b = s->state[1];
109
		c = s->state[2];
110
		d = s->state[3];
111
 
112
		decode(x, p, 64);
113
 
114
		for(i = 0; i < 48; i++){
115
			t = tab + i;
116
			switch(i>>4){
117
			case 0:
118
				a += (b & c) | (~b & d);
119
				break;
120
			case 1:
121
				a += ((b & c) | (b & d) | (c & d)) + 0x5A827999;
122
				break;
123
			case 2:
124
				a += (b ^ c ^ d) + 0x6ED9EBA1;
125
				break;
126
			}
127
			a += x[t->x];
128
			a = (a << t->rot) | (a >> (32 - t->rot));
129
 
130
			/* rotate variables */
131
			tmp = d;
132
			d = c;
133
			c = b;
134
			b = a;
135
			a = tmp;
136
		}
137
 
138
		s->state[0] += a;
139
		s->state[1] += b;
140
		s->state[2] += c;
141
		s->state[3] += d;
142
 
143
		s->len += 64;
144
	}
145
}
146
 
147
MD4state*
148
md4(uchar *p, ulong len, uchar *digest, MD4state *s)
149
{
150
	u32int x[16];
151
	uchar buf[128];
152
	int i;
153
	uchar *e;
154
 
155
	if(s == nil){
156
		s = malloc(sizeof(*s));
157
		if(s == nil)
158
			return nil;
159
		memset(s, 0, sizeof(*s));
160
		s->malloced = 1;
161
	}
162
 
163
	if(s->seeded == 0){
164
		/* seed the state, these constants would look nicer big-endian */
165
		s->state[0] = 0x67452301;
166
		s->state[1] = 0xefcdab89;
167
		s->state[2] = 0x98badcfe;
168
		s->state[3] = 0x10325476;
169
		s->seeded = 1;
170
	}
171
 
172
	/* fill out the partial 64 byte block from previous calls */
173
	if(s->blen){
174
		i = 64 - s->blen;
175
		if(len < i)
176
			i = len;
177
		memmove(s->buf + s->blen, p, i);
178
		len -= i;
179
		s->blen += i;
180
		p += i;
181
		if(s->blen == 64){
182
			md4block(s->buf, s->blen, s);
183
			s->blen = 0;
184
		}
185
	}
186
 
187
	/* do 64 byte blocks */
188
	i = len & ~0x3f;
189
	if(i){
190
		md4block(p, i, s);
191
		len -= i;
192
		p += i;
193
	}
194
 
195
	/* save the left overs if not last call */
196
	if(digest == 0){
197
		if(len){
198
			memmove(s->buf, p, len);
199
			s->blen += len;
200
		}
201
		return s;
202
	}
203
 
204
	/*
205
	 *  this is the last time through, pad what's left with 0x80,
206
	 *  0's, and the input count to create a multiple of 64 bytes
207
	 */
208
	if(s->blen){
209
		p = s->buf;
210
		len = s->blen;
211
	} else {
212
		memmove(buf, p, len);
213
		p = buf;
214
	}
215
	s->len += len;
216
	e = p + len;
217
	if(len < 56)
218
		i = 56 - len;
219
	else
220
		i = 120 - len;
221
	memset(e, 0, i);
222
	*e = 0x80;
223
	len += i;
224
 
225
	/* append the count */
226
	x[0] = s->len<<3;
227
	x[1] = s->len>>29;
228
	encode(p+len, x, 8);
229
 
230
	/* digest the last part */
231
	md4block(p, len+8, s);
232
 
233
	/* return result and free state */
234
	encode(digest, s->state, MD4dlen);
235
	if(s->malloced == 1)
236
		free(s);
237
	return nil;
238
}
239
 
240
/*
241
 *	encodes input (u32int) into output (uchar). Assumes len is
242
 *	a multiple of 4.
243
 */
244
static void
245
encode(uchar *output, u32int *input, ulong len)
246
{
247
	u32int x;
248
	uchar *e;
249
 
250
	for(e = output + len; output < e;) {
251
		x = *input++;
252
		*output++ = x;
253
		*output++ = x >> 8;
254
		*output++ = x >> 16;
255
		*output++ = x >> 24;
256
	}
257
}
258
 
259
/*
260
 *	decodes input (uchar) into output (u32int). Assumes len is
261
 *	a multiple of 4.
262
 */
263
static void
264
decode(u32int *output, uchar *input, ulong len)
265
{
266
	uchar *e;
267
 
268
	for(e = input+len; input < e; input += 4)
269
		*output++ = input[0] | (input[1] << 8) |
270
			(input[2] << 16) | (input[3] << 24);
271
}