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