chiark / gitweb /
Static buffers: ipaddr_getbuf: Rename some variables
[secnet.git] / transform-eax.c
1 /*
2  * eax-transform.c: EAX-Serpent bulk data transformation
3  *
4  * We use EAX with the following parameters:
5  *
6  *   Plaintext:
7  *      Concatenation of:
8  *        Data packet as supplied to us
9  *        Zero or more zero bytes ignored by receiver } padding
10  *        One byte padding length                     }
11  *      This is a bit like PKCS#5.  It helps disguise message lengths.
12  *      It also provides a further room for future expansion.  When
13  *      transmitting we pad the message to the next multiple of
14  *      a configurable rounding factor, 16 bytes by default.
15  *
16  *   Transmitted message:
17  *      Concatenation of:
18  *        EAX ciphertext
19  *        32-bit sequence number (initially zero)
20  *      The sequence number allows us to discard far-too-old
21  *      packets.
22  *
23  *   Nonce:
24  *      Concatenation of:
25  *        32-bit sequence number (big endian)
26  *               initial value comes from SHA-512 hash (see below)
27  *        1 byte: 0x01 if sender has setup priority, 0x00 if it doesn't
28  *               (ie, the direction of data flow)
29  *
30  *   Header: None
31  *
32  *   Tag length:
33  *      16 bytes (128 bits) by default
34  *
35  *   Key:
36  *      The first 32 bytes of the SHA-512 hash of the shared secret
37  *      from the DH key exchange (the latter being expressed as
38  *      the shortest possible big-endian octet string).
39  *
40  * The bytes [32,40> of the hash of the shared secret are used for
41  * initial sequence numbers: [32,36> for those sent by the end without
42  * setup priority, [36,40> for those for the other end.
43  *
44  */
45
46 #include "secnet.h"
47 #include "unaligned.h"
48 #include "util.h"
49 #include "serpent.h"
50 #include "sha512.h"
51 #include "transform-common.h"
52 #include "hexdebug.h"
53
54 #define BLOCK_SIZE 16
55 #define SEQLEN 4
56
57 struct transform_params {
58     SEQNUM_PARAMS_FIELDS;
59     uint32_t tag_length, padding_mask;
60 };
61
62 struct transform {
63     closure_t cl;
64     struct transform_if ops;
65     struct transform_params p;
66 };
67
68 struct transform_inst {
69     struct transform_inst_if ops;
70     struct transform_params p;
71     /* remaining valid iff keyed */
72     unsigned direction:1;
73     SEQNUM_KEYED_FIELDS;
74     struct keyInstance key;
75     uint8_t info_b[BLOCK_SIZE], info_p[BLOCK_SIZE];
76 };
77
78 static void block_encrypt(struct transform_inst *transform_inst,
79                           uint8_t dst[BLOCK_SIZE],
80                           const uint8_t src[BLOCK_SIZE])
81 {
82     serpent_encrypt(&transform_inst->key, src, dst);
83 }
84
85 #define INFO                    struct transform_inst *transform_inst
86 #define I                       transform_inst
87 #define EAX_ENTRYPOINT_DECL     static
88 #define BLOCK_ENCRYPT(dst,src)  block_encrypt(transform_inst,dst,src)
89 #define INFO_B                  (transform_inst->info_b)
90 #define INFO_P                  (transform_inst->info_p)
91
92 #include "eax.c"
93
94 #if 0
95
96 #define TEAX_DEBUG(ary,sz) teax_debug(__func__,__LINE__,#ary,#sz,ary,sz)
97 static void teax_debug(const char *func, int line,
98                        const char *aryp, const char *szp,
99                        const void *ary, size_t sz)
100 {
101     fprintf(stderr,"TEAX %s:%-3d %10s %15s : ", func,line,aryp,szp);
102     hexdebug(stderr,ary,sz);
103     fprintf(stderr,"\n");
104 }
105
106 #else
107
108 #define TEAX_DEBUG(ary,sz) /* empty */
109
110 #endif
111
112 static bool_t transform_setkey(void *sst, uint8_t *key, int32_t keylen,
113                                bool_t direction)
114 {
115     struct transform_inst *ti=sst;
116     struct sha512_ctx hash_ctx;
117     uint8_t hash_out[64];
118
119     TEAX_DEBUG(key,keylen);
120
121     sha512_init_ctx(&hash_ctx);
122     sha512_process_bytes(key, keylen, &hash_ctx);
123     sha512_finish_ctx(&hash_ctx, hash_out);
124
125     TEAX_DEBUG(hash_out,32);
126     TEAX_DEBUG(hash_out+32,8);
127
128     ti->direction=direction;
129     serpent_makekey(&ti->key, 32*8, hash_out);
130     eax_setup(ti);
131     SEQNUM_KEYED_INIT(get_uint32(hash_out+32+!direction*4),
132                       get_uint32(hash_out+32+direction*4));
133
134     return True;
135 }
136
137 TRANSFORM_VALID;
138
139 TRANSFORM_DESTROY;
140
141 static void transform_delkey(void *sst)
142 {
143     struct transform_inst *ti=sst;
144
145     FILLZERO(ti->key);
146     FILLZERO(ti->info_b);
147     FILLZERO(ti->info_p);
148     ti->keyed=False;
149 }
150
151 static uint32_t transform_forward(void *sst, struct buffer_if *buf,
152                                   const char **errmsg)
153 {
154     struct transform_inst *ti=sst;
155
156     KEYED_CHECK;
157     
158     size_t padlen = ti->p.padding_mask - buf->size;
159     padlen &= ti->p.padding_mask;
160     padlen++;
161
162     uint8_t *pad = buf_append(buf,padlen);
163     memset(pad, 0, padlen-1);
164     pad[padlen-1] = padlen;
165
166     uint8_t nonce[SEQLEN+1];
167     put_uint32(nonce,ti->sendseq);
168     nonce[SEQLEN] = ti->direction;
169
170     TEAX_DEBUG(nonce,sizeof(nonce));
171     TEAX_DEBUG(buf->start,buf->size);
172
173     assert(buf_append(buf,ti->p.tag_length));
174     eax_encrypt(ti, nonce,sizeof(nonce), 0,0,
175                 buf->start,buf->size-ti->p.tag_length,
176                 ti->p.tag_length, buf->start);
177
178     TEAX_DEBUG(buf->start,buf->size);
179
180     BUF_ADD_BYTES(append,buf,nonce,SEQLEN);
181
182     TEAX_DEBUG(nonce,SEQLEN);
183
184     ti->sendseq++;
185
186     return 0;
187 }
188
189 static uint32_t transform_reverse(void *sst, struct buffer_if *buf,
190                                   const char **errmsg)
191 {
192     struct transform_inst *ti=sst;
193
194     KEYED_CHECK;
195
196     TEAX_DEBUG(buf->start,buf->size);
197
198     uint8_t nonce[SEQLEN+1];
199     const uint8_t *seqp = buf_unappend(buf,SEQLEN);
200     if (!seqp) goto too_short;
201
202     TEAX_DEBUG(seqp,SEQLEN);
203
204     uint32_t seqnum = get_uint32(seqp);
205
206     memcpy(nonce,seqp,SEQLEN);
207     nonce[4] = !ti->direction;
208
209     TEAX_DEBUG(nonce,sizeof(nonce));
210     TEAX_DEBUG(buf->start,buf->size);
211
212     bool_t ok = eax_decrypt(ti, nonce,sizeof(nonce), 0,0, buf->start,buf->size,
213                             ti->p.tag_length, buf->start);
214     if (!ok) {
215         TEAX_DEBUG(0,0);
216         *errmsg="EAX decryption failed";
217         return 1;
218     }
219     assert(buf->size >= (int)ti->p.tag_length);
220     buf->size -= ti->p.tag_length;
221
222     TEAX_DEBUG(buf->start,buf->size);
223
224     const uint8_t *padp = buf_unappend(buf,1);
225     if (!padp) goto too_short;
226
227     TEAX_DEBUG(padp,1);
228
229     size_t padlen = *padp;
230     if (!buf_unappend(buf,padlen-1)) goto too_short;
231
232     SEQNUM_CHECK(seqnum, &ti->p);
233
234     TEAX_DEBUG(buf->start,buf->size);
235
236     return 0;
237
238  too_short:
239     *errmsg="ciphertext or plaintext too short";
240     return 1;
241 }
242
243 static struct transform_inst_if *transform_create(void *sst)
244 {
245     struct transform *st=sst;
246
247     TRANSFORM_CREATE_CORE;
248
249     ti->p=st->p;
250
251     return &ti->ops;
252 }
253
254 static list_t *transform_apply(closure_t *self, struct cloc loc,
255                                dict_t *context, list_t *args)
256 {
257     struct transform *st;
258     item_t *item;
259     dict_t *dict;
260
261     NEW(st);
262     st->cl.description="eax-serpent";
263     st->cl.type=CL_TRANSFORM;
264     st->cl.apply=NULL;
265     st->cl.interface=&st->ops;
266     st->ops.st=st;
267
268     /* First parameter must be a dict */
269     item=list_elem(args,0);
270     if (!item || item->type!=t_dict)
271         cfgfatal(loc,"eax-serpent","parameter must be a dictionary\n");
272     dict=item->data.dict;
273
274     SET_CAPAB_TRANSFORMNUM(CAPAB_TRANSFORMNUM_EAXSERPENT);
275
276     SEQNUM_PARAMS_INIT(dict,&st->p,"eax-serpent",loc);
277
278     st->p.tag_length=dict_read_number(dict, "tag-length-bytes",
279                                       False, "eax-serpent", loc, 128/8);
280     if (st->p.tag_length<1 || st->p.tag_length>BLOCK_SIZE)
281         cfgfatal(loc,"eax-serpent","tag-length-bytes out of range 0..%d\n",
282                  BLOCK_SIZE);
283
284     uint32_t padding_round=dict_read_number(dict, "padding-rounding",
285                                             False, "eax-serpent", loc, 16);
286     if (padding_round & (padding_round-1))
287         cfgfatal(loc,"eax-serpent","padding-round not a power of two\n");
288     if (padding_round > 255)
289         cfgfatal(loc,"eax-serpent","padding-round must be 1..128\n");
290     if (padding_round == 0)
291         padding_round = 1;
292     st->p.padding_mask = padding_round-1;
293
294     update_max_start_pad(&transform_max_start_pad, 0);
295
296     st->ops.keylen=0;
297     st->ops.create=transform_create;
298
299     return new_closure(&st->cl);
300 }
301
302 void transform_eax_module(dict_t *dict)
303 {
304     add_closure(dict,"eax-serpent",transform_apply);
305 }