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