|  | #include "os.h" | 
|  | #include <libsec.h> | 
|  |  | 
|  | /* | 
|  | *  This MD4 is implemented from the description in Stinson's Cryptography, | 
|  | *  theory and practice. -- presotto | 
|  | */ | 
|  |  | 
|  | /* | 
|  | *	Rotate ammounts used in the algorithm | 
|  | */ | 
|  | enum | 
|  | { | 
|  | S11=	3, | 
|  | S12=	7, | 
|  | S13=	11, | 
|  | S14=	19, | 
|  |  | 
|  | S21=	3, | 
|  | S22=	5, | 
|  | S23=	9, | 
|  | S24=	13, | 
|  |  | 
|  | S31=	3, | 
|  | S32=	9, | 
|  | S33=	11, | 
|  | S34=	15 | 
|  | }; | 
|  |  | 
|  | typedef struct MD4Table MD4Table; | 
|  | struct MD4Table | 
|  | { | 
|  | uchar	x;	/* index into data block */ | 
|  | uchar	rot;	/* amount to rotate left by */ | 
|  | }; | 
|  |  | 
|  | static MD4Table tab[] = | 
|  | { | 
|  | /* round 1 */ | 
|  | /*[0]*/	{ 0,	S11}, | 
|  | { 1,	S12}, | 
|  | { 2,	S13}, | 
|  | { 3,	S14}, | 
|  | { 4,	S11}, | 
|  | { 5,	S12}, | 
|  | { 6,	S13}, | 
|  | { 7,	S14}, | 
|  | { 8,	S11}, | 
|  | { 9,	S12}, | 
|  | { 10,	S13}, | 
|  | { 11,	S14}, | 
|  | { 12,	S11}, | 
|  | { 13,	S12}, | 
|  | { 14,	S13}, | 
|  | { 15,	S14}, | 
|  |  | 
|  | /* round 2 */ | 
|  | /*[16]*/{ 0,	S21}, | 
|  | { 4,	S22}, | 
|  | { 8,	S23}, | 
|  | { 12,	S24}, | 
|  | { 1,	S21}, | 
|  | { 5,	S22}, | 
|  | { 9,	S23}, | 
|  | { 13,	S24}, | 
|  | { 2,	S21}, | 
|  | { 6,	S22}, | 
|  | { 10,	S23}, | 
|  | { 14,	S24}, | 
|  | { 3,	S21}, | 
|  | { 7,	S22}, | 
|  | { 11,	S23}, | 
|  | { 15,	S24}, | 
|  |  | 
|  | /* round 3 */ | 
|  | /*[32]*/{ 0,	S31}, | 
|  | { 8,	S32}, | 
|  | { 4,	S33}, | 
|  | { 12,	S34}, | 
|  | { 2,	S31}, | 
|  | { 10,	S32}, | 
|  | { 6,	S33}, | 
|  | { 14,	S34}, | 
|  | { 1,	S31}, | 
|  | { 9,	S32}, | 
|  | { 5,	S33}, | 
|  | { 13,	S34}, | 
|  | { 3,	S31}, | 
|  | { 11,	S32}, | 
|  | { 7,	S33}, | 
|  | { 15,	S34}, | 
|  | }; | 
|  |  | 
|  | static void encode(uchar*, u32int*, ulong); | 
|  | static void decode(u32int*, uchar*, ulong); | 
|  |  | 
|  | static void | 
|  | md4block(uchar *p, ulong len, MD4state *s) | 
|  | { | 
|  | int i; | 
|  | u32int a, b, c, d, tmp; | 
|  | MD4Table *t; | 
|  | uchar *end; | 
|  | u32int x[16]; | 
|  |  | 
|  | for(end = p+len; p < end; p += 64){ | 
|  | a = s->state[0]; | 
|  | b = s->state[1]; | 
|  | c = s->state[2]; | 
|  | d = s->state[3]; | 
|  |  | 
|  | decode(x, p, 64); | 
|  |  | 
|  | for(i = 0; i < 48; i++){ | 
|  | t = tab + i; | 
|  | switch(i>>4){ | 
|  | case 0: | 
|  | a += (b & c) | (~b & d); | 
|  | break; | 
|  | case 1: | 
|  | a += ((b & c) | (b & d) | (c & d)) + 0x5A827999; | 
|  | break; | 
|  | case 2: | 
|  | a += (b ^ c ^ d) + 0x6ED9EBA1; | 
|  | break; | 
|  | } | 
|  | a += x[t->x]; | 
|  | a = (a << t->rot) | (a >> (32 - t->rot)); | 
|  |  | 
|  | /* rotate variables */ | 
|  | tmp = d; | 
|  | d = c; | 
|  | c = b; | 
|  | b = a; | 
|  | a = tmp; | 
|  | } | 
|  |  | 
|  | s->state[0] += a; | 
|  | s->state[1] += b; | 
|  | s->state[2] += c; | 
|  | s->state[3] += d; | 
|  |  | 
|  | s->len += 64; | 
|  | } | 
|  | } | 
|  |  | 
|  | MD4state* | 
|  | md4(uchar *p, ulong len, uchar *digest, MD4state *s) | 
|  | { | 
|  | u32int x[16]; | 
|  | uchar buf[128]; | 
|  | int i; | 
|  | uchar *e; | 
|  |  | 
|  | if(s == nil){ | 
|  | s = malloc(sizeof(*s)); | 
|  | if(s == nil) | 
|  | return nil; | 
|  | memset(s, 0, sizeof(*s)); | 
|  | s->malloced = 1; | 
|  | } | 
|  |  | 
|  | if(s->seeded == 0){ | 
|  | /* seed the state, these constants would look nicer big-endian */ | 
|  | s->state[0] = 0x67452301; | 
|  | s->state[1] = 0xefcdab89; | 
|  | s->state[2] = 0x98badcfe; | 
|  | s->state[3] = 0x10325476; | 
|  | s->seeded = 1; | 
|  | } | 
|  |  | 
|  | /* fill out the partial 64 byte block from previous calls */ | 
|  | if(s->blen){ | 
|  | i = 64 - s->blen; | 
|  | if(len < i) | 
|  | i = len; | 
|  | memmove(s->buf + s->blen, p, i); | 
|  | len -= i; | 
|  | s->blen += i; | 
|  | p += i; | 
|  | if(s->blen == 64){ | 
|  | md4block(s->buf, s->blen, s); | 
|  | s->blen = 0; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* do 64 byte blocks */ | 
|  | i = len & ~0x3f; | 
|  | if(i){ | 
|  | md4block(p, i, s); | 
|  | len -= i; | 
|  | p += i; | 
|  | } | 
|  |  | 
|  | /* save the left overs if not last call */ | 
|  | if(digest == 0){ | 
|  | if(len){ | 
|  | memmove(s->buf, p, len); | 
|  | s->blen += len; | 
|  | } | 
|  | return s; | 
|  | } | 
|  |  | 
|  | /* | 
|  | *  this is the last time through, pad what's left with 0x80, | 
|  | *  0's, and the input count to create a multiple of 64 bytes | 
|  | */ | 
|  | if(s->blen){ | 
|  | p = s->buf; | 
|  | len = s->blen; | 
|  | } else { | 
|  | memmove(buf, p, len); | 
|  | p = buf; | 
|  | } | 
|  | s->len += len; | 
|  | e = p + len; | 
|  | if(len < 56) | 
|  | i = 56 - len; | 
|  | else | 
|  | i = 120 - len; | 
|  | memset(e, 0, i); | 
|  | *e = 0x80; | 
|  | len += i; | 
|  |  | 
|  | /* append the count */ | 
|  | x[0] = s->len<<3; | 
|  | x[1] = s->len>>29; | 
|  | encode(p+len, x, 8); | 
|  |  | 
|  | /* digest the last part */ | 
|  | md4block(p, len+8, s); | 
|  |  | 
|  | /* return result and free state */ | 
|  | encode(digest, s->state, MD4dlen); | 
|  | if(s->malloced == 1) | 
|  | free(s); | 
|  | return nil; | 
|  | } | 
|  |  | 
|  | /* | 
|  | *	encodes input (u32int) into output (uchar). Assumes len is | 
|  | *	a multiple of 4. | 
|  | */ | 
|  | static void | 
|  | encode(uchar *output, u32int *input, ulong len) | 
|  | { | 
|  | u32int x; | 
|  | uchar *e; | 
|  |  | 
|  | for(e = output + len; output < e;) { | 
|  | x = *input++; | 
|  | *output++ = x; | 
|  | *output++ = x >> 8; | 
|  | *output++ = x >> 16; | 
|  | *output++ = x >> 24; | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | *	decodes input (uchar) into output (u32int). Assumes len is | 
|  | *	a multiple of 4. | 
|  | */ | 
|  | static void | 
|  | decode(u32int *output, uchar *input, ulong len) | 
|  | { | 
|  | uchar *e; | 
|  |  | 
|  | for(e = input+len; input < e; input += 4) | 
|  | *output++ = input[0] | (input[1] << 8) | | 
|  | (input[2] << 16) | (input[3] << 24); | 
|  | } |