changelog: mention hippotat
[secnet] / transform-eax.c
CommitLineData
b02b720a
IJ
1/*
2 * eax-transform.c: EAX-Serpent bulk data transformation
c215a4bc
IJ
3 */
4/*
5 * This file is part of secnet.
6 * See README for full list of copyright holders.
b02b720a 7 *
c215a4bc
IJ
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 d of the License, or
11 * (at your option) any later version.
12 *
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.
17 *
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.
21 */
22/*
b02b720a
IJ
23 * We use EAX with the following parameters:
24 *
25 * Plaintext:
26 * Concatenation of:
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.
34 *
35 * Transmitted message:
36 * Concatenation of:
37 * EAX ciphertext
38 * 32-bit sequence number (initially zero)
39 * The sequence number allows us to discard far-too-old
40 * packets.
41 *
42 * Nonce:
43 * Concatenation of:
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)
48 *
49 * Header: None
50 *
51 * Tag length:
52 * 16 bytes (128 bits) by default
53 *
54 * Key:
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).
58 *
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.
62 *
63 */
64
65#include "secnet.h"
66#include "unaligned.h"
67#include "util.h"
68#include "serpent.h"
69#include "sha512.h"
70#include "transform-common.h"
71#include "hexdebug.h"
72
73#define BLOCK_SIZE 16
74#define SEQLEN 4
75
76struct transform_params {
35d30aa3
IJ
77 SEQNUM_PARAMS_FIELDS;
78 uint32_t tag_length, padding_mask;
b02b720a
IJ
79};
80
81struct transform {
82 closure_t cl;
83 struct transform_if ops;
84 struct transform_params p;
85};
86
87struct transform_inst {
88 struct transform_inst_if ops;
89 struct transform_params p;
b02b720a
IJ
90 /* remaining valid iff keyed */
91 unsigned direction:1;
35d30aa3 92 SEQNUM_KEYED_FIELDS;
b02b720a
IJ
93 struct keyInstance key;
94 uint8_t info_b[BLOCK_SIZE], info_p[BLOCK_SIZE];
95};
96
97static void block_encrypt(struct transform_inst *transform_inst,
98 uint8_t dst[BLOCK_SIZE],
99 const uint8_t src[BLOCK_SIZE])
100{
101 serpent_encrypt(&transform_inst->key, src, dst);
102}
103
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)
110
111#include "eax.c"
112
113#if 0
114
115#define TEAX_DEBUG(ary,sz) teax_debug(__func__,__LINE__,#ary,#sz,ary,sz)
116static void teax_debug(const char *func, int line,
117 const char *aryp, const char *szp,
118 const void *ary, size_t sz)
119{
120 fprintf(stderr,"TEAX %s:%-3d %10s %15s : ", func,line,aryp,szp);
121 hexdebug(stderr,ary,sz);
122 fprintf(stderr,"\n");
123}
124
125#else
126
127#define TEAX_DEBUG(ary,sz) /* empty */
128
129#endif
130
131static bool_t transform_setkey(void *sst, uint8_t *key, int32_t keylen,
132 bool_t direction)
133{
134 struct transform_inst *ti=sst;
135 struct sha512_ctx hash_ctx;
136 uint8_t hash_out[64];
137
138 TEAX_DEBUG(key,keylen);
139
140 sha512_init_ctx(&hash_ctx);
141 sha512_process_bytes(key, keylen, &hash_ctx);
142 sha512_finish_ctx(&hash_ctx, hash_out);
143
144 TEAX_DEBUG(hash_out,32);
145 TEAX_DEBUG(hash_out+32,8);
146
147 ti->direction=direction;
b02b720a
IJ
148 serpent_makekey(&ti->key, 32*8, hash_out);
149 eax_setup(ti);
35d30aa3
IJ
150 SEQNUM_KEYED_INIT(get_uint32(hash_out+32+!direction*4),
151 get_uint32(hash_out+32+direction*4));
b02b720a
IJ
152
153 return True;
154}
155
156TRANSFORM_VALID;
157
158TRANSFORM_DESTROY;
159
160static void transform_delkey(void *sst)
161{
162 struct transform_inst *ti=sst;
163
164 FILLZERO(ti->key);
165 FILLZERO(ti->info_b);
166 FILLZERO(ti->info_p);
167 ti->keyed=False;
168}
169
170static uint32_t transform_forward(void *sst, struct buffer_if *buf,
171 const char **errmsg)
172{
173 struct transform_inst *ti=sst;
174
175 KEYED_CHECK;
176
177 size_t padlen = ti->p.padding_mask - buf->size;
178 padlen &= ti->p.padding_mask;
179 padlen++;
180
181 uint8_t *pad = buf_append(buf,padlen);
182 memset(pad, 0, padlen-1);
183 pad[padlen-1] = padlen;
184
185 uint8_t nonce[SEQLEN+1];
186 put_uint32(nonce,ti->sendseq);
187 nonce[SEQLEN] = ti->direction;
188
189 TEAX_DEBUG(nonce,sizeof(nonce));
190 TEAX_DEBUG(buf->start,buf->size);
191
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);
196
197 TEAX_DEBUG(buf->start,buf->size);
198
4f28e77e 199 BUF_ADD_BYTES(append,buf,nonce,SEQLEN);
b02b720a
IJ
200
201 TEAX_DEBUG(nonce,SEQLEN);
202
203 ti->sendseq++;
204
205 return 0;
206}
207
208static uint32_t transform_reverse(void *sst, struct buffer_if *buf,
209 const char **errmsg)
210{
211 struct transform_inst *ti=sst;
212
213 KEYED_CHECK;
214
215 TEAX_DEBUG(buf->start,buf->size);
216
217 uint8_t nonce[SEQLEN+1];
218 const uint8_t *seqp = buf_unappend(buf,SEQLEN);
219 if (!seqp) goto too_short;
220
221 TEAX_DEBUG(seqp,SEQLEN);
222
223 uint32_t seqnum = get_uint32(seqp);
224
225 memcpy(nonce,seqp,SEQLEN);
226 nonce[4] = !ti->direction;
227
228 TEAX_DEBUG(nonce,sizeof(nonce));
229 TEAX_DEBUG(buf->start,buf->size);
230
231 bool_t ok = eax_decrypt(ti, nonce,sizeof(nonce), 0,0, buf->start,buf->size,
232 ti->p.tag_length, buf->start);
233 if (!ok) {
234 TEAX_DEBUG(0,0);
235 *errmsg="EAX decryption failed";
236 return 1;
237 }
238 assert(buf->size >= (int)ti->p.tag_length);
239 buf->size -= ti->p.tag_length;
240
241 TEAX_DEBUG(buf->start,buf->size);
242
243 const uint8_t *padp = buf_unappend(buf,1);
244 if (!padp) goto too_short;
245
246 TEAX_DEBUG(padp,1);
247
248 size_t padlen = *padp;
249 if (!buf_unappend(buf,padlen-1)) goto too_short;
250
35d30aa3 251 SEQNUM_CHECK(seqnum, &ti->p);
b02b720a
IJ
252
253 TEAX_DEBUG(buf->start,buf->size);
254
255 return 0;
256
257 too_short:
258 *errmsg="ciphertext or plaintext too short";
259 return 1;
260}
261
262static struct transform_inst_if *transform_create(void *sst)
263{
264 struct transform *st=sst;
265
266 TRANSFORM_CREATE_CORE;
267
268 ti->p=st->p;
269
270 return &ti->ops;
271}
272
273static list_t *transform_apply(closure_t *self, struct cloc loc,
274 dict_t *context, list_t *args)
275{
276 struct transform *st;
277 item_t *item;
278 dict_t *dict;
279
b7886fd4 280 NEW(st);
b02b720a
IJ
281 st->cl.description="eax-serpent";
282 st->cl.type=CL_TRANSFORM;
283 st->cl.apply=NULL;
284 st->cl.interface=&st->ops;
285 st->ops.st=st;
286
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;
292
5b5f297f
IJ
293 SET_CAPAB_TRANSFORMNUM(CAPAB_TRANSFORMNUM_EAXSERPENT);
294
35d30aa3 295 SEQNUM_PARAMS_INIT(dict,&st->p,"eax-serpent",loc);
b02b720a
IJ
296
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",
301 BLOCK_SIZE);
302
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)
310 padding_round = 1;
311 st->p.padding_mask = padding_round-1;
312
3abd18e8 313 update_max_start_pad(&transform_max_start_pad, 0);
b02b720a
IJ
314
315 st->ops.keylen=0;
316 st->ops.create=transform_create;
317
318 return new_closure(&st->cl);
319}
320
321void transform_eax_module(dict_t *dict)
322{
323 add_closure(dict,"eax-serpent",transform_apply);
324}