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. */
15 #include "unaligned.h"
17 /* Required key length in bytes */
18 #define REQUIRED_KEYLEN ((512+64+32)/8)
20 #ifdef WORDS_BIGENDIAN
21 static inline uint32_t byteswap(uint32_t a
)
24 ((a
&0x000000ff)<<24) |
34 struct transform_if ops
;
35 uint32_t max_seq_skew
;
38 struct transform_inst
{
39 struct transform_inst_if ops
;
40 struct keyInstance cryptkey
;
41 struct keyInstance mackey
;
52 static bool_t
transform_setkey(void *sst
, uint8_t *key
, uint32_t keylen
)
54 struct transform_inst
*ti
=sst
;
56 if (keylen
<REQUIRED_KEYLEN
) {
57 Message(M_ERR
,"transform_create: insufficient key material supplied "
58 "(need %d bytes, got %d)\n",REQUIRED_KEYLEN
,keylen
);
65 printf("Setting key to: ");
66 for (i
=0; i
<keylen
; i
++)
67 printf("%02x",key
[i
]);
72 serpent_makekey(&ti
->cryptkey
,256,key
);
73 serpent_makekey(&ti
->mackey
,256,key
+32);
74 ti
->cryptiv
=ntohl(*(uint32_t *)(key
+64));
75 ti
->maciv
=ntohl(*(uint32_t *)(key
+68));
76 ti
->sendseq
=ntohl(*(uint32_t *)(key
+72));
77 ti
->lastrecvseq
=ti
->sendseq
;
83 static void transform_delkey(void *sst
)
85 struct transform_inst
*ti
=sst
;
87 memset(&ti
->cryptkey
,0,sizeof(ti
->cryptkey
));
88 memset(&ti
->mackey
,0,sizeof(ti
->mackey
));
92 static uint32_t transform_forward(void *sst
, struct buffer_if
*buf
,
95 struct transform_inst
*ti
=sst
;
104 *errmsg
="transform unkeyed";
108 /* Sequence number */
109 buf_prepend_uint32(buf
,ti
->sendseq
);
112 /* PKCS5, stolen from IWJ */
113 /* eg with blocksize=4 mask=3 mask+2=5 */
114 /* msgsize 20 21 22 23 24 */
115 padlen
= PKCS5_MASK
-buf
->size
; /* -17 -18 -19 -16 -17 */
116 padlen
&= PKCS5_MASK
; /* 3 2 1 0 3 */
117 padlen
++; /* 4 3 2 1 4 */
119 padp
=buf_append(buf
,padlen
);
120 memset(padp
,padlen
,padlen
);
122 /* Serpent-CBCMAC. We expand the IV from 32-bit to 128-bit using
123 one encryption. Then we do the MAC and append the result. We don't
124 bother sending the IV - it's the same each time. (If we wanted to send
125 it we've have to add 16 bytes to each message, not 4, so that the
126 message stays a multiple of 16 bytes long.) */
129 serpent_encrypt(&ti
->mackey
,iv
,macacc
);
131 /* CBCMAC: encrypt in CBC mode. The MAC is the last encrypted
132 block encrypted once again. */
133 for (n
=(uint32_t *)buf
->start
; n
<(uint32_t *)(buf
->start
+buf
->size
); n
+=4)
135 #ifdef WORDS_BIGENDIAN
136 macplain
[0]=macacc
[0]^byteswap(n
[0]);
137 macplain
[1]=macacc
[1]^byteswap(n
[1]);
138 macplain
[2]=macacc
[2]^byteswap(n
[2]);
139 macplain
[3]=macacc
[3]^byteswap(n
[3]);
141 macplain
[0]=macacc
[0]^n
[0];
142 macplain
[1]=macacc
[1]^n
[1];
143 macplain
[2]=macacc
[2]^n
[2];
144 macplain
[3]=macacc
[3]^n
[3];
146 serpent_encrypt(&ti
->mackey
,macplain
,macacc
);
148 serpent_encrypt(&ti
->mackey
,macacc
,macacc
);
149 #ifdef WORDS_BIGENDIAN
150 macacc
[0]=byteswap(macacc
[0]);
151 macacc
[1]=byteswap(macacc
[1]);
152 macacc
[2]=byteswap(macacc
[2]);
153 macacc
[3]=byteswap(macacc
[3]);
155 memcpy(buf_append(buf
,16),macacc
,16);
157 /* Serpent-CBC. We expand the ID as for CBCMAC, do the encryption,
158 and prepend the IV before increasing it. */
161 serpent_encrypt(&ti
->cryptkey
,iv
,iv
);
163 /* CBC: each block is XORed with the previous encrypted block (or the IV)
164 before being encrypted. */
166 #ifdef WORDS_BIGENDIAN
167 /* This counters the byteswap() in the first half of the loop, which in
168 turn counters the byteswap() in the second half of the loop. Ick. */
169 iv
[0]=byteswap(iv
[0]);
170 iv
[1]=byteswap(iv
[1]);
171 iv
[2]=byteswap(iv
[2]);
172 iv
[3]=byteswap(iv
[3]);
174 for (n
=(uint32_t *)buf
->start
; n
<(uint32_t *)(buf
->start
+buf
->size
); n
+=4)
176 #ifdef WORDS_BIGENDIAN
177 /* Think of this as byteswap(p[x])^byteswap(n[x]) */
178 n
[0]=byteswap(p
[0]^n
[0]);
179 n
[1]=byteswap(p
[1]^n
[1]);
180 n
[2]=byteswap(p
[2]^n
[2]);
181 n
[3]=byteswap(p
[3]^n
[3]);
188 serpent_encrypt(&ti
->cryptkey
,n
,n
);
189 #ifdef WORDS_BIGENDIAN
198 buf_prepend_uint32(buf
,ti
->cryptiv
);
203 static uint32_t transform_reverse(void *sst
, struct buffer_if
*buf
,
206 struct transform_inst
*ti
=sst
;
210 uint32_t seqnum
, skew
;
213 uint32_t macplain
[4];
216 uint32_t *macexpected
;
219 *errmsg
="transform unkeyed";
226 iv
[0]=buf_unprepend_uint32(buf
);
227 /* Assert bufsize is multiple of blocksize */
229 *errmsg
="msg not multiple of cipher blocksize";
231 serpent_encrypt(&ti
->cryptkey
,iv
,iv
);
232 for (n
=(uint32_t *)buf
->start
; n
<(uint32_t *)(buf
->start
+buf
->size
); n
+=4)
234 #ifdef WORDS_BIGENDIAN
240 pct
[0]=n
[0]; pct
[1]=n
[1]; pct
[2]=n
[2]; pct
[3]=n
[3];
241 serpent_decrypt(&ti
->cryptkey
,n
,n
);
242 #ifdef WORDS_BIGENDIAN
243 n
[0]=byteswap(iv
[0]^n
[0]);
244 n
[1]=byteswap(iv
[1]^n
[1]);
245 n
[2]=byteswap(iv
[2]^n
[2]);
246 n
[3]=byteswap(iv
[3]^n
[3]);
253 iv
[0]=pct
[0]; iv
[1]=pct
[1]; iv
[2]=pct
[2]; iv
[3]=pct
[3];
257 macexpected
=buf_unappend(buf
,16);
260 serpent_encrypt(&ti
->mackey
,iv
,macacc
);
262 /* CBCMAC: encrypt in CBC mode. The MAC is the last encrypted
263 block encrypted once again. */
264 for (n
=(uint32_t *)buf
->start
; n
<(uint32_t *)(buf
->start
+buf
->size
); n
+=4)
266 #ifdef WORDS_BIGENDIAN
267 macplain
[0]=macacc
[0]^byteswap(n
[0]);
268 macplain
[1]=macacc
[1]^byteswap(n
[1]);
269 macplain
[2]=macacc
[2]^byteswap(n
[2]);
270 macplain
[3]=macacc
[3]^byteswap(n
[3]);
272 macplain
[0]=macacc
[0]^n
[0];
273 macplain
[1]=macacc
[1]^n
[1];
274 macplain
[2]=macacc
[2]^n
[2];
275 macplain
[3]=macacc
[3]^n
[3];
277 serpent_encrypt(&ti
->mackey
,macplain
,macacc
);
279 serpent_encrypt(&ti
->mackey
,macacc
,macacc
);
280 #ifdef WORDS_BIGENDIAN
281 macacc
[0]=byteswap(macacc
[0]);
282 macacc
[1]=byteswap(macacc
[1]);
283 macacc
[2]=byteswap(macacc
[2]);
284 macacc
[3]=byteswap(macacc
[3]);
286 if (memcmp(macexpected
,macacc
,16)!=0) {
287 *errmsg
="invalid MAC";
291 /* PKCS5, stolen from IWJ */
293 padp
=buf_unappend(buf
,1);
295 if (!padlen
|| (padlen
> PKCS5_MASK
+1)) {
296 *errmsg
="pkcs5: invalid length";
300 padp
=buf_unappend(buf
,padlen
-1);
301 for (i
=0; i
<padlen
-1; i
++) {
302 if (*++padp
!= padlen
) {
303 *errmsg
="pkcs5: corrupted padding";
308 /* Sequence number must be within max_skew of lastrecvseq; lastrecvseq
309 is only allowed to increase. */
310 seqnum
=buf_unprepend_uint32(buf
);
311 skew
=seqnum
-ti
->lastrecvseq
;
312 if (skew
<0x8fffffff) {
314 ti
->lastrecvseq
=seqnum
;
315 } else if ((0-skew
)<ti
->max_skew
) {
319 *errmsg
="seqnum: too much skew";
326 static void transform_destroy(void *sst
)
328 struct transform_inst
*st
=sst
;
330 memset(st
,0,sizeof(*st
)); /* Destroy key material */
334 static struct transform_inst_if
*transform_create(void *sst
)
336 struct transform_inst
*ti
;
337 struct transform
*st
=sst
;
339 ti
=safe_malloc(sizeof(*ti
),"transform_create");
343 ti
->ops
.setkey
=transform_setkey
;
344 ti
->ops
.delkey
=transform_delkey
;
345 ti
->ops
.forwards
=transform_forward
;
346 ti
->ops
.reverse
=transform_reverse
;
347 ti
->ops
.destroy
=transform_destroy
;
348 ti
->max_skew
=st
->max_seq_skew
;
354 static list_t
*transform_apply(closure_t
*self
, struct cloc loc
,
355 dict_t
*context
, list_t
*args
)
357 struct transform
*st
;
361 st
=safe_malloc(sizeof(*st
),"serpent");
362 st
->cl
.description
="serpent-cbc256";
363 st
->cl
.type
=CL_TRANSFORM
;
365 st
->cl
.interface
=&st
->ops
;
367 st
->ops
.max_start_pad
=28; /* 4byte seqnum, 16byte pad, 4byte MACIV,
369 st
->ops
.max_end_pad
=16; /* 16byte CBCMAC */
371 /* We need 256*2 bits for serpent keys, 32 bits for CBC-IV and 32 bits
372 for CBCMAC-IV, and 32 bits for init sequence number */
373 st
->ops
.keylen
=REQUIRED_KEYLEN
;
374 st
->ops
.create
=transform_create
;
376 /* First parameter must be a dict */
377 item
=list_elem(args
,0);
378 if (!item
|| item
->type
!=t_dict
)
379 cfgfatal(loc
,"userv-ipif","parameter must be a dictionary\n");
381 dict
=item
->data
.dict
;
382 st
->max_seq_skew
=dict_read_number(dict
, "max-sequence-skew",
383 False
, "serpent-cbc256", loc
, 10);
385 return new_closure(&st
->cl
);
388 init_module transform_module
;
389 void transform_module(dict_t
*dict
)
391 struct keyInstance k
;
393 uint32_t plaintext
[4];
394 uint32_t ciphertext
[4];
396 /* Serpent self-test */
398 serpent_makekey(&k
,256,data
);
399 plaintext
[0]=0x00000000;
400 plaintext
[1]=0x00000001;
401 plaintext
[2]=0x00000002;
402 plaintext
[3]=0x00000003;
403 serpent_encrypt(&k
,plaintext
,ciphertext
);
404 if (ciphertext
[3]!=0x7ca73bb0 ||
405 ciphertext
[2]!=0x83C31E69 ||
406 ciphertext
[1]!=0xec52bd82 ||
407 ciphertext
[0]!=0x27a46120) {
408 fatal("transform_module: serpent failed self-test (encrypt)");
410 serpent_decrypt(&k
,ciphertext
,plaintext
);
411 if (plaintext
[0]!=0 ||
415 fatal("transform_module: serpent failed self-test (decrypt)");
418 add_closure(dict
,"serpent256-cbc",transform_apply
);