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