1 /* Transform module - bulk data transformation */
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. */
14 #include "unaligned.h"
16 /* Required key length in bytes */
17 #define REQUIRED_KEYLEN ((512+64+32)/8)
19 #ifdef WORDS_BIGENDIAN
20 static inline uint32_t byteswap(uint32_t a)
23 ((a&0x000000ff)<<24) |
33 struct transform_if ops;
34 uint32_t max_seq_skew;
37 struct transform_inst {
38 struct transform_inst_if ops;
39 struct keyInstance cryptkey;
40 struct keyInstance mackey;
51 static bool_t transform_setkey(void *sst, uint8_t *key, uint32_t keylen)
53 struct transform_inst *ti=sst;
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);
64 printf("Setting key to: ");
65 for (i=0; i<keylen; i++)
66 printf("%02x",key[i]);
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;
82 static void transform_delkey(void *sst)
84 struct transform_inst *ti=sst;
86 memset(&ti->cryptkey,0,sizeof(ti->cryptkey));
87 memset(&ti->mackey,0,sizeof(ti->mackey));
91 static uint32_t transform_forward(void *sst, struct buffer_if *buf,
94 struct transform_inst *ti=sst;
103 *errmsg="transform unkeyed";
107 /* Sequence number */
108 buf_prepend_uint32(buf,ti->sendseq);
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 */
118 padp=buf_append(buf,padlen);
119 memset(padp,padlen,padlen);
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.) */
128 serpent_encrypt(&ti->mackey,iv,macacc);
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)
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]);
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];
145 serpent_encrypt(&ti->mackey,macplain,macacc);
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]);
154 memcpy(buf_append(buf,16),macacc,16);
156 /* Serpent-CBC. We expand the ID as for CBCMAC, do the encryption,
157 and prepend the IV before increasing it. */
160 serpent_encrypt(&ti->cryptkey,iv,iv);
162 /* CBC: each block is XORed with the previous encrypted block (or the IV)
163 before being encrypted. */
165 for (n=(uint32_t *)buf->start; n<(uint32_t *)(buf->start+buf->size); n+=4)
167 #ifdef WORDS_BIGENDIAN
168 n[0]=byteswap(p[0]^n[0]);
169 n[1]=byteswap(p[1]^n[1]);
170 n[2]=byteswap(p[2]^n[2]);
171 n[3]=byteswap(p[3]^n[3]);
178 serpent_encrypt(&ti->cryptkey,n,n);
182 buf_prepend_uint32(buf,ti->cryptiv);
188 static uint32_t transform_reverse(void *sst, struct buffer_if *buf,
191 struct transform_inst *ti=sst;
195 uint32_t seqnum, skew;
198 uint32_t macplain[4];
201 uint32_t *macexpected;
204 *errmsg="transform unkeyed";
210 iv[0]=buf_unprepend_uint32(buf);
211 serpent_encrypt(&ti->cryptkey,iv,iv);
212 /* XXX assert bufsize is multiple of blocksize */
213 for (n=(uint32_t *)buf->start; n<(uint32_t *)(buf->start+buf->size); n+=4)
215 pct[0]=n[0]; pct[1]=n[1]; pct[2]=n[2]; pct[3]=n[3];
216 serpent_decrypt(&ti->cryptkey,n,n);
217 #ifdef WORDS_BIGENDIAN
218 n[0]=byteswap(iv[0]^n[0]);
219 n[1]=byteswap(iv[1]^n[1]);
220 n[2]=byteswap(iv[2]^n[2]);
221 n[3]=byteswap(iv[3]^n[3]);
228 iv[0]=pct[0]; iv[1]=pct[1]; iv[2]=pct[2]; iv[3]=pct[3];
232 macexpected=buf_unappend(buf,16);
235 serpent_encrypt(&ti->mackey,iv,macacc);
237 /* CBCMAC: encrypt in CBC mode. The MAC is the last encrypted
238 block encrypted once again. */
239 for (n=(uint32_t *)buf->start; n<(uint32_t *)(buf->start+buf->size); n+=4)
241 #ifdef WORDS_BIGENDIAN
242 macplain[0]=macacc[0]^byteswap(n[0]);
243 macplain[1]=macacc[1]^byteswap(n[1]);
244 macplain[2]=macacc[2]^byteswap(n[2]);
245 macplain[3]=macacc[3]^byteswap(n[3]);
247 macplain[0]=macacc[0]^n[0];
248 macplain[1]=macacc[1]^n[1];
249 macplain[2]=macacc[2]^n[2];
250 macplain[3]=macacc[3]^n[3];
252 serpent_encrypt(&ti->mackey,macplain,macacc);
254 serpent_encrypt(&ti->mackey,macacc,macacc);
255 #ifdef WORDS_BIGENDIAN
256 macacc[0]=byteswap(macacc[0]);
257 macacc[1]=byteswap(macacc[1]);
258 macacc[2]=byteswap(macacc[2]);
259 macacc[3]=byteswap(macacc[3]);
261 if (memcmp(macexpected,macacc,16)!=0) {
262 *errmsg="invalid MAC";
266 /* PKCS5, stolen from IWJ */
268 padp=buf_unappend(buf,1);
270 if (!padlen || (padlen > PKCS5_MASK+1)) {
271 *errmsg="pkcs5: invalid length";
275 padp=buf_unappend(buf,padlen-1);
276 for (i=0; i<padlen-1; i++) {
277 if (*++padp != padlen) {
278 *errmsg="pkcs5: corrupted padding";
283 /* Sequence number must be within max_skew of lastrecvseq; lastrecvseq
284 is only allowed to increase. */
285 seqnum=buf_unprepend_uint32(buf);
286 skew=seqnum-ti->lastrecvseq;
289 ti->lastrecvseq=seqnum;
290 } else if ((0-skew)<10) {
294 *errmsg="seqnum: too much skew";
301 static void transform_destroy(void *sst)
303 struct transform_inst *st=sst;
305 memset(st,0,sizeof(*st)); /* Destroy key material */
309 static struct transform_inst_if *transform_create(void *sst)
311 struct transform_inst *ti;
312 struct transform *st=sst;
314 ti=safe_malloc(sizeof(*ti),"transform_create");
318 ti->ops.setkey=transform_setkey;
319 ti->ops.delkey=transform_delkey;
320 ti->ops.forwards=transform_forward;
321 ti->ops.reverse=transform_reverse;
322 ti->ops.destroy=transform_destroy;
323 ti->max_skew=st->max_seq_skew;
329 static list_t *transform_apply(closure_t *self, struct cloc loc,
330 dict_t *context, list_t *args)
332 struct transform *st;
336 st=safe_malloc(sizeof(*st),"serpent");
337 st->cl.description="serpent-cbc256";
338 st->cl.type=CL_TRANSFORM;
340 st->cl.interface=&st->ops;
342 st->ops.max_start_pad=28; /* 4byte seqnum, 16byte pad, 4byte MACIV,
344 st->ops.max_end_pad=16; /* 16byte CBCMAC */
346 /* We need 256*2 bits for serpent keys, 32 bits for CBC-IV and 32 bits
347 for CBCMAC-IV, and 32 bits for init sequence number */
348 st->ops.keylen=REQUIRED_KEYLEN;
349 st->ops.create=transform_create;
351 /* First parameter must be a dict */
352 item=list_elem(args,0);
353 if (!item || item->type!=t_dict)
354 cfgfatal(loc,"userv-ipif","parameter must be a dictionary\n");
356 dict=item->data.dict;
357 st->max_seq_skew=dict_read_number(dict, "max-sequence-skew",
358 False, "serpent-cbc256", loc, 10);
360 return new_closure(&st->cl);
363 init_module transform_module;
364 void transform_module(dict_t *dict)
366 struct keyInstance k;
368 uint32_t plaintext[4];
369 uint32_t ciphertext[4];
371 /* Serpent self-test */
373 serpent_makekey(&k,256,data);
374 plaintext[0]=0x00000000;
375 plaintext[1]=0x00000001;
376 plaintext[2]=0x00000002;
377 plaintext[3]=0x00000003;
378 serpent_encrypt(&k,plaintext,ciphertext);
379 if (ciphertext[3]!=0x7ca73bb0 ||
380 ciphertext[2]!=0x83C31E69 ||
381 ciphertext[1]!=0xec52bd82 ||
382 ciphertext[0]!=0x27a46120) {
383 fatal("transform_module: serpent failed self-test (encrypt)\n");
385 serpent_decrypt(&k,ciphertext,plaintext);
386 if (plaintext[0]!=0 ||
390 fatal("transform_module: serpent failed self-test (decrypt)\n");
393 add_closure(dict,"serpent256-cbc",transform_apply);