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