Import release 0.1.9
[secnet] / transform.c
CommitLineData
2fe58dfd
SE
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"
59635212 14#include "unaligned.h"
2fe58dfd
SE
15
16/* Required key length in bytes */
17#define REQUIRED_KEYLEN ((512+64+32)/8)
18
59635212
SE
19#ifdef WORDS_BIGENDIAN
20static 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
2fe58dfd
SE
30struct transform {
31 closure_t cl;
32 uint32_t line;
33 struct transform_if ops;
34 uint32_t max_seq_skew;
35};
36
37struct 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
51static 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);
59635212
SE
73 ti->cryptiv=ntohl(*(uint32_t *)(key+64));
74 ti->maciv=ntohl(*(uint32_t *)(key+68));
75 ti->sendseq=ntohl(*(uint32_t *)(key+72));
2fe58dfd
SE
76 ti->lastrecvseq=ti->sendseq;
77 ti->keyed=True;
78
79 return True;
80}
81
82static 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
91static 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 */
59635212 108 buf_prepend_uint32(buf,ti->sendseq);
2fe58dfd
SE
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 {
59635212
SE
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
2fe58dfd
SE
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];
59635212 144#endif
2fe58dfd
SE
145 serpent_encrypt(&ti->mackey,macplain,macacc);
146 }
147 serpent_encrypt(&ti->mackey,macacc,macacc);
59635212
SE
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
2fe58dfd
SE
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;
8689b3a9
SE
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
2fe58dfd
SE
173 for (n=(uint32_t *)buf->start; n<(uint32_t *)(buf->start+buf->size); n+=4)
174 {
59635212 175#ifdef WORDS_BIGENDIAN
8689b3a9 176 /* Think of this as byteswap(p[x])^byteswap(n[x]) */
59635212
SE
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
2fe58dfd
SE
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];
59635212 186#endif
2fe58dfd 187 serpent_encrypt(&ti->cryptkey,n,n);
8689b3a9
SE
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
2fe58dfd
SE
194 p=n;
195 }
196
59635212 197 buf_prepend_uint32(buf,ti->cryptiv);
2fe58dfd 198 ti->cryptiv++;
2fe58dfd
SE
199 return 0;
200}
201
202static 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
8689b3a9 222
2fe58dfd
SE
223 /* CBC */
224 memset(iv,0,16);
59635212 225 iv[0]=buf_unprepend_uint32(buf);
8689b3a9
SE
226 /* Assert bufsize is multiple of blocksize */
227 if (buf->size&0xf) {
228 *errmsg="msg not multiple of cipher blocksize";
229 }
2fe58dfd 230 serpent_encrypt(&ti->cryptkey,iv,iv);
2fe58dfd
SE
231 for (n=(uint32_t *)buf->start; n<(uint32_t *)(buf->start+buf->size); n+=4)
232 {
8689b3a9
SE
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
2fe58dfd
SE
239 pct[0]=n[0]; pct[1]=n[1]; pct[2]=n[2]; pct[3]=n[3];
240 serpent_decrypt(&ti->cryptkey,n,n);
59635212
SE
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
2fe58dfd
SE
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];
59635212 251#endif
2fe58dfd
SE
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 {
59635212
SE
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
2fe58dfd
SE
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];
59635212 275#endif
2fe58dfd
SE
276 serpent_encrypt(&ti->mackey,macplain,macacc);
277 }
278 serpent_encrypt(&ti->mackey,macacc,macacc);
59635212
SE
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
2fe58dfd
SE
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. */
59635212 309 seqnum=buf_unprepend_uint32(buf);
2fe58dfd 310 skew=seqnum-ti->lastrecvseq;
c6f79b17 311 if (skew<0x8fffffff) {
2fe58dfd
SE
312 /* Ok */
313 ti->lastrecvseq=seqnum;
c6f79b17 314 } else if ((0-skew)<ti->max_skew) {
2fe58dfd
SE
315 /* Ok */
316 } else {
317 /* Too much skew */
318 *errmsg="seqnum: too much skew";
319 return 1;
320 }
321
322 return 0;
323}
324
325static 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
333static 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
353static 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
387init_module transform_module;
388void 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}