chiark / gitweb /
Import release 0.1.8
[secnet.git] / transform.c
1 /* Transform module - bulk data transformation */
2
3 /* For now it's hard-coded to do sequence
4    number/pkcs5/serpent-cbcmac/serpent with a 256 bit key for each
5    instance of serpent. We also require key material for the IVs for
6    cbcmac and cbc. Hack: we're not using full 128-bit IVs, we're just
7    using 32 bits and encrypting to get the full IV to save space in
8    the packets sent over the wire. */
9
10 #include <stdio.h>
11 #include "secnet.h"
12 #include "util.h"
13 #include "serpent.h"
14 #include "unaligned.h"
15
16 /* Required key length in bytes */
17 #define REQUIRED_KEYLEN ((512+64+32)/8)
18
19 #ifdef WORDS_BIGENDIAN
20 static inline uint32_t byteswap(uint32_t a)
21 {
22     return
23         ((a&0x000000ff)<<24) |
24         ((a&0x0000ff00)<<8) |
25         ((a&0x00ff0000)>>8) |
26         ((a&0xff000000)>>24);
27 }
28 #endif
29
30 struct transform {
31     closure_t cl;
32     uint32_t line;
33     struct transform_if ops;
34     uint32_t max_seq_skew;
35 };
36
37 struct transform_inst {
38     struct transform_inst_if ops;
39     struct keyInstance cryptkey;
40     struct keyInstance mackey;
41     uint32_t cryptiv;
42     uint32_t maciv;
43     uint32_t sendseq;
44     uint32_t lastrecvseq;
45     uint32_t max_skew;
46     bool_t keyed;
47 };
48
49 #define PKCS5_MASK 15
50
51 static bool_t transform_setkey(void *sst, uint8_t *key, uint32_t keylen)
52 {
53     struct transform_inst *ti=sst;
54
55     if (keylen<REQUIRED_KEYLEN) {
56         Message(M_ERROR,"transform_create: insufficient key material supplied "
57                 "(need %d bytes, got %d)\n",REQUIRED_KEYLEN,keylen);
58         return False;
59     }
60
61 #if 0
62     {
63         int i;
64         printf("Setting key to: ");
65         for (i=0; i<keylen; i++)
66             printf("%02x",key[i]);
67         printf("\n");
68     }
69 #endif /* 0 */
70
71     serpent_makekey(&ti->cryptkey,256,key);
72     serpent_makekey(&ti->mackey,256,key+32);
73     ti->cryptiv=ntohl(*(uint32_t *)(key+64));
74     ti->maciv=ntohl(*(uint32_t *)(key+68));
75     ti->sendseq=ntohl(*(uint32_t *)(key+72));
76     ti->lastrecvseq=ti->sendseq;
77     ti->keyed=True;
78
79     return True;
80 }
81
82 static void transform_delkey(void *sst)
83 {
84     struct transform_inst *ti=sst;
85
86     memset(&ti->cryptkey,0,sizeof(ti->cryptkey));
87     memset(&ti->mackey,0,sizeof(ti->mackey));
88     ti->keyed=False;
89 }
90
91 static uint32_t transform_forward(void *sst, struct buffer_if *buf,
92                                   char **errmsg)
93 {
94     struct transform_inst *ti=sst;
95     uint8_t *padp;
96     int padlen;
97     uint32_t iv[4];
98     uint32_t macplain[4];
99     uint32_t macacc[4];
100     uint32_t *n, *p;
101
102     if (!ti->keyed) {
103         *errmsg="transform unkeyed";
104         return 1;
105     }
106
107     /* Sequence number */
108     buf_prepend_uint32(buf,ti->sendseq);
109     ti->sendseq++;
110
111     /* PKCS5, stolen from IWJ */
112                                     /* eg with blocksize=4 mask=3 mask+2=5   */
113                                     /* msgsize    20    21    22    23   24  */
114     padlen= PKCS5_MASK-buf->size;   /*           -17   -18   -19   -16  -17  */
115     padlen &= PKCS5_MASK;           /*             3     2     1     0    3  */
116     padlen++;                       /*             4     3     2     1    4  */
117
118     padp=buf_append(buf,padlen);
119     memset(padp,padlen,padlen);
120
121     /* Serpent-CBCMAC. We expand the IV from 32-bit to 128-bit using
122        one encryption. Then we do the MAC and append the result. We don't
123        bother sending the IV - it's the same each time. (If we wanted to send
124        it we've have to add 16 bytes to each message, not 4, so that the
125        message stays a multiple of 16 bytes long.) */
126     memset(iv,0,16);
127     iv[0]=ti->maciv;
128     serpent_encrypt(&ti->mackey,iv,macacc);
129
130     /* CBCMAC: encrypt in CBC mode. The MAC is the last encrypted
131        block encrypted once again. */
132     for (n=(uint32_t *)buf->start; n<(uint32_t *)(buf->start+buf->size); n+=4)
133     {
134 #ifdef WORDS_BIGENDIAN
135         macplain[0]=macacc[0]^byteswap(n[0]);
136         macplain[1]=macacc[1]^byteswap(n[1]);
137         macplain[2]=macacc[2]^byteswap(n[2]);
138         macplain[3]=macacc[3]^byteswap(n[3]);
139 #else
140         macplain[0]=macacc[0]^n[0];
141         macplain[1]=macacc[1]^n[1];
142         macplain[2]=macacc[2]^n[2];
143         macplain[3]=macacc[3]^n[3];
144 #endif
145         serpent_encrypt(&ti->mackey,macplain,macacc);
146     }
147     serpent_encrypt(&ti->mackey,macacc,macacc);
148 #ifdef WORDS_BIGENDIAN
149     macacc[0]=byteswap(macacc[0]);
150     macacc[1]=byteswap(macacc[1]);
151     macacc[2]=byteswap(macacc[2]);
152     macacc[3]=byteswap(macacc[3]);
153 #endif
154     memcpy(buf_append(buf,16),macacc,16);
155
156     /* Serpent-CBC. We expand the ID as for CBCMAC, do the encryption,
157        and prepend the IV before increasing it. */
158     memset(iv,0,16);
159     iv[0]=ti->cryptiv;
160     serpent_encrypt(&ti->cryptkey,iv,iv);
161
162     /* CBC: each block is XORed with the previous encrypted block (or the IV)
163        before being encrypted. */
164     p=iv;
165 #ifdef WORDS_BIGENDIAN
166     /* This counters the byteswap() in the first half of the loop, which in
167        turn counters the byteswap() in the second half of the loop. Ick. */
168     iv[0]=byteswap(iv[0]);
169     iv[1]=byteswap(iv[1]);
170     iv[2]=byteswap(iv[2]);
171     iv[3]=byteswap(iv[3]);
172 #endif
173     for (n=(uint32_t *)buf->start; n<(uint32_t *)(buf->start+buf->size); n+=4)
174     {
175 #ifdef WORDS_BIGENDIAN
176         /* Think of this as byteswap(p[x])^byteswap(n[x]) */
177         n[0]=byteswap(p[0]^n[0]);
178         n[1]=byteswap(p[1]^n[1]);
179         n[2]=byteswap(p[2]^n[2]);
180         n[3]=byteswap(p[3]^n[3]);
181 #else
182         n[0]=p[0]^n[0];
183         n[1]=p[1]^n[1];
184         n[2]=p[2]^n[2];
185         n[3]=p[3]^n[3];
186 #endif
187         serpent_encrypt(&ti->cryptkey,n,n);
188 #ifdef WORDS_BIGENDIAN
189         n[0]=byteswap(n[0]);
190         n[1]=byteswap(n[1]);
191         n[2]=byteswap(n[2]);
192         n[3]=byteswap(n[3]);
193 #endif
194         p=n;
195     }
196
197     buf_prepend_uint32(buf,ti->cryptiv);
198     ti->cryptiv++;
199     return 0;
200 }
201
202 static uint32_t transform_reverse(void *sst, struct buffer_if *buf,
203                                   char **errmsg)
204 {
205     struct transform_inst *ti=sst;
206     uint8_t *padp;
207     unsigned padlen;
208     int i;
209     uint32_t seqnum, skew;
210     uint32_t iv[4];
211     uint32_t pct[4];
212     uint32_t macplain[4];
213     uint32_t macacc[4];
214     uint32_t *n;
215     uint32_t *macexpected;
216
217     if (!ti->keyed) {
218         *errmsg="transform unkeyed";
219         return 1;
220     }
221
222
223     /* CBC */
224     memset(iv,0,16);
225     iv[0]=buf_unprepend_uint32(buf);
226     /* Assert bufsize is multiple of blocksize */
227     if (buf->size&0xf) {
228         *errmsg="msg not multiple of cipher blocksize";
229     }
230     serpent_encrypt(&ti->cryptkey,iv,iv);
231     for (n=(uint32_t *)buf->start; n<(uint32_t *)(buf->start+buf->size); n+=4)
232     {
233 #ifdef WORDS_BIGENDIAN
234         n[0]=byteswap(n[0]);
235         n[1]=byteswap(n[1]);
236         n[2]=byteswap(n[2]);
237         n[3]=byteswap(n[3]);
238 #endif
239         pct[0]=n[0]; pct[1]=n[1]; pct[2]=n[2]; pct[3]=n[3];
240         serpent_decrypt(&ti->cryptkey,n,n);
241 #ifdef WORDS_BIGENDIAN
242         n[0]=byteswap(iv[0]^n[0]);
243         n[1]=byteswap(iv[1]^n[1]);
244         n[2]=byteswap(iv[2]^n[2]);
245         n[3]=byteswap(iv[3]^n[3]);
246 #else
247         n[0]=iv[0]^n[0];
248         n[1]=iv[1]^n[1];
249         n[2]=iv[2]^n[2];
250         n[3]=iv[3]^n[3];
251 #endif
252         iv[0]=pct[0]; iv[1]=pct[1]; iv[2]=pct[2]; iv[3]=pct[3];
253     }
254
255     /* CBCMAC */
256     macexpected=buf_unappend(buf,16);
257     memset(iv,0,16);
258     iv[0]=ti->maciv;
259     serpent_encrypt(&ti->mackey,iv,macacc);
260
261     /* CBCMAC: encrypt in CBC mode. The MAC is the last encrypted
262        block encrypted once again. */
263     for (n=(uint32_t *)buf->start; n<(uint32_t *)(buf->start+buf->size); n+=4)
264     {
265 #ifdef WORDS_BIGENDIAN
266         macplain[0]=macacc[0]^byteswap(n[0]);
267         macplain[1]=macacc[1]^byteswap(n[1]);
268         macplain[2]=macacc[2]^byteswap(n[2]);
269         macplain[3]=macacc[3]^byteswap(n[3]);
270 #else
271         macplain[0]=macacc[0]^n[0];
272         macplain[1]=macacc[1]^n[1];
273         macplain[2]=macacc[2]^n[2];
274         macplain[3]=macacc[3]^n[3];
275 #endif
276         serpent_encrypt(&ti->mackey,macplain,macacc);
277     }
278     serpent_encrypt(&ti->mackey,macacc,macacc);
279 #ifdef WORDS_BIGENDIAN
280     macacc[0]=byteswap(macacc[0]);
281     macacc[1]=byteswap(macacc[1]);
282     macacc[2]=byteswap(macacc[2]);
283     macacc[3]=byteswap(macacc[3]);
284 #endif
285     if (memcmp(macexpected,macacc,16)!=0) {
286         *errmsg="invalid MAC";
287         return 1;
288     }
289
290     /* PKCS5, stolen from IWJ */
291
292     padp=buf_unappend(buf,1);
293     padlen=*padp;
294     if (!padlen || (padlen > PKCS5_MASK+1)) {
295         *errmsg="pkcs5: invalid length";
296         return 1;
297     }
298
299     padp=buf_unappend(buf,padlen-1);
300     for (i=0; i<padlen-1; i++) {
301         if (*++padp != padlen) {
302             *errmsg="pkcs5: corrupted padding";
303             return 1;
304         }
305     }
306
307     /* Sequence number must be within max_skew of lastrecvseq; lastrecvseq
308        is only allowed to increase. */
309     seqnum=buf_unprepend_uint32(buf);
310     skew=seqnum-ti->lastrecvseq;
311     if (skew<0x8fffffff) {
312         /* Ok */
313         ti->lastrecvseq=seqnum;
314     } else if ((0-skew)<ti->max_skew) {
315         /* Ok */
316     } else {
317         /* Too much skew */
318         *errmsg="seqnum: too much skew";
319         return 1;
320     }
321     
322     return 0;
323 }
324
325 static void transform_destroy(void *sst)
326 {
327     struct transform_inst *st=sst;
328
329     memset(st,0,sizeof(*st)); /* Destroy key material */
330     free(st);
331 }
332
333 static struct transform_inst_if *transform_create(void *sst)
334 {
335     struct transform_inst *ti;
336     struct transform *st=sst;
337
338     ti=safe_malloc(sizeof(*ti),"transform_create");
339     /* mlock XXX */
340
341     ti->ops.st=ti;
342     ti->ops.setkey=transform_setkey;
343     ti->ops.delkey=transform_delkey;
344     ti->ops.forwards=transform_forward;
345     ti->ops.reverse=transform_reverse;
346     ti->ops.destroy=transform_destroy;
347     ti->max_skew=st->max_seq_skew;
348     ti->keyed=False;
349
350     return &ti->ops;
351 }
352
353 static list_t *transform_apply(closure_t *self, struct cloc loc,
354                                dict_t *context, list_t *args)
355 {
356     struct transform *st;
357     item_t *item;
358     dict_t *dict;
359
360     st=safe_malloc(sizeof(*st),"serpent");
361     st->cl.description="serpent-cbc256";
362     st->cl.type=CL_TRANSFORM;
363     st->cl.apply=NULL;
364     st->cl.interface=&st->ops;
365     st->ops.st=st;
366     st->ops.max_start_pad=28; /* 4byte seqnum, 16byte pad, 4byte MACIV,
367                                  4byte IV */
368     st->ops.max_end_pad=16; /* 16byte CBCMAC */
369
370     /* We need 256*2 bits for serpent keys, 32 bits for CBC-IV and 32 bits
371        for CBCMAC-IV, and 32 bits for init sequence number */
372     st->ops.keylen=REQUIRED_KEYLEN;
373     st->ops.create=transform_create;
374
375     /* First parameter must be a dict */
376     item=list_elem(args,0);
377     if (!item || item->type!=t_dict)
378         cfgfatal(loc,"userv-ipif","parameter must be a dictionary\n");
379     
380     dict=item->data.dict;
381     st->max_seq_skew=dict_read_number(dict, "max-sequence-skew",
382                                       False, "serpent-cbc256", loc, 10);
383
384     return new_closure(&st->cl);
385 }
386
387 init_module transform_module;
388 void transform_module(dict_t *dict)
389 {
390     struct keyInstance k;
391     uint8_t data[32];
392     uint32_t plaintext[4];
393     uint32_t ciphertext[4];
394
395     /* Serpent self-test */
396     memset(data,0,32);
397     serpent_makekey(&k,256,data);
398     plaintext[0]=0x00000000;
399     plaintext[1]=0x00000001;
400     plaintext[2]=0x00000002;
401     plaintext[3]=0x00000003;
402     serpent_encrypt(&k,plaintext,ciphertext);
403     if (ciphertext[3]!=0x7ca73bb0 ||
404         ciphertext[2]!=0x83C31E69 ||
405         ciphertext[1]!=0xec52bd82 ||
406         ciphertext[0]!=0x27a46120) {
407         fatal("transform_module: serpent failed self-test (encrypt)\n");
408     }
409     serpent_decrypt(&k,ciphertext,plaintext);
410     if (plaintext[0]!=0 ||
411         plaintext[1]!=1 ||
412         plaintext[2]!=2 ||
413         plaintext[3]!=3) {
414         fatal("transform_module: serpent failed self-test (decrypt)\n");
415     }
416
417     add_closure(dict,"serpent256-cbc",transform_apply);
418 }