chiark / gitweb /
Report when transport peers updated as a result of transmit.
[secnet.git] / transform-eax.c
1 /*
2  * eax-transform.c: EAX-Serpent bulk data transformation
3  */
4 /*
5  * This file is part of secnet.
6  * See README for full list of copyright holders.
7  *
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 /*
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
76 struct transform_params {
77     SEQNUM_PARAMS_FIELDS;
78     uint32_t tag_length, padding_mask;
79 };
80
81 struct transform {
82     closure_t cl;
83     struct transform_if ops;
84     struct transform_params p;
85 };
86
87 struct transform_inst {
88     struct transform_inst_if ops;
89     struct transform_params p;
90     /* remaining valid iff keyed */
91     unsigned direction:1;
92     SEQNUM_KEYED_FIELDS;
93     struct keyInstance key;
94     uint8_t info_b[BLOCK_SIZE], info_p[BLOCK_SIZE];
95 };
96
97 static 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)
116 static 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
131 static 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;
148     serpent_makekey(&ti->key, 32*8, hash_out);
149     eax_setup(ti);
150     SEQNUM_KEYED_INIT(get_uint32(hash_out+32+!direction*4),
151                       get_uint32(hash_out+32+direction*4));
152
153     return True;
154 }
155
156 TRANSFORM_VALID;
157
158 TRANSFORM_DESTROY;
159
160 static 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
170 static 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
199     BUF_ADD_BYTES(append,buf,nonce,SEQLEN);
200
201     TEAX_DEBUG(nonce,SEQLEN);
202
203     ti->sendseq++;
204
205     return 0;
206 }
207
208 static 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
251     SEQNUM_CHECK(seqnum, &ti->p);
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
262 static 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
273 static 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
280     NEW(st);
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
293     SET_CAPAB_TRANSFORMNUM(CAPAB_TRANSFORMNUM_EAXSERPENT);
294
295     SEQNUM_PARAMS_INIT(dict,&st->p,"eax-serpent",loc);
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
313     update_max_start_pad(&transform_max_start_pad, 0);
314
315     st->ops.keylen=0;
316     st->ops.create=transform_create;
317
318     return new_closure(&st->cl);
319 }
320
321 void transform_eax_module(dict_t *dict)
322 {
323     add_closure(dict,"eax-serpent",transform_apply);
324 }