xref: /plan9/sys/src/cmd/unix/drawterm/libsec/md4.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1*8ccd4a63SDavid du Colombier #include "os.h"
2*8ccd4a63SDavid du Colombier #include <libsec.h>
39b943567SDavid du Colombier 
49b943567SDavid du Colombier /*
59b943567SDavid du Colombier  *  This MD4 is implemented from the description in Stinson's Cryptography,
69b943567SDavid du Colombier  *  theory and practice. -- presotto
79b943567SDavid du Colombier  */
89b943567SDavid du Colombier 
99b943567SDavid du Colombier /*
109b943567SDavid du Colombier  *	Rotate ammounts used in the algorithm
119b943567SDavid du Colombier  */
129b943567SDavid du Colombier enum
139b943567SDavid du Colombier {
149b943567SDavid du Colombier 	S11=	3,
159b943567SDavid du Colombier 	S12=	7,
169b943567SDavid du Colombier 	S13=	11,
179b943567SDavid du Colombier 	S14=	19,
189b943567SDavid du Colombier 
199b943567SDavid du Colombier 	S21=	3,
209b943567SDavid du Colombier 	S22=	5,
219b943567SDavid du Colombier 	S23=	9,
229b943567SDavid du Colombier 	S24=	13,
239b943567SDavid du Colombier 
249b943567SDavid du Colombier 	S31=	3,
259b943567SDavid du Colombier 	S32=	9,
269b943567SDavid du Colombier 	S33=	11,
279b943567SDavid du Colombier 	S34=	15,
289b943567SDavid du Colombier };
299b943567SDavid du Colombier 
309b943567SDavid du Colombier typedef struct MD4Table MD4Table;
319b943567SDavid du Colombier struct MD4Table
329b943567SDavid du Colombier {
339b943567SDavid du Colombier 	uchar	x;	/* index into data block */
349b943567SDavid du Colombier 	uchar	rot;	/* amount to rotate left by */
359b943567SDavid du Colombier };
369b943567SDavid du Colombier 
379b943567SDavid du Colombier static MD4Table tab[] =
389b943567SDavid du Colombier {
399b943567SDavid du Colombier 	/* round 1 */
409b943567SDavid du Colombier /*[0]*/	{ 0,	S11},
419b943567SDavid du Colombier 	{ 1,	S12},
429b943567SDavid du Colombier 	{ 2,	S13},
439b943567SDavid du Colombier 	{ 3,	S14},
449b943567SDavid du Colombier 	{ 4,	S11},
459b943567SDavid du Colombier 	{ 5,	S12},
469b943567SDavid du Colombier 	{ 6,	S13},
479b943567SDavid du Colombier 	{ 7,	S14},
489b943567SDavid du Colombier 	{ 8,	S11},
499b943567SDavid du Colombier 	{ 9,	S12},
509b943567SDavid du Colombier 	{ 10,	S13},
519b943567SDavid du Colombier 	{ 11,	S14},
529b943567SDavid du Colombier 	{ 12,	S11},
539b943567SDavid du Colombier 	{ 13,	S12},
549b943567SDavid du Colombier 	{ 14,	S13},
559b943567SDavid du Colombier 	{ 15,	S14},
569b943567SDavid du Colombier 
579b943567SDavid du Colombier 	/* round 2 */
589b943567SDavid du Colombier /*[16]*/{ 0,	S21},
599b943567SDavid du Colombier 	{ 4,	S22},
609b943567SDavid du Colombier 	{ 8,	S23},
619b943567SDavid du Colombier 	{ 12,	S24},
629b943567SDavid du Colombier 	{ 1,	S21},
639b943567SDavid du Colombier 	{ 5,	S22},
649b943567SDavid du Colombier 	{ 9,	S23},
659b943567SDavid du Colombier 	{ 13,	S24},
669b943567SDavid du Colombier 	{ 2,	S21},
679b943567SDavid du Colombier 	{ 6,	S22},
689b943567SDavid du Colombier 	{ 10,	S23},
699b943567SDavid du Colombier 	{ 14,	S24},
709b943567SDavid du Colombier 	{ 3,	S21},
719b943567SDavid du Colombier 	{ 7,	S22},
729b943567SDavid du Colombier 	{ 11,	S23},
739b943567SDavid du Colombier 	{ 15,	S24},
749b943567SDavid du Colombier 
759b943567SDavid du Colombier 	/* round 3 */
769b943567SDavid du Colombier /*[32]*/{ 0,	S31},
779b943567SDavid du Colombier 	{ 8,	S32},
789b943567SDavid du Colombier 	{ 4,	S33},
799b943567SDavid du Colombier 	{ 12,	S34},
809b943567SDavid du Colombier 	{ 2,	S31},
819b943567SDavid du Colombier 	{ 10,	S32},
829b943567SDavid du Colombier 	{ 6,	S33},
839b943567SDavid du Colombier 	{ 14,	S34},
849b943567SDavid du Colombier 	{ 1,	S31},
859b943567SDavid du Colombier 	{ 9,	S32},
869b943567SDavid du Colombier 	{ 5,	S33},
879b943567SDavid du Colombier 	{ 13,	S34},
889b943567SDavid du Colombier 	{ 3,	S31},
899b943567SDavid du Colombier 	{ 11,	S32},
909b943567SDavid du Colombier 	{ 7,	S33},
919b943567SDavid du Colombier 	{ 15,	S34},
929b943567SDavid du Colombier };
939b943567SDavid du Colombier 
949b943567SDavid du Colombier static void encode(uchar*, u32int*, ulong);
959b943567SDavid du Colombier static void decode(u32int*, uchar*, ulong);
969b943567SDavid du Colombier 
979b943567SDavid du Colombier static void
md4block(uchar * p,ulong len,MD4state * s)989b943567SDavid du Colombier md4block(uchar *p, ulong len, MD4state *s)
999b943567SDavid du Colombier {
1009b943567SDavid du Colombier 	int i;
1019b943567SDavid du Colombier 	u32int a, b, c, d, tmp;
1029b943567SDavid du Colombier 	MD4Table *t;
1039b943567SDavid du Colombier 	uchar *end;
1049b943567SDavid du Colombier 	u32int x[16];
1059b943567SDavid du Colombier 
1069b943567SDavid du Colombier 	for(end = p+len; p < end; p += 64){
1079b943567SDavid du Colombier 		a = s->state[0];
1089b943567SDavid du Colombier 		b = s->state[1];
1099b943567SDavid du Colombier 		c = s->state[2];
1109b943567SDavid du Colombier 		d = s->state[3];
1119b943567SDavid du Colombier 
1129b943567SDavid du Colombier 		decode(x, p, 64);
1139b943567SDavid du Colombier 
1149b943567SDavid du Colombier 		for(i = 0; i < 48; i++){
1159b943567SDavid du Colombier 			t = tab + i;
1169b943567SDavid du Colombier 			switch(i>>4){
1179b943567SDavid du Colombier 			case 0:
1189b943567SDavid du Colombier 				a += (b & c) | (~b & d);
1199b943567SDavid du Colombier 				break;
1209b943567SDavid du Colombier 			case 1:
1219b943567SDavid du Colombier 				a += ((b & c) | (b & d) | (c & d)) + 0x5A827999;
1229b943567SDavid du Colombier 				break;
1239b943567SDavid du Colombier 			case 2:
1249b943567SDavid du Colombier 				a += (b ^ c ^ d) + 0x6ED9EBA1;
1259b943567SDavid du Colombier 				break;
1269b943567SDavid du Colombier 			}
1279b943567SDavid du Colombier 			a += x[t->x];
1289b943567SDavid du Colombier 			a = (a << t->rot) | (a >> (32 - t->rot));
1299b943567SDavid du Colombier 
1309b943567SDavid du Colombier 			/* rotate variables */
1319b943567SDavid du Colombier 			tmp = d;
1329b943567SDavid du Colombier 			d = c;
1339b943567SDavid du Colombier 			c = b;
1349b943567SDavid du Colombier 			b = a;
1359b943567SDavid du Colombier 			a = tmp;
1369b943567SDavid du Colombier 		}
1379b943567SDavid du Colombier 
1389b943567SDavid du Colombier 		s->state[0] += a;
1399b943567SDavid du Colombier 		s->state[1] += b;
1409b943567SDavid du Colombier 		s->state[2] += c;
1419b943567SDavid du Colombier 		s->state[3] += d;
1429b943567SDavid du Colombier 
1439b943567SDavid du Colombier 		s->len += 64;
1449b943567SDavid du Colombier 	}
1459b943567SDavid du Colombier }
1469b943567SDavid du Colombier 
1479b943567SDavid du Colombier MD4state*
md4(uchar * p,ulong len,uchar * digest,MD4state * s)1489b943567SDavid du Colombier md4(uchar *p, ulong len, uchar *digest, MD4state *s)
1499b943567SDavid du Colombier {
1509b943567SDavid du Colombier 	u32int x[16];
1519b943567SDavid du Colombier 	uchar buf[128];
1529b943567SDavid du Colombier 	int i;
1539b943567SDavid du Colombier 	uchar *e;
1549b943567SDavid du Colombier 
1559b943567SDavid du Colombier 	if(s == nil){
1569b943567SDavid du Colombier 		s = malloc(sizeof(*s));
1579b943567SDavid du Colombier 		if(s == nil)
1589b943567SDavid du Colombier 			return nil;
1599b943567SDavid du Colombier 		memset(s, 0, sizeof(*s));
1609b943567SDavid du Colombier 		s->malloced = 1;
1619b943567SDavid du Colombier 	}
1629b943567SDavid du Colombier 
1639b943567SDavid du Colombier 	if(s->seeded == 0){
1649b943567SDavid du Colombier 		/* seed the state, these constants would look nicer big-endian */
1659b943567SDavid du Colombier 		s->state[0] = 0x67452301;
1669b943567SDavid du Colombier 		s->state[1] = 0xefcdab89;
1679b943567SDavid du Colombier 		s->state[2] = 0x98badcfe;
1689b943567SDavid du Colombier 		s->state[3] = 0x10325476;
1699b943567SDavid du Colombier 		s->seeded = 1;
1709b943567SDavid du Colombier 	}
1719b943567SDavid du Colombier 
1729b943567SDavid du Colombier 	/* fill out the partial 64 byte block from previous calls */
1739b943567SDavid du Colombier 	if(s->blen){
1749b943567SDavid du Colombier 		i = 64 - s->blen;
1759b943567SDavid du Colombier 		if(len < i)
1769b943567SDavid du Colombier 			i = len;
1779b943567SDavid du Colombier 		memmove(s->buf + s->blen, p, i);
1789b943567SDavid du Colombier 		len -= i;
1799b943567SDavid du Colombier 		s->blen += i;
1809b943567SDavid du Colombier 		p += i;
1819b943567SDavid du Colombier 		if(s->blen == 64){
1829b943567SDavid du Colombier 			md4block(s->buf, s->blen, s);
1839b943567SDavid du Colombier 			s->blen = 0;
1849b943567SDavid du Colombier 		}
1859b943567SDavid du Colombier 	}
1869b943567SDavid du Colombier 
1879b943567SDavid du Colombier 	/* do 64 byte blocks */
1889b943567SDavid du Colombier 	i = len & ~0x3f;
1899b943567SDavid du Colombier 	if(i){
1909b943567SDavid du Colombier 		md4block(p, i, s);
1919b943567SDavid du Colombier 		len -= i;
1929b943567SDavid du Colombier 		p += i;
1939b943567SDavid du Colombier 	}
1949b943567SDavid du Colombier 
1959b943567SDavid du Colombier 	/* save the left overs if not last call */
1969b943567SDavid du Colombier 	if(digest == 0){
1979b943567SDavid du Colombier 		if(len){
1989b943567SDavid du Colombier 			memmove(s->buf, p, len);
1999b943567SDavid du Colombier 			s->blen += len;
2009b943567SDavid du Colombier 		}
2019b943567SDavid du Colombier 		return s;
2029b943567SDavid du Colombier 	}
2039b943567SDavid du Colombier 
2049b943567SDavid du Colombier 	/*
2059b943567SDavid du Colombier 	 *  this is the last time through, pad what's left with 0x80,
2069b943567SDavid du Colombier 	 *  0's, and the input count to create a multiple of 64 bytes
2079b943567SDavid du Colombier 	 */
2089b943567SDavid du Colombier 	if(s->blen){
2099b943567SDavid du Colombier 		p = s->buf;
2109b943567SDavid du Colombier 		len = s->blen;
2119b943567SDavid du Colombier 	} else {
2129b943567SDavid du Colombier 		memmove(buf, p, len);
2139b943567SDavid du Colombier 		p = buf;
2149b943567SDavid du Colombier 	}
2159b943567SDavid du Colombier 	s->len += len;
2169b943567SDavid du Colombier 	e = p + len;
2179b943567SDavid du Colombier 	if(len < 56)
2189b943567SDavid du Colombier 		i = 56 - len;
2199b943567SDavid du Colombier 	else
2209b943567SDavid du Colombier 		i = 120 - len;
2219b943567SDavid du Colombier 	memset(e, 0, i);
2229b943567SDavid du Colombier 	*e = 0x80;
2239b943567SDavid du Colombier 	len += i;
2249b943567SDavid du Colombier 
2259b943567SDavid du Colombier 	/* append the count */
2269b943567SDavid du Colombier 	x[0] = s->len<<3;
2279b943567SDavid du Colombier 	x[1] = s->len>>29;
2289b943567SDavid du Colombier 	encode(p+len, x, 8);
2299b943567SDavid du Colombier 
2309b943567SDavid du Colombier 	/* digest the last part */
2319b943567SDavid du Colombier 	md4block(p, len+8, s);
2329b943567SDavid du Colombier 
2339b943567SDavid du Colombier 	/* return result and free state */
2349b943567SDavid du Colombier 	encode(digest, s->state, MD4dlen);
2359b943567SDavid du Colombier 	if(s->malloced == 1)
2369b943567SDavid du Colombier 		free(s);
2379b943567SDavid du Colombier 	return nil;
2389b943567SDavid du Colombier }
2399b943567SDavid du Colombier 
2409b943567SDavid du Colombier /*
2419b943567SDavid du Colombier  *	encodes input (u32int) into output (uchar). Assumes len is
2429b943567SDavid du Colombier  *	a multiple of 4.
2439b943567SDavid du Colombier  */
2449b943567SDavid du Colombier static void
encode(uchar * output,u32int * input,ulong len)2459b943567SDavid du Colombier encode(uchar *output, u32int *input, ulong len)
2469b943567SDavid du Colombier {
2479b943567SDavid du Colombier 	u32int x;
2489b943567SDavid du Colombier 	uchar *e;
2499b943567SDavid du Colombier 
2509b943567SDavid du Colombier 	for(e = output + len; output < e;) {
2519b943567SDavid du Colombier 		x = *input++;
2529b943567SDavid du Colombier 		*output++ = x;
2539b943567SDavid du Colombier 		*output++ = x >> 8;
2549b943567SDavid du Colombier 		*output++ = x >> 16;
2559b943567SDavid du Colombier 		*output++ = x >> 24;
2569b943567SDavid du Colombier 	}
2579b943567SDavid du Colombier }
2589b943567SDavid du Colombier 
2599b943567SDavid du Colombier /*
2609b943567SDavid du Colombier  *	decodes input (uchar) into output (u32int). Assumes len is
2619b943567SDavid du Colombier  *	a multiple of 4.
2629b943567SDavid du Colombier  */
2639b943567SDavid du Colombier static void
decode(u32int * output,uchar * input,ulong len)2649b943567SDavid du Colombier decode(u32int *output, uchar *input, ulong len)
2659b943567SDavid du Colombier {
2669b943567SDavid du Colombier 	uchar *e;
2679b943567SDavid du Colombier 
2689b943567SDavid du Colombier 	for(e = input+len; input < e; input += 4)
2699b943567SDavid du Colombier 		*output++ = input[0] | (input[1] << 8) |
2709b943567SDavid du Colombier 			(input[2] << 16) | (input[3] << 24);
2719b943567SDavid du Colombier }
272