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);
316 st->ops.create=transform_create;
318 return new_closure(&st->cl);
321 void transform_eax_module(dict_t *dict)
323 add_closure(dict,"eax-serpent",transform_apply);