chiark / gitweb /
server/: Make bulk crypto transforms responsible for algorithm selection.
[tripe] / server / bulkcrypto.c
1 /* -*-c-*-
2  *
3  * Bulk crypto transformations
4  *
5  * (c) 2014 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of Trivial IP Encryption (TrIPE).
11  *
12  * TrIPE is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * TrIPE is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with TrIPE; if not, write to the Free Software Foundation,
24  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25  */
26
27 /*----- Header files ------------------------------------------------------*/
28
29 #include "tripe.h"
30
31 /*----- Utilities ---------------------------------------------------------*/
32
33 #define SEQSZ 4                         /* Size of sequence number packet */
34
35 #define TRACE_IV(qiv, ivsz) do { IF_TRACING(T_KEYSET, {                 \
36   trace_block(T_CRYPTO, "crypto: initialization vector",                \
37               (qiv), (ivsz));                                           \
38 }) } while (0)
39
40 #define TRACE_CT(qpk, sz) do { IF_TRACING(T_KEYSET, {                   \
41   trace_block(T_CRYPTO, "crypto: encrypted packet", (qpk), (sz));       \
42 }) } while (0)
43
44 #define TRACE_MAC(qmac, tagsz) do { IF_TRACING(T_KEYSET, {              \
45   trace_block(T_CRYPTO, "crypto: computed MAC", (qmac), (tagsz));       \
46 }) } while (0)
47
48 #define TRACE_MACERR(pmac, tagsz) do { IF_TRACING(T_KEYSET, {           \
49   trace(T_KEYSET, "keyset: incorrect MAC: decryption failed");          \
50   trace_block(T_CRYPTO, "crypto: expected MAC", (pmac), (tagsz));       \
51 }) } while (0)
52
53 /*----- Common functionality for generic-composition transforms -----------*/
54
55 #define CHECK_MAC(h, pmac, tagsz) do {                                  \
56   ghash *_h = (h);                                                      \
57   const octet *_pmac = (pmac);                                          \
58   size_t _tagsz = (tagsz);                                              \
59   octet *_mac = GH_DONE(_h, 0);                                         \
60   int _eq = ct_memeq(_mac, _pmac, _tagsz);                              \
61   TRACE_MAC(_mac, _tagsz);                                              \
62   GH_DESTROY(_h);                                                       \
63   if (!_eq) {                                                           \
64     TRACE_MACERR(_pmac, _tagsz);                                        \
65     return (KSERR_DECRYPT);                                             \
66   }                                                                     \
67 } while (0)
68
69 typedef struct gencomp_algs {
70   const gccipher *c; size_t cksz;
71   const gcmac *m; size_t mksz; size_t tagsz;
72 } gencomp_algs;
73
74 typedef struct gencomp_chal {
75   bulkchal _b;
76   gmac *m; size_t tagsz;
77 } gencomp_chal;
78
79 static int gencomp_getalgs(gencomp_algs *a, const algswitch *asw,
80                            dstr *e, key_file *kf, key *k)
81 {
82   const char *p;
83   char *q, *qq;
84   unsigned long n;
85   dstr d = DSTR_INIT;
86   int rc = -1;
87
88   /* --- Symmetric encryption --- */
89
90   if ((p = key_getattr(kf, k, "cipher")) == 0) p = "blowfish-cbc";
91   if ((a->c = gcipher_byname(p)) == 0) {
92     a_format(e, "unknown-cipher", "%s", p, A_END);
93     goto done;
94   }
95
96   /* --- Message authentication --- */
97
98   if ((p = key_getattr(kf, k, "mac")) != 0) {
99     dstr_reset(&d);
100     dstr_puts(&d, p);
101     if ((q = strchr(d.buf, '/')) != 0)
102       *q++ = 0;
103     if ((a->m = gmac_byname(d.buf)) == 0) {
104       a_format(e, "unknown-mac", "%s", d.buf, A_END);
105       goto done;
106     }
107     if (!q)
108       a->tagsz = a->m->hashsz;
109     else {
110       n = strtoul(q, &qq, 0);
111       if (*qq)  {
112         a_format(e, "bad-tag-length-string", "%s", q, A_END);
113         goto done;
114       }
115       if (n%8 || n/8 > a->m->hashsz) {
116         a_format(e, "bad-tag-length", "%lu", n, A_END);
117         goto done;
118       }
119       a->tagsz = n/8;
120     }
121   } else {
122     dstr_reset(&d);
123     dstr_putf(&d, "%s-hmac", asw->h->name);
124     if ((a->m = gmac_byname(d.buf)) == 0) {
125       a_format(e, "no-hmac-for-hash", "%s", asw->h->name, A_END);
126       goto done;
127     }
128     a->tagsz = asw->h->hashsz/2;
129   }
130
131   rc = 0;
132 done:
133   dstr_destroy(&d);
134   return (rc);
135 }
136
137 #ifndef NTRACE
138 static void gencomp_tracealgs(const gencomp_algs *a)
139 {
140   trace(T_CRYPTO, "crypto: cipher = %s", a->c->name);
141   trace(T_CRYPTO, "crypto: mac = %s/%lu",
142         a->m->name, (unsigned long)a->tagsz * 8);
143 }
144 #endif
145
146 static int gencomp_checkalgs(gencomp_algs *a, const algswitch *asw, dstr *e)
147 {
148   /* --- Derive the key sizes --- *
149    *
150    * Must ensure that we have non-empty keys.  This isn't ideal, but it
151    * provides a handy sanity check.  Also must be based on a 64- or 128-bit
152    * block cipher or we can't do the data expiry properly.
153    */
154
155   if ((a->cksz = keysz(asw->hashsz, a->c->keysz)) == 0) {
156     a_format(e, "cipher", "%s", a->c->name,
157              "no-key-size", "%lu", (unsigned long)asw->hashsz,
158              A_END);
159     return (-1);
160   }
161   if ((a->mksz = keysz(asw->hashsz, a->m->keysz)) == 0) {
162     a_format(e, "mac", "%s", a->m->name,
163              "no-key-size", "%lu", (unsigned long)asw->hashsz,
164              A_END);
165     return (-1);
166   }
167
168   return (0);
169 }
170
171 static void gencomp_alginfo(const gencomp_algs *a, admin *adm)
172 {
173   a_info(adm,
174          "cipher=%s", a->c->name,
175          "cipher-keysz=%lu", (unsigned long)a->cksz,
176          "cipher-blksz=%lu", (unsigned long)a->c->blksz,
177          A_END);
178   a_info(adm,
179          "mac=%s", a->m->name,
180          "mac-keysz=%lu", (unsigned long)a->mksz,
181          "mac-tagsz=%lu", (unsigned long)a->tagsz,
182          A_END);
183 }
184
185 static int gencomp_samealgsp(const gencomp_algs *a, const gencomp_algs *aa)
186 {
187   return (a->c == aa->c &&
188           a->m == aa->m && a->tagsz == aa->tagsz);
189 }
190
191 static size_t gencomp_expsz(const gencomp_algs *a)
192   { return (a->c->blksz < 16 ? MEG(64) : MEG(2048)); }
193
194 static bulkchal *gencomp_genchal(const gencomp_algs *a)
195 {
196   gencomp_chal *gc = CREATE(gencomp_chal);
197
198   rand_get(RAND_GLOBAL, buf_t, a->mksz);
199   gc->m = GM_KEY(a->m, buf_t, a->mksz);
200   gc->_b.tagsz = a->tagsz;
201   IF_TRACING(T_CHAL, {
202     trace(T_CHAL, "chal: generated new challenge key");
203     trace_block(T_CRYPTO, "chal: new key", buf_t, a->mksz);
204   })
205   return (&gc->_b);
206 }
207
208 static int gencomp_chaltag(bulkchal *bc, const void *m, size_t msz, void *t)
209 {
210   gencomp_chal *gc = (gencomp_chal *)bc;
211   ghash *h = GM_INIT(gc->m);
212
213   GH_HASH(h, m, msz);
214   memcpy(t, GH_DONE(h, 0), bc->tagsz);
215   GH_DESTROY(h);
216   return (0);
217 }
218
219 static int gencomp_chalvrf(bulkchal *bc, const void *m, size_t msz,
220                            const void *t)
221 {
222   gencomp_chal *gc = (gencomp_chal *)bc;
223   ghash *h = GM_INIT(gc->m);
224   int ok;
225
226   GH_HASH(h, m, msz);
227   ok = ct_memeq(GH_DONE(h, 0), t, gc->_b.tagsz);
228   GH_DESTROY(h);
229   return (ok ? 0 : -1);
230 }
231
232 static void gencomp_freechal(bulkchal *bc)
233   { gencomp_chal *gc = (gencomp_chal *)bc; GM_DESTROY(gc->m); DESTROY(gc); }
234
235 /*----- The original transform --------------------------------------------*
236  *
237  * We generate a random initialization vector (if the cipher needs one).  We
238  * encrypt the input message with the cipher, and format the type, sequence
239  * number, IV, and ciphertext as follows.
240  *
241  *              +------+ +------+---...---+------...------+
242  *              | type | | seq  |   iv    |   ciphertext  |
243  *              +------+ +------+---...---+------...------+
244  *                 32       32     blksz         sz
245  *
246  * All of this is fed into the MAC to compute a tag.  The type is not
247  * transmitted: the other end knows what type of message it expects, and the
248  * type is only here to prevent us from being confused because some other
249  * kind of ciphertext has been substituted.  The tag is prepended to the
250  * remainder, to yield the finished cryptogram, as follows.
251  *
252  *              +---...---+------+---...---+------...------+
253  *              |   tag   | seq  |   iv    |   ciphertext  |
254  *              +---...---+------+---...---+------...------+
255  *                 tagsz     32     blksz         sz
256  *
257  * Decryption: checks the overall size, verifies the tag, then decrypts the
258  * ciphertext and extracts the sequence number.
259  */
260
261 typedef struct v0_algs {
262   bulkalgs _b;
263   gencomp_algs ga;
264 } v0_algs;
265
266 typedef struct v0_ctx {
267   bulkctx _b;
268   size_t tagsz;
269   struct {
270     gcipher *c;
271     gmac *m;
272   } d[NDIR];
273 } v0_ctx;
274
275 static bulkalgs *v0_getalgs(const algswitch *asw, dstr *e,
276                             key_file *kf, key *k)
277 {
278   v0_algs *a = CREATE(v0_algs);
279   if (gencomp_getalgs(&a->ga, asw, e, kf, k)) { DESTROY(a); return (0); }
280   return (&a->_b);
281 }
282
283 #ifndef NTRACE
284 static void v0_tracealgs(const bulkalgs *aa)
285   { const v0_algs *a = (const v0_algs *)aa; gencomp_tracealgs(&a->ga); }
286 #endif
287
288 static int v0_checkalgs(bulkalgs *aa, const algswitch *asw, dstr *e)
289 {
290   v0_algs *a = (v0_algs *)aa;
291   if (gencomp_checkalgs(&a->ga, asw, e)) return (-1);
292   return (0);
293 }
294
295 static int v0_samealgsp(const bulkalgs *aa, const bulkalgs *bb)
296 {
297   const v0_algs *a = (const v0_algs *)aa, *b = (const v0_algs *)bb;
298   return (gencomp_samealgsp(&a->ga, &b->ga));
299 }
300
301 static void v0_alginfo(const bulkalgs *aa, admin *adm)
302   { const v0_algs *a = (const v0_algs *)aa; gencomp_alginfo(&a->ga, adm); }
303
304 static size_t v0_overhead(const bulkalgs *aa)
305 {
306   const v0_algs *a = (const v0_algs *)aa;
307   return (a->ga.tagsz + SEQSZ + a->ga.c->blksz);
308 }
309
310 static size_t v0_expsz(const bulkalgs *aa)
311   { const v0_algs *a = (const v0_algs *)aa; return (gencomp_expsz(&a->ga)); }
312
313 static bulkctx *v0_genkeys(const bulkalgs *aa, const struct rawkey *rk)
314 {
315   const v0_algs *a = (const v0_algs *)aa;
316   v0_ctx *bc = CREATE(v0_ctx);
317   octet k[MAXHASHSZ];
318   int i;
319
320   bc->tagsz = a->ga.tagsz;
321   for (i = 0; i < NDIR; i++) {
322     ks_derivekey(k, a->ga.cksz, rk, i, "encryption");
323     bc->d[i].c = GC_INIT(a->ga.c, k, a->ga.cksz);
324     ks_derivekey(k, a->ga.mksz, rk, i, "integrity");
325     bc->d[i].m = GM_KEY(a->ga.m, k, a->ga.mksz);
326   }
327   return (&bc->_b);
328 }
329
330 static bulkchal *v0_genchal(const bulkalgs *aa)
331 {
332   const v0_algs *a = (const v0_algs *)aa;
333   return (gencomp_genchal(&a->ga));
334 }
335 #define v0_chaltag gencomp_chaltag
336 #define v0_chalvrf gencomp_chalvrf
337 #define v0_freechal gencomp_freechal
338
339 static void v0_freealgs(bulkalgs *aa)
340   { v0_algs *a = (v0_algs *)aa; DESTROY(a); }
341
342 static void v0_freectx(bulkctx *bbc)
343 {
344   v0_ctx *bc = (v0_ctx *)bbc;
345   int i;
346
347   for (i = 0; i < NDIR; i++) {
348     GC_DESTROY(bc->d[i].c);
349     GM_DESTROY(bc->d[i].m);
350   }
351   DESTROY(bc);
352 }
353
354 static int v0_encrypt(bulkctx *bbc, unsigned ty,
355                       buf *b, buf *bb, uint32 seq)
356 {
357   v0_ctx *bc = (v0_ctx *)bbc;
358   ghash *h;
359   gcipher *c = bc->d[DIR_OUT].c;
360   const octet *p = BCUR(b);
361   size_t sz = BLEFT(b);
362   octet *qmac, *qseq, *qiv, *qpk;
363   size_t ivsz = GC_CLASS(c)->blksz;
364   size_t tagsz = bc->tagsz;
365   octet t[4];
366
367   /* --- Determine the ciphertext layout --- */
368
369   if (buf_ensure(bb, tagsz + SEQSZ + ivsz + sz)) return (0);
370   qmac = BCUR(bb); qseq = qmac + tagsz; qiv = qseq + SEQSZ; qpk = qiv + ivsz;
371   BSTEP(bb, tagsz + SEQSZ + ivsz + sz);
372
373   /* --- Store the type --- *
374    *
375    * This isn't transmitted, but it's covered by the MAC.
376    */
377
378   STORE32(t, ty);
379
380   /* --- Store the sequence number --- */
381
382   STORE32(qseq, seq);
383
384   /* --- Establish an initialization vector if necessary --- */
385
386   if (ivsz) {
387     rand_get(RAND_GLOBAL, qiv, ivsz);
388     GC_SETIV(c, qiv);
389     TRACE_IV(qiv, ivsz);
390   }
391
392   /* --- Encrypt the packet --- */
393
394   GC_ENCRYPT(c, p, qpk, sz);
395   TRACE_CT(qpk, sz);
396
397   /* --- Compute a MAC over type, sequence number, IV, and ciphertext --- */
398
399   if (tagsz) {
400     h = GM_INIT(bc->d[DIR_OUT].m);
401     GH_HASH(h, t, sizeof(t));
402     GH_HASH(h, qseq, SEQSZ + ivsz + sz);
403     memcpy(qmac, GH_DONE(h, 0), tagsz);
404     GH_DESTROY(h);
405     TRACE_MAC(qmac, tagsz);
406   }
407
408   /* --- We're done --- */
409
410   return (0);
411 }
412
413 static int v0_decrypt(bulkctx *bbc, unsigned ty,
414                       buf *b, buf *bb, uint32 *seq)
415 {
416   v0_ctx *bc = (v0_ctx *)bbc;
417   const octet *pmac, *piv, *pseq, *ppk;
418   size_t psz = BLEFT(b);
419   size_t sz;
420   octet *q = BCUR(bb);
421   ghash *h;
422   gcipher *c = bc->d[DIR_IN].c;
423   size_t ivsz = GC_CLASS(c)->blksz;
424   size_t tagsz = bc->tagsz;
425   octet t[4];
426
427   /* --- Break up the packet into its components --- */
428
429   if (psz < ivsz + SEQSZ + tagsz) {
430     T( trace(T_KEYSET, "keyset: block too small for keyset"); )
431     return (KSERR_MALFORMED);
432   }
433   sz = psz - ivsz - SEQSZ - tagsz;
434   pmac = BCUR(b); pseq = pmac + tagsz; piv = pseq + SEQSZ; ppk = piv + ivsz;
435   STORE32(t, ty);
436
437   /* --- Verify the MAC on the packet --- */
438
439   if (tagsz) {
440     h = GM_INIT(bc->d[DIR_IN].m);
441     GH_HASH(h, t, sizeof(t));
442     GH_HASH(h, pseq, SEQSZ + ivsz + sz);
443     CHECK_MAC(h, pmac, tagsz);
444   }
445
446   /* --- Decrypt the packet --- */
447
448   if (ivsz) {
449     TRACE_IV(piv, ivsz);
450     GC_SETIV(c, piv);
451   }
452   GC_DECRYPT(c, ppk, q, sz);
453
454   /* --- Finished --- */
455
456   *seq = LOAD32(pseq);
457   BSTEP(bb, sz);
458   return (0);
459 }
460
461 /*----- The implicit-IV transform -----------------------------------------*
462  *
463  * The v0 transform makes everything explicit.  There's an IV because the
464  * cipher needs an IV; there's a sequence number because replay prevention
465  * needs a sequence number.
466  *
467  * This new transform works rather differently.  We make use of a block
468  * cipher to encrypt the sequence number, and use that as the IV.  We
469  * transmit the sequence number in the clear, as before.  This reduces
470  * overhead; and it's not a significant privacy leak because the adversary
471  * can see the order in which the messages are transmitted -- i.e., the
472  * sequence numbers are almost completely predictable anyway.
473  *
474  * So, a MAC is computed over
475  *
476  *              +------+ +------+------...------+
477  *              | type | | seq  |   ciphertext  |
478  *              +------+ +------+------...------+
479  *                 32       32         sz
480  *
481  * and we actually transmit the following as the cryptogram.
482  *
483  *              +---...---+------+------...------+
484  *              |   tag   | seq  |   ciphertext  |
485  *              +---...---+------+------...------+
486  *                 tagsz     32         sz
487  */
488
489 typedef struct iiv_algs {
490   bulkalgs _b;
491   gencomp_algs ga;
492   const gccipher *b; size_t bksz;
493 } iiv_algs;
494
495 typedef struct iiv_ctx {
496   bulkctx _b;
497   size_t tagsz;
498   struct {
499     gcipher *c, *b;
500     gmac *m;
501   } d[NDIR];
502 } iiv_ctx;
503
504
505 static bulkalgs *iiv_getalgs(const algswitch *asw, dstr *e,
506                             key_file *kf, key *k)
507 {
508   iiv_algs *a = CREATE(iiv_algs);
509   dstr d = DSTR_INIT, dd = DSTR_INIT;
510   const char *p;
511   char *q;
512
513   if (gencomp_getalgs(&a->ga, asw, e, kf, k)) goto fail;
514
515   if ((p = key_getattr(kf, k, "blkc")) == 0) {
516     dstr_puts(&dd, a->ga.c->name);
517     if ((q = strrchr(dd.buf, '-')) != 0) *q = 0;
518     p = dd.buf;
519   }
520   dstr_putf(&d, "%s-ecb", p);
521   if ((a->b = gcipher_byname(d.buf)) == 0) {
522     a_format(e, "unknown-blkc", "%s", p, A_END);
523     goto fail;
524   }
525
526   dstr_destroy(&d); dstr_destroy(&dd);
527   return (&a->_b);
528 fail:
529   dstr_destroy(&d); dstr_destroy(&dd);
530   DESTROY(a);
531   return (0);
532 }
533
534 #ifndef NTRACE
535 static void iiv_tracealgs(const bulkalgs *aa)
536 {
537   const iiv_algs *a = (const iiv_algs *)aa;
538
539   gencomp_tracealgs(&a->ga);
540   trace(T_CRYPTO, "crypto: blkc = %.*s", strlen(a->b->name) - 4, a->b->name);
541 }
542 #endif
543
544 static int iiv_checkalgs(bulkalgs *aa, const algswitch *asw, dstr *e)
545 {
546   iiv_algs *a = (iiv_algs *)aa;
547
548   if (gencomp_checkalgs(&a->ga, asw, e)) return (-1);
549
550   if ((a->bksz = keysz(asw->hashsz, a->b->keysz)) == 0) {
551     a_format(e, "blkc", "%.*s", strlen(a->b->name) - 4, a->b->name,
552              "no-key-size", "%lu", (unsigned long)asw->hashsz,
553              A_END);
554     return (-1);
555   }
556   if (a->b->blksz < a->ga.c->blksz) {
557     a_format(e, "blkc", "%.*s", strlen(a->b->name) - 4, a->b->name,
558              "blksz-insufficient", A_END);
559     return (-1);
560   }
561   return (0);
562 }
563
564 static int iiv_samealgsp(const bulkalgs *aa, const bulkalgs *bb)
565 {
566   const iiv_algs *a = (const iiv_algs *)aa, *b = (const iiv_algs *)bb;
567   return (gencomp_samealgsp(&a->ga, &b->ga) && a->b == b->b);
568 }
569
570 static void iiv_alginfo(const bulkalgs *aa, admin *adm)
571 {
572   const iiv_algs *a = (const iiv_algs *)aa;
573   gencomp_alginfo(&a->ga, adm);
574   a_info(adm,
575          "blkc=%.*s", strlen(a->b->name) - 4, a->b->name,
576          "blkc-keysz=%lu", (unsigned long)a->bksz,
577          "blkc-blksz=%lu", (unsigned long)a->b->blksz,
578          A_END);
579 }
580
581 static size_t iiv_overhead(const bulkalgs *aa)
582   { const iiv_algs *a = (const iiv_algs *)aa; return (a->ga.tagsz + SEQSZ); }
583
584 static size_t iiv_expsz(const bulkalgs *aa)
585 {
586   const iiv_algs *a = (const iiv_algs *)aa;
587   return (gencomp_expsz(&a->ga));
588 }
589
590 static bulkctx *iiv_genkeys(const bulkalgs *aa, const struct rawkey *rk)
591 {
592   const iiv_algs *a = (const iiv_algs *)aa;
593   iiv_ctx *bc = CREATE(iiv_ctx);
594   octet k[MAXHASHSZ];
595   int i;
596
597   bc->tagsz = a->ga.tagsz;
598   for (i = 0; i < NDIR; i++) {
599     ks_derivekey(k, a->ga.cksz, rk, i, "encryption");
600     bc->d[i].c = GC_INIT(a->ga.c, k, a->ga.cksz);
601     ks_derivekey(k, a->bksz, rk, i, "blkc");
602     bc->d[i].b = GC_INIT(a->b, k, a->bksz);
603     ks_derivekey(k, a->ga.mksz, rk, i, "integrity");
604     bc->d[i].m = GM_KEY(a->ga.m, k, a->ga.mksz);
605   }
606   return (&bc->_b);
607 }
608
609 static bulkchal *iiv_genchal(const bulkalgs *aa)
610 {
611   const iiv_algs *a = (const iiv_algs *)aa;
612   return (gencomp_genchal(&a->ga));
613 }
614 #define iiv_chaltag gencomp_chaltag
615 #define iiv_chalvrf gencomp_chalvrf
616 #define iiv_freechal gencomp_freechal
617
618 static void iiv_freealgs(bulkalgs *aa)
619   { iiv_algs *a = (iiv_algs *)aa; DESTROY(a); }
620
621 static void iiv_freectx(bulkctx *bbc)
622 {
623   iiv_ctx *bc = (iiv_ctx *)bbc;
624   int i;
625
626   for (i = 0; i < NDIR; i++) {
627     GC_DESTROY(bc->d[i].c);
628     GC_DESTROY(bc->d[i].b);
629     GM_DESTROY(bc->d[i].m);
630   }
631   DESTROY(bc);
632 }
633
634 #define TRACE_PRESEQ(qseq, ivsz) do { IF_TRACING(T_KEYSET, {            \
635   trace_block(T_CRYPTO, "crypto: IV derivation input", (qseq), (ivsz)); \
636 }) } while (0)
637
638 static int iiv_encrypt(bulkctx *bbc, unsigned ty,
639                        buf *b, buf *bb, uint32 seq)
640 {
641   iiv_ctx *bc = (iiv_ctx *)bbc;
642   ghash *h;
643   gcipher *c = bc->d[DIR_OUT].c, *blkc = bc->d[DIR_OUT].b;
644   const octet *p = BCUR(b);
645   size_t sz = BLEFT(b);
646   octet *qmac, *qseq, *qpk;
647   size_t ivsz = GC_CLASS(c)->blksz, blkcsz = GC_CLASS(blkc)->blksz;
648   size_t tagsz = bc->tagsz;
649   octet t[4];
650
651   /* --- Determine the ciphertext layout --- */
652
653   if (buf_ensure(bb, tagsz + SEQSZ + sz)) return (0);
654   qmac = BCUR(bb); qseq = qmac + tagsz; qpk = qseq + SEQSZ;
655   BSTEP(bb, tagsz + SEQSZ + sz);
656
657   /* --- Store the type --- *
658    *
659    * This isn't transmitted, but it's covered by the MAC.
660    */
661
662   STORE32(t, ty);
663
664   /* --- Store the sequence number --- */
665
666   STORE32(qseq, seq);
667
668   /* --- Establish an initialization vector if necessary --- */
669
670   if (ivsz) {
671     memset(buf_u, 0, blkcsz - SEQSZ);
672     memcpy(buf_u + blkcsz - SEQSZ, qseq, SEQSZ);
673     TRACE_PRESEQ(buf_u, ivsz);
674     GC_ENCRYPT(blkc, buf_u, buf_u, blkcsz);
675     GC_SETIV(c, buf_u);
676     TRACE_IV(buf_u, ivsz);
677   }
678
679   /* --- Encrypt the packet --- */
680
681   GC_ENCRYPT(c, p, qpk, sz);
682   TRACE_CT(qpk, sz);
683
684   /* --- Compute a MAC over type, sequence number, and ciphertext --- */
685
686   if (tagsz) {
687     h = GM_INIT(bc->d[DIR_OUT].m);
688     GH_HASH(h, t, sizeof(t));
689     GH_HASH(h, qseq, SEQSZ + sz);
690     memcpy(qmac, GH_DONE(h, 0), tagsz);
691     GH_DESTROY(h);
692     TRACE_MAC(qmac, tagsz);
693   }
694
695   /* --- We're done --- */
696
697   return (0);
698 }
699
700 static int iiv_decrypt(bulkctx *bbc, unsigned ty,
701                        buf *b, buf *bb, uint32 *seq)
702 {
703   iiv_ctx *bc = (iiv_ctx *)bbc;
704   const octet *pmac, *pseq, *ppk;
705   size_t psz = BLEFT(b);
706   size_t sz;
707   octet *q = BCUR(bb);
708   ghash *h;
709   gcipher *c = bc->d[DIR_IN].c, *blkc = bc->d[DIR_IN].b;
710   size_t ivsz = GC_CLASS(c)->blksz, blkcsz = GC_CLASS(blkc)->blksz;
711   size_t tagsz = bc->tagsz;
712   octet t[4];
713
714   /* --- Break up the packet into its components --- */
715
716   if (psz < SEQSZ + tagsz) {
717     T( trace(T_KEYSET, "keyset: block too small for keyset"); )
718     return (KSERR_MALFORMED);
719   }
720   sz = psz - SEQSZ - tagsz;
721   pmac = BCUR(b); pseq = pmac + tagsz; ppk = pseq + SEQSZ;
722   STORE32(t, ty);
723
724   /* --- Verify the MAC on the packet --- */
725
726   if (tagsz) {
727     h = GM_INIT(bc->d[DIR_IN].m);
728     GH_HASH(h, t, sizeof(t));
729     GH_HASH(h, pseq, SEQSZ + sz);
730     CHECK_MAC(h, pmac, tagsz);
731   }
732
733   /* --- Decrypt the packet --- */
734
735   if (ivsz) {
736     memset(buf_u, 0, blkcsz - SEQSZ);
737     memcpy(buf_u + blkcsz - SEQSZ, pseq, SEQSZ);
738     TRACE_PRESEQ(buf_u, ivsz);
739     GC_ENCRYPT(blkc, buf_u, buf_u, blkcsz);
740     GC_SETIV(c, buf_u);
741     TRACE_IV(buf_u, ivsz);
742   }
743   GC_DECRYPT(c, ppk, q, sz);
744
745   /* --- Finished --- */
746
747   *seq = LOAD32(pseq);
748   BSTEP(bb, sz);
749   return (0);
750 }
751
752 /*----- Bulk crypto transform table ---------------------------------------*/
753
754 const bulkops bulktab[] = {
755
756 #define COMMA ,
757
758 #define BULK(name, pre)                                                 \
759   { name, pre##_getalgs, T( pre##_tracealgs COMMA )                     \
760     pre##_checkalgs, pre##_samealgsp,                                   \
761     pre##_alginfo, pre##_overhead, pre##_expsz,                         \
762     pre##_genkeys, pre##_genchal, pre##_freealgs,                       \
763     pre##_encrypt, pre##_decrypt, pre##_freectx,                        \
764     pre##_chaltag, pre##_chalvrf, pre##_freechal }
765
766   BULK("v0", v0),
767   BULK("iiv", iiv),
768
769 #undef BULK
770   { 0 }
771 };
772
773 /*----- That's all, folks -------------------------------------------------*/