2 * eax-transform.c: EAX-Serpent bulk data transformation
5 * This file is part of secnet.
6 * See README for full list of copyright holders.
8 * secnet is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 3 of the License, or
11 * (at your option) any later version.
13 * secnet is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * version 3 along with secnet; if not, see
20 * https://www.gnu.org/licenses/gpl.html.
23 * We use EAX with the following parameters:
27 * Data packet as supplied to us
28 * Zero or more zero bytes ignored by receiver } padding
29 * One byte padding length }
30 * This is a bit like PKCS#5. It helps disguise message lengths.
31 * It also provides a further room for future expansion. When
32 * transmitting we pad the message to the next multiple of
33 * a configurable rounding factor, 16 bytes by default.
35 * Transmitted message:
38 * 32-bit sequence number (initially zero)
39 * The sequence number allows us to discard far-too-old
44 * 32-bit sequence number (big endian)
45 * initial value comes from SHA-512 hash (see below)
46 * 1 byte: 0x01 if sender has setup priority, 0x00 if it doesn't
47 * (ie, the direction of data flow)
52 * 16 bytes (128 bits) by default
55 * The first 32 bytes of the SHA-512 hash of the shared secret
56 * from the DH key exchange (the latter being expressed as
57 * the shortest possible big-endian octet string).
59 * The bytes [32,40> of the hash of the shared secret are used for
60 * initial sequence numbers: [32,36> for those sent by the end without
61 * setup priority, [36,40> for those for the other end.
66 #include "unaligned.h"
70 #include "transform-common.h"
76 struct transform_params
{
78 uint32_t tag_length
, padding_mask
;
83 struct transform_if ops
;
84 struct transform_params p
;
87 struct transform_inst
{
88 struct transform_inst_if ops
;
89 struct transform_params p
;
90 /* remaining valid iff keyed */
93 struct keyInstance key
;
94 uint8_t info_b
[BLOCK_SIZE
], info_p
[BLOCK_SIZE
];
97 static void block_encrypt(struct transform_inst
*transform_inst
,
98 uint8_t dst
[BLOCK_SIZE
],
99 const uint8_t src
[BLOCK_SIZE
])
101 serpent_encrypt(&transform_inst
->key
, src
, dst
);
104 #define INFO struct transform_inst *transform_inst
105 #define I transform_inst
106 #define EAX_ENTRYPOINT_DECL static
107 #define BLOCK_ENCRYPT(dst,src) block_encrypt(transform_inst,dst,src)
108 #define INFO_B (transform_inst->info_b)
109 #define INFO_P (transform_inst->info_p)
115 #define TEAX_DEBUG(ary,sz) teax_debug(__func__,__LINE__,#ary,#sz,ary,sz)
116 static void teax_debug(const char *func
, int line
,
117 const char *aryp
, const char *szp
,
118 const void *ary
, size_t sz
)
120 fprintf(stderr
,"TEAX %s:%-3d %10s %15s : ", func
,line
,aryp
,szp
);
121 hexdebug(stderr
,ary
,sz
);
122 fprintf(stderr
,"\n");
127 #define TEAX_DEBUG(ary,sz) /* empty */
131 static bool_t
transform_setkey(void *sst
, uint8_t *key
, int32_t keylen
,
134 struct transform_inst
*ti
=sst
;
135 struct sha512_ctx hash_ctx
;
136 uint8_t hash_out
[64];
138 TEAX_DEBUG(key
,keylen
);
140 sha512_init_ctx(&hash_ctx
);
141 sha512_process_bytes(key
, keylen
, &hash_ctx
);
142 sha512_finish_ctx(&hash_ctx
, hash_out
);
144 TEAX_DEBUG(hash_out
,32);
145 TEAX_DEBUG(hash_out
+32,8);
147 ti
->direction
=direction
;
148 serpent_makekey(&ti
->key
, 32*8, hash_out
);
150 SEQNUM_KEYED_INIT(get_uint32(hash_out
+32+!direction
*4),
151 get_uint32(hash_out
+32+direction
*4));
160 static void transform_delkey(void *sst
)
162 struct transform_inst
*ti
=sst
;
165 FILLZERO(ti
->info_b
);
166 FILLZERO(ti
->info_p
);
170 static transform_apply_return
transform_forward(void *sst
,
171 struct buffer_if
*buf
, const char **errmsg
)
173 struct transform_inst
*ti
=sst
;
177 size_t padlen
= ti
->p
.padding_mask
- buf
->size
;
178 padlen
&= ti
->p
.padding_mask
;
181 uint8_t *pad
= buf_append(buf
,padlen
);
182 memset(pad
, 0, padlen
-1);
183 pad
[padlen
-1] = padlen
;
185 uint8_t nonce
[SEQLEN
+1];
186 put_uint32(nonce
,ti
->sendseq
);
187 nonce
[SEQLEN
] = ti
->direction
;
189 TEAX_DEBUG(nonce
,sizeof(nonce
));
190 TEAX_DEBUG(buf
->start
,buf
->size
);
192 assert(buf_append(buf
,ti
->p
.tag_length
));
193 eax_encrypt(ti
, nonce
,sizeof(nonce
), 0,0,
194 buf
->start
,buf
->size
-ti
->p
.tag_length
,
195 ti
->p
.tag_length
, buf
->start
);
197 TEAX_DEBUG(buf
->start
,buf
->size
);
199 BUF_ADD_BYTES(append
,buf
,nonce
,SEQLEN
);
201 TEAX_DEBUG(nonce
,SEQLEN
);
208 static transform_apply_return
transform_reverse(void *sst
,
209 struct buffer_if
*buf
, const char **errmsg
)
211 struct transform_inst
*ti
=sst
;
215 TEAX_DEBUG(buf
->start
,buf
->size
);
217 uint8_t nonce
[SEQLEN
+1];
218 const uint8_t *seqp
= buf_unappend(buf
,SEQLEN
);
219 if (!seqp
) goto too_short
;
221 TEAX_DEBUG(seqp
,SEQLEN
);
223 uint32_t seqnum
= get_uint32(seqp
);
225 memcpy(nonce
,seqp
,SEQLEN
);
226 nonce
[4] = !ti
->direction
;
228 TEAX_DEBUG(nonce
,sizeof(nonce
));
229 TEAX_DEBUG(buf
->start
,buf
->size
);
231 bool_t ok
= eax_decrypt(ti
, nonce
,sizeof(nonce
), 0,0, buf
->start
,buf
->size
,
232 ti
->p
.tag_length
, buf
->start
);
235 *errmsg
="EAX decryption failed";
236 return transform_apply_err
;
238 assert(buf
->size
>= (int)ti
->p
.tag_length
);
239 buf
->size
-= ti
->p
.tag_length
;
241 TEAX_DEBUG(buf
->start
,buf
->size
);
243 const uint8_t *padp
= buf_unappend(buf
,1);
244 if (!padp
) goto too_short
;
248 size_t padlen
= *padp
;
249 if (!buf_unappend(buf
,padlen
-1)) goto too_short
;
251 SEQNUM_CHECK(seqnum
, &ti
->p
);
253 TEAX_DEBUG(buf
->start
,buf
->size
);
258 *errmsg
="ciphertext or plaintext too short";
259 return transform_apply_err
;
262 static struct transform_inst_if
*transform_create(void *sst
)
264 struct transform
*st
=sst
;
266 TRANSFORM_CREATE_CORE
;
273 static list_t
*transform_apply(closure_t
*self
, struct cloc loc
,
274 dict_t
*context
, list_t
*args
)
276 struct transform
*st
;
281 st
->cl
.description
="eax-serpent";
282 st
->cl
.type
=CL_TRANSFORM
;
284 st
->cl
.interface
=&st
->ops
;
287 /* First parameter must be a dict */
288 item
=list_elem(args
,0);
289 if (!item
|| item
->type
!=t_dict
)
290 cfgfatal(loc
,"eax-serpent","parameter must be a dictionary\n");
291 dict
=item
->data
.dict
;
293 SET_CAPAB_BIT(CAPAB_BIT_EAXSERPENT
);
295 SEQNUM_PARAMS_INIT(dict
,&st
->p
,"eax-serpent",loc
);
297 st
->p
.tag_length
=dict_read_number(dict
, "tag-length-bytes",
298 False
, "eax-serpent", loc
, 128/8);
299 if (st
->p
.tag_length
<1 || st
->p
.tag_length
>BLOCK_SIZE
)
300 cfgfatal(loc
,"eax-serpent","tag-length-bytes out of range 0..%d\n",
303 uint32_t padding_round
=dict_read_number(dict
, "padding-rounding",
304 False
, "eax-serpent", loc
, 16);
305 if (padding_round
& (padding_round
-1))
306 cfgfatal(loc
,"eax-serpent","padding-round not a power of two\n");
307 if (padding_round
> 255)
308 cfgfatal(loc
,"eax-serpent","padding-round must be 1..128\n");
309 if (padding_round
== 0)
311 st
->p
.padding_mask
= padding_round
-1;
313 update_max_start_pad(&transform_max_start_pad
, 0);
315 st
->ops
.create
=transform_create
;
317 return new_closure(&st
->cl
);
320 void transform_eax_module(dict_t
*dict
)
322 add_closure(dict
,"eax-serpent",transform_apply
);