chiark / gitweb /
svc/conntrack.in: Maintain config groups in a dictionary.
[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 it under
13  * the terms of the GNU General Public License as published by the Free
14  * Software Foundation; either version 3 of the License, or (at your
15  * option) any later version.
16  *
17  * TrIPE is distributed in the hope that it will be useful, but WITHOUT
18  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20  * for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with TrIPE.  If not, see <https://www.gnu.org/licenses/>.
24  */
25
26 /*----- Header files ------------------------------------------------------*/
27
28 #include "tripe.h"
29
30 /*----- Utilities ---------------------------------------------------------*/
31
32 #define SEQSZ 4                         /* Size of sequence number packet */
33
34 #define TRACE_IV(qiv, ivsz) do { IF_TRACING(T_KEYSET, {                 \
35   trace_block(T_CRYPTO, "crypto: initialization vector",                \
36               (qiv), (ivsz));                                           \
37 }) } while (0)
38
39 #define TRACE_CT(qpk, sz) do { IF_TRACING(T_KEYSET, {                   \
40   trace_block(T_CRYPTO, "crypto: encrypted packet", (qpk), (sz));       \
41 }) } while (0)
42
43 #define TRACE_MAC(qmac, tagsz) do { IF_TRACING(T_KEYSET, {              \
44   trace_block(T_CRYPTO, "crypto: computed MAC", (qmac), (tagsz));       \
45 }) } while (0)
46
47 #define TRACE_MACERR(pmac, tagsz) do { IF_TRACING(T_KEYSET, {           \
48   trace(T_KEYSET, "keyset: incorrect MAC: decryption failed");          \
49   trace_block(T_CRYPTO, "crypto: expected MAC", (pmac), (tagsz));       \
50 }) } while (0)
51
52 /*----- Common functionality for generic-composition transforms -----------*/
53
54 #define CHECK_MAC(h, pmac, tagsz) do {                                  \
55   ghash *_h = (h);                                                      \
56   const octet *_pmac = (pmac);                                          \
57   size_t _tagsz = (tagsz);                                              \
58   octet *_mac = GH_DONE(_h, 0);                                         \
59   int _eq = ct_memeq(_mac, _pmac, _tagsz);                              \
60   TRACE_MAC(_mac, _tagsz);                                              \
61   GH_DESTROY(_h);                                                       \
62   if (!_eq) {                                                           \
63     TRACE_MACERR(_pmac, _tagsz);                                        \
64     return (KSERR_DECRYPT);                                             \
65   }                                                                     \
66 } while (0)
67
68 typedef struct gencomp_algs {
69   const gccipher *c; size_t cksz;
70   const gcmac *m; size_t mksz; size_t tagsz;
71 } gencomp_algs;
72
73 typedef struct gencomp_chal {
74   bulkchal _b;
75   gmac *m;
76 } gencomp_chal;
77
78 static int gencomp_getalgs(gencomp_algs *a, const algswitch *asw,
79                            dstr *e, key_file *kf, key *k)
80 {
81   const char *p;
82   char *q, *qq;
83   unsigned long n;
84   dstr d = DSTR_INIT;
85   int rc = -1;
86
87   /* --- Symmetric encryption --- */
88
89   if ((p = key_getattr(kf, k, "cipher")) == 0) p = "blowfish-cbc";
90   if ((a->c = gcipher_byname(p)) == 0) {
91     a_format(e, "unknown-cipher", "%s", p, A_END);
92     goto done;
93   }
94
95   /* --- Message authentication --- */
96
97   if ((p = key_getattr(kf, k, "mac")) != 0) {
98     dstr_reset(&d);
99     dstr_puts(&d, p);
100     if ((q = strrchr(d.buf, '/')) != 0)
101       *q++ = 0;
102     if ((a->m = gmac_byname(d.buf)) == 0) {
103       a_format(e, "unknown-mac", "%s", d.buf, A_END);
104       goto done;
105     }
106     if (!q)
107       a->tagsz = a->m->hashsz;
108     else {
109       n = strtoul(q, &qq, 0);
110       if (*qq)  {
111         a_format(e, "bad-tag-length-string", "%s", q, A_END);
112         goto done;
113       }
114       if (n%8 || n/8 > a->m->hashsz) {
115         a_format(e, "bad-tag-length", "%lu", n, A_END);
116         goto done;
117       }
118       a->tagsz = n/8;
119     }
120   } else {
121     dstr_reset(&d);
122     dstr_putf(&d, "%s-hmac", asw->h->name);
123     if ((a->m = gmac_byname(d.buf)) == 0) {
124       a_format(e, "no-hmac-for-hash", "%s", asw->h->name, A_END);
125       goto done;
126     }
127     a->tagsz = asw->h->hashsz/2;
128   }
129
130   rc = 0;
131 done:
132   dstr_destroy(&d);
133   return (rc);
134 }
135
136 #ifndef NTRACE
137 static void gencomp_tracealgs(const gencomp_algs *a)
138 {
139   trace(T_CRYPTO, "crypto: cipher = %s", a->c->name);
140   trace(T_CRYPTO, "crypto: mac = %s/%lu",
141         a->m->name, (unsigned long)a->tagsz * 8);
142 }
143 #endif
144
145 static int gencomp_checkalgs(gencomp_algs *a, const algswitch *asw, dstr *e)
146 {
147   /* --- Derive the key sizes --- *
148    *
149    * Must ensure that we have non-empty keys.  This isn't ideal, but it
150    * provides a handy sanity check.  Also must be based on a 64- or 128-bit
151    * block cipher or we can't do the data expiry properly.
152    */
153
154   if ((a->cksz = keysz(asw->hashsz, a->c->keysz)) == 0) {
155     a_format(e, "cipher", "%s", a->c->name,
156              "no-key-size", "%lu", (unsigned long)asw->hashsz,
157              A_END);
158     return (-1);
159   }
160   if ((a->mksz = keysz(asw->hashsz, a->m->keysz)) == 0) {
161     a_format(e, "mac", "%s", a->m->name,
162              "no-key-size", "%lu", (unsigned long)asw->hashsz,
163              A_END);
164     return (-1);
165   }
166
167   return (0);
168 }
169
170 static void gencomp_alginfo(const gencomp_algs *a, admin *adm)
171 {
172   a_info(adm,
173          "cipher=%s", a->c->name,
174          "cipher-keysz=%lu", (unsigned long)a->cksz,
175          "cipher-blksz=%lu", (unsigned long)a->c->blksz,
176          A_END);
177   a_info(adm,
178          "mac=%s", a->m->name,
179          "mac-keysz=%lu", (unsigned long)a->mksz,
180          "mac-tagsz=%lu", (unsigned long)a->tagsz,
181          A_END);
182 }
183
184 static int gencomp_samealgsp(const gencomp_algs *a, const gencomp_algs *aa)
185 {
186   return (a->c == aa->c &&
187           a->m == aa->m && a->tagsz == aa->tagsz);
188 }
189
190 static size_t gencomp_expsz(const gencomp_algs *a)
191   { return (a->c->blksz < 16 ? MEG(64) : MEG(2048)); }
192
193 static bulkchal *gencomp_genchal(const gencomp_algs *a)
194 {
195   gencomp_chal *gc = CREATE(gencomp_chal);
196
197   rand_get(RAND_GLOBAL, buf_t, a->mksz);
198   gc->m = GM_KEY(a->m, buf_t, a->mksz);
199   gc->_b.tagsz = a->tagsz;
200   IF_TRACING(T_CHAL, {
201     trace(T_CHAL, "chal: generated new challenge key");
202     trace_block(T_CRYPTO, "chal: new key", buf_t, a->mksz);
203   })
204   return (&gc->_b);
205 }
206
207 static int gencomp_chaltag(bulkchal *bc, const void *m, size_t msz, void *t)
208 {
209   gencomp_chal *gc = (gencomp_chal *)bc;
210   ghash *h = GM_INIT(gc->m);
211
212   GH_HASH(h, m, msz);
213   memcpy(t, GH_DONE(h, 0), bc->tagsz);
214   GH_DESTROY(h);
215   return (0);
216 }
217
218 static int gencomp_chalvrf(bulkchal *bc, const void *m, size_t msz,
219                            const void *t)
220 {
221   gencomp_chal *gc = (gencomp_chal *)bc;
222   ghash *h = GM_INIT(gc->m);
223   int ok;
224
225   GH_HASH(h, m, msz);
226   ok = ct_memeq(GH_DONE(h, 0), t, gc->_b.tagsz);
227   GH_DESTROY(h);
228   return (ok ? 0 : -1);
229 }
230
231 static void gencomp_freechal(bulkchal *bc)
232   { gencomp_chal *gc = (gencomp_chal *)bc; GM_DESTROY(gc->m); DESTROY(gc); }
233
234 /*----- The original transform --------------------------------------------*
235  *
236  * We generate a random initialization vector (if the cipher needs one).  We
237  * encrypt the input message with the cipher, and format the type, sequence
238  * number, IV, and ciphertext as follows.
239  *
240  *              +------+ +------+---...---+------...------+
241  *              | type | | seq  |   iv    |   ciphertext  |
242  *              +------+ +------+---...---+------...------+
243  *                 32       32     blksz         sz
244  *
245  * All of this is fed into the MAC to compute a tag.  The type is not
246  * transmitted: the other end knows what type of message it expects, and the
247  * type is only here to prevent us from being confused because some other
248  * kind of ciphertext has been substituted.  The tag is prepended to the
249  * remainder, to yield the finished cryptogram, as follows.
250  *
251  *              +---...---+------+---...---+------...------+
252  *              |   tag   | seq  |   iv    |   ciphertext  |
253  *              +---...---+------+---...---+------...------+
254  *                 tagsz     32     blksz         sz
255  *
256  * Decryption: checks the overall size, verifies the tag, then decrypts the
257  * ciphertext and extracts the sequence number.
258  */
259
260 typedef struct v0_algs {
261   bulkalgs _b;
262   gencomp_algs ga;
263 } v0_algs;
264
265 typedef struct v0_ctx {
266   bulkctx _b;
267   size_t tagsz;
268   struct {
269     gcipher *c;
270     gmac *m;
271   } d[NDIR];
272 } v0_ctx;
273
274 static bulkalgs *v0_getalgs(const algswitch *asw, dstr *e,
275                             key_file *kf, key *k)
276 {
277   v0_algs *a = CREATE(v0_algs);
278   if (gencomp_getalgs(&a->ga, asw, e, kf, k)) { DESTROY(a); return (0); }
279   return (&a->_b);
280 }
281
282 #ifndef NTRACE
283 static void v0_tracealgs(const bulkalgs *aa)
284   { const v0_algs *a = (const v0_algs *)aa; gencomp_tracealgs(&a->ga); }
285 #endif
286
287 static int v0_checkalgs(bulkalgs *aa, const algswitch *asw, dstr *e)
288 {
289   v0_algs *a = (v0_algs *)aa;
290   if (gencomp_checkalgs(&a->ga, asw, e)) return (-1);
291   return (0);
292 }
293
294 static int v0_samealgsp(const bulkalgs *aa, const bulkalgs *bb)
295 {
296   const v0_algs *a = (const v0_algs *)aa, *b = (const v0_algs *)bb;
297   return (gencomp_samealgsp(&a->ga, &b->ga));
298 }
299
300 static void v0_alginfo(const bulkalgs *aa, admin *adm)
301   { const v0_algs *a = (const v0_algs *)aa; gencomp_alginfo(&a->ga, adm); }
302
303 static size_t v0_overhead(const bulkalgs *aa)
304 {
305   const v0_algs *a = (const v0_algs *)aa;
306   return (a->ga.tagsz + SEQSZ + a->ga.c->blksz);
307 }
308
309 static size_t v0_expsz(const bulkalgs *aa)
310   { const v0_algs *a = (const v0_algs *)aa; return (gencomp_expsz(&a->ga)); }
311
312 static bulkctx *v0_genkeys(const bulkalgs *aa, const struct rawkey *rk)
313 {
314   const v0_algs *a = (const v0_algs *)aa;
315   v0_ctx *bc = CREATE(v0_ctx);
316   octet k[MAXHASHSZ];
317   int i;
318
319   bc->tagsz = a->ga.tagsz;
320   for (i = 0; i < NDIR; i++) {
321     ks_derivekey(k, a->ga.cksz, rk, i, "encryption");
322     bc->d[i].c = GC_INIT(a->ga.c, k, a->ga.cksz);
323     ks_derivekey(k, a->ga.mksz, rk, i, "integrity");
324     bc->d[i].m = GM_KEY(a->ga.m, k, a->ga.mksz);
325   }
326   return (&bc->_b);
327 }
328
329 static bulkchal *v0_genchal(const bulkalgs *aa)
330 {
331   const v0_algs *a = (const v0_algs *)aa;
332   return (gencomp_genchal(&a->ga));
333 }
334 #define v0_chaltag gencomp_chaltag
335 #define v0_chalvrf gencomp_chalvrf
336 #define v0_freechal gencomp_freechal
337
338 static void v0_freealgs(bulkalgs *aa)
339   { v0_algs *a = (v0_algs *)aa; DESTROY(a); }
340
341 static void v0_freectx(bulkctx *bbc)
342 {
343   v0_ctx *bc = (v0_ctx *)bbc;
344   int i;
345
346   for (i = 0; i < NDIR; i++) {
347     GC_DESTROY(bc->d[i].c);
348     GM_DESTROY(bc->d[i].m);
349   }
350   DESTROY(bc);
351 }
352
353 static int v0_encrypt(bulkctx *bbc, unsigned ty,
354                       buf *b, buf *bb, uint32 seq)
355 {
356   v0_ctx *bc = (v0_ctx *)bbc;
357   ghash *h;
358   gcipher *c = bc->d[DIR_OUT].c;
359   const octet *p = BCUR(b);
360   size_t sz = BLEFT(b);
361   octet *qmac, *qseq, *qiv, *qpk;
362   size_t ivsz = GC_CLASS(c)->blksz;
363   size_t tagsz = bc->tagsz;
364   octet t[4];
365
366   /* --- Determine the ciphertext layout --- */
367
368   if (buf_ensure(bb, tagsz + SEQSZ + ivsz + sz)) return (0);
369   qmac = BCUR(bb); qseq = qmac + tagsz; qiv = qseq + SEQSZ; qpk = qiv + ivsz;
370   BSTEP(bb, tagsz + SEQSZ + ivsz + sz);
371
372   /* --- Store the type --- *
373    *
374    * This isn't transmitted, but it's covered by the MAC.
375    */
376
377   STORE32(t, ty);
378
379   /* --- Store the sequence number --- */
380
381   STORE32(qseq, seq);
382
383   /* --- Establish an initialization vector if necessary --- */
384
385   if (ivsz) {
386     rand_get(RAND_GLOBAL, qiv, ivsz);
387     GC_SETIV(c, qiv);
388     TRACE_IV(qiv, ivsz);
389   }
390
391   /* --- Encrypt the packet --- */
392
393   GC_ENCRYPT(c, p, qpk, sz);
394   TRACE_CT(qpk, sz);
395
396   /* --- Compute a MAC over type, sequence number, IV, and ciphertext --- */
397
398   if (tagsz) {
399     h = GM_INIT(bc->d[DIR_OUT].m);
400     GH_HASH(h, t, sizeof(t));
401     GH_HASH(h, qseq, SEQSZ + ivsz + sz);
402     memcpy(qmac, GH_DONE(h, 0), tagsz);
403     GH_DESTROY(h);
404     TRACE_MAC(qmac, tagsz);
405   }
406
407   /* --- We're done --- */
408
409   return (0);
410 }
411
412 static int v0_decrypt(bulkctx *bbc, unsigned ty,
413                       buf *b, buf *bb, uint32 *seq)
414 {
415   v0_ctx *bc = (v0_ctx *)bbc;
416   const octet *pmac, *piv, *pseq, *ppk;
417   size_t psz = BLEFT(b);
418   size_t sz;
419   octet *q = BCUR(bb);
420   ghash *h;
421   gcipher *c = bc->d[DIR_IN].c;
422   size_t ivsz = GC_CLASS(c)->blksz;
423   size_t tagsz = bc->tagsz;
424   octet t[4];
425
426   /* --- Break up the packet into its components --- */
427
428   if (psz < ivsz + SEQSZ + tagsz) {
429     T( trace(T_KEYSET, "keyset: block too small for keyset"); )
430     return (KSERR_MALFORMED);
431   }
432   sz = psz - ivsz - SEQSZ - tagsz;
433   pmac = BCUR(b); pseq = pmac + tagsz; piv = pseq + SEQSZ; ppk = piv + ivsz;
434   STORE32(t, ty);
435
436   /* --- Verify the MAC on the packet --- */
437
438   if (tagsz) {
439     h = GM_INIT(bc->d[DIR_IN].m);
440     GH_HASH(h, t, sizeof(t));
441     GH_HASH(h, pseq, SEQSZ + ivsz + sz);
442     CHECK_MAC(h, pmac, tagsz);
443   }
444
445   /* --- Decrypt the packet --- */
446
447   if (ivsz) {
448     TRACE_IV(piv, ivsz);
449     GC_SETIV(c, piv);
450   }
451   GC_DECRYPT(c, ppk, q, sz);
452
453   /* --- Finished --- */
454
455   *seq = LOAD32(pseq);
456   BSTEP(bb, sz);
457   return (0);
458 }
459
460 /*----- The implicit-IV transform -----------------------------------------*
461  *
462  * The v0 transform makes everything explicit.  There's an IV because the
463  * cipher needs an IV; there's a sequence number because replay prevention
464  * needs a sequence number.
465  *
466  * This new transform works rather differently.  We make use of a block
467  * cipher to encrypt the sequence number, and use that as the IV.  We
468  * transmit the sequence number in the clear, as before.  This reduces
469  * overhead; and it's not a significant privacy leak because the adversary
470  * can see the order in which the messages are transmitted -- i.e., the
471  * sequence numbers are almost completely predictable anyway.
472  *
473  * So, a MAC is computed over
474  *
475  *              +------+ +------+------...------+
476  *              | type | | seq  |   ciphertext  |
477  *              +------+ +------+------...------+
478  *                 32       32         sz
479  *
480  * and we actually transmit the following as the cryptogram.
481  *
482  *              +---...---+------+------...------+
483  *              |   tag   | seq  |   ciphertext  |
484  *              +---...---+------+------...------+
485  *                 tagsz     32         sz
486  */
487
488 typedef struct iiv_algs {
489   bulkalgs _b;
490   gencomp_algs ga;
491   const gccipher *b; size_t bksz;
492 } iiv_algs;
493
494 typedef struct iiv_ctx {
495   bulkctx _b;
496   size_t tagsz;
497   struct {
498     gcipher *c, *b;
499     gmac *m;
500   } d[NDIR];
501 } iiv_ctx;
502
503
504 static bulkalgs *iiv_getalgs(const algswitch *asw, dstr *e,
505                             key_file *kf, key *k)
506 {
507   iiv_algs *a = CREATE(iiv_algs);
508   dstr d = DSTR_INIT, dd = DSTR_INIT;
509   const char *p;
510   char *q;
511
512   if (gencomp_getalgs(&a->ga, asw, e, kf, k)) goto fail;
513
514   if ((p = key_getattr(kf, k, "blkc")) == 0) {
515     dstr_puts(&dd, a->ga.c->name);
516     if ((q = strrchr(dd.buf, '-')) != 0) *q = 0;
517     p = dd.buf;
518   }
519   dstr_putf(&d, "%s-ecb", p);
520   if ((a->b = gcipher_byname(d.buf)) == 0) {
521     a_format(e, "unknown-blkc", "%s", p, A_END);
522     goto fail;
523   }
524
525   dstr_destroy(&d); dstr_destroy(&dd);
526   return (&a->_b);
527 fail:
528   dstr_destroy(&d); dstr_destroy(&dd);
529   DESTROY(a);
530   return (0);
531 }
532
533 #ifndef NTRACE
534 static void iiv_tracealgs(const bulkalgs *aa)
535 {
536   const iiv_algs *a = (const iiv_algs *)aa;
537
538   gencomp_tracealgs(&a->ga);
539   trace(T_CRYPTO,
540         "crypto: blkc = %.*s", (int)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 /*----- The NaCl box transform --------------------------------------------*
753  *
754  * This transform is very similar to the NaCl `crypto_secretbox' transform
755  * described in Bernstein, `Cryptography in NaCl', with the difference that,
756  * rather than using XSalsa20, we use either Salsa20/r or ChaChar, because we
757  * have no need of XSalsa20's extended nonce.  The default cipher is Salsa20.
758  *
759  * Salsa20 and ChaCha accept a 64-bit nonce.  The low 32 bits are the
760  * sequence number, and the high 32 bits are the type, both big-endian.
761  *
762  *              +------+------+
763  *              | seq  | type |
764  *              +------+------+
765  *                 32     32
766  *
767  * A stream is generated by concatenating the raw output blocks generated
768  * with this nonce and successive counter values starting from zero.  The
769  * first 32 bytes of the stream are used as a key for Poly1305: the first 16
770  * bytes are the universal hash key r, and the second 16 bytes are the mask
771  * value s.
772  *
773  *              +------+------+ +------...------+
774  *              |  r   |  s   | |   keystream   |
775  *              +------+------+ +------...------+
776  *                128    128           sz
777  *
778  * The remainder of the stream is XORed with the incoming plaintext to form a
779  * ciphertext with the same length.  The ciphertext (only) is then tagged
780  * using Poly1305.  The tag, sequence number, and ciphertext are concatenated
781  * in this order, and transmitted.
782  *
783  *
784  *              +---...---+------+------...------+
785  *              |   tag   | seq  |   ciphertext  |
786  *              +---...---+------+------...------+
787  *                  128     32          sz
788  *
789  * Note that there is no need to authenticate the type separately, since it
790  * was used to select the cipher nonce, and hence the Poly1305 key.  The
791  * Poly1305 tag length is fixed.
792  */
793
794 typedef struct naclbox_algs {
795   bulkalgs _b;
796   const gccipher *c; size_t cksz;
797 } naclbox_algs;
798
799 typedef struct naclbox_ctx {
800   bulkctx _b;
801   struct { gcipher *c; } d[NDIR];
802 } naclbox_ctx;
803
804
805 static bulkalgs *naclbox_getalgs(const algswitch *asw, dstr *e,
806                                  key_file *kf, key *k)
807 {
808   naclbox_algs *a = CREATE(naclbox_algs);
809   const char *p;
810   char *qq;
811   unsigned long n;
812
813   /* --- Collect the selected cipher and check that it's supported --- */
814
815   p = key_getattr(kf, k, "cipher");
816   if (!p || strcmp(p, "salsa20") == 0) a->c = &salsa20;
817   else if (strcmp(p, "salsa20/12") == 0) a->c = &salsa2012;
818   else if (strcmp(p, "salsa20/8") == 0) a->c = &salsa208;
819   else if (strcmp(p, "chacha20") == 0) a->c = &chacha20;
820   else if (strcmp(p, "chacha12") == 0) a->c = &chacha12;
821   else if (strcmp(p, "chacha8") == 0) a->c = &chacha8;
822   else {
823     a_format(e, "unknown-cipher", "%s", p, A_END);
824     goto fail;
825   }
826
827   /* --- Collect the selected MAC, and check the tag length --- */
828
829   p = key_getattr(kf, k, "mac");
830   if (!p)
831     ;
832   else if (strncmp(p, "poly1305", 8) != 0 || (p[8] && p[8] != '/')) {
833     a_format(e, "unknown-mac", "%s", p, A_END);
834     goto fail;
835   } else if (p[8] == '/') {
836     n = strtoul(p + 9, &qq, 0);
837     if (*qq) {
838       a_format(e, "bad-tag-length-string", "%s", p + 9, A_END);
839       goto fail;
840     }
841     if (n != 128) {
842       a_format(e, "bad-tag-length", "%lu", n, A_END);
843       goto fail;
844     }
845   }
846
847   return (&a->_b);
848 fail:
849   DESTROY(a);
850   return (0);
851 }
852
853 #ifndef NTRACE
854 static void naclbox_tracealgs(const bulkalgs *aa)
855 {
856   const naclbox_algs *a = (const naclbox_algs *)aa;
857
858   trace(T_CRYPTO, "crypto: cipher = %s", a->c->name);
859   trace(T_CRYPTO, "crypto: mac = poly1305/128");
860 }
861 #endif
862
863 static int naclbox_checkalgs(bulkalgs *aa, const algswitch *asw, dstr *e)
864 {
865   naclbox_algs *a = (naclbox_algs *)aa;
866
867   if ((a->cksz = keysz(asw->hashsz, a->c->keysz)) == 0) {
868     a_format(e, "cipher", "%s", a->c->name,
869              "no-key-size", "%lu", (unsigned long)asw->hashsz,
870              A_END);
871     return (-1);
872   }
873   return (0);
874 }
875
876 static int naclbox_samealgsp(const bulkalgs *aa, const bulkalgs *bb)
877 {
878   const naclbox_algs *a = (const naclbox_algs *)aa,
879     *b = (const naclbox_algs *)bb;
880   return (a->c == b->c);
881 }
882
883 static void naclbox_alginfo(const bulkalgs *aa, admin *adm)
884 {
885   const naclbox_algs *a = (const naclbox_algs *)aa;
886   a_info(adm, "cipher=%s", a->c->name, "cipher-keysz=32", A_END);
887   a_info(adm, "mac=poly1305", "mac-tagsz=16", A_END);
888 }
889
890 static size_t naclbox_overhead(const bulkalgs *aa)
891   { return (POLY1305_TAGSZ + SEQSZ); }
892
893 static size_t naclbox_expsz(const bulkalgs *aa)
894   { return (MEG(2048)); }
895
896 static bulkctx *naclbox_genkeys(const bulkalgs *aa, const struct rawkey *rk)
897 {
898   const naclbox_algs *a = (const naclbox_algs *)aa;
899   naclbox_ctx *bc = CREATE(naclbox_ctx);
900   octet k[MAXHASHSZ];
901   int i;
902
903   for (i = 0; i < NDIR; i++) {
904     ks_derivekey(k, a->cksz, rk, i, "encryption");
905     bc->d[i].c = GC_INIT(a->c, k, a->cksz);
906   }
907   return (&bc->_b);
908 }
909
910 typedef struct naclbox_chal {
911   bulkchal _b;
912   gcipher *c;
913 } naclbox_chal;
914
915 static bulkchal *naclbox_genchal(const bulkalgs *aa)
916 {
917   const naclbox_algs *a = (const naclbox_algs *)aa;
918   naclbox_chal *c = CREATE(naclbox_chal);
919   rand_get(RAND_GLOBAL, buf_t, a->cksz);
920   c->c = GC_INIT(a->c, buf_t, a->cksz);
921   IF_TRACING(T_CHAL, {
922     trace(T_CHAL, "chal: generated new challenge key");
923     trace_block(T_CRYPTO, "chal: new key", buf_t, a->cksz);
924   })
925   c->_b.tagsz = 16;
926   return (&c->_b);
927 }
928
929 static int naclbox_chaltag(bulkchal *bc, const void *m, size_t msz, void *t)
930 {
931   naclbox_chal *c = (naclbox_chal *)bc;
932   octet b0[SALSA20_NONCESZ];
933   assert(msz <= sizeof(b0));
934   memcpy(b0, m, msz); memset(b0 + msz, 0, sizeof(b0) - msz);
935   GC_SETIV(c->c, b0);
936   GC_ENCRYPT(c->c, 0, t, c->_b.tagsz);
937   return (0);
938 }
939
940 static int naclbox_chalvrf(bulkchal *bc, const void *m, size_t msz,
941                            const void *t)
942 {
943   naclbox_chal *c = (naclbox_chal *)bc;
944   octet b0[SALSA20_NONCESZ], b1[16];
945   assert(msz <= sizeof(b0)); assert(c->_b.tagsz <= sizeof(b1));
946   memcpy(b0, m, msz); memset(b0 + msz, 0, sizeof(b0) - msz);
947   GC_SETIV(c->c, b0);
948   GC_ENCRYPT(c->c, 0, b1, c->_b.tagsz);
949   return (ct_memeq(t, b1, c->_b.tagsz) ? 0 : -1);
950 }
951
952 static void naclbox_freechal(bulkchal *bc)
953   { naclbox_chal *c = (naclbox_chal *)bc; GC_DESTROY(c->c); DESTROY(c); }
954
955 static void naclbox_freealgs(bulkalgs *aa)
956   { naclbox_algs *a = (naclbox_algs *)aa; DESTROY(a); }
957
958 static void naclbox_freectx(bulkctx *bbc)
959 {
960   naclbox_ctx *bc = (naclbox_ctx *)bbc;
961   int i;
962
963   for (i = 0; i < NDIR; i++) GC_DESTROY(bc->d[i].c);
964   DESTROY(bc);
965 }
966
967 static int naclbox_encrypt(bulkctx *bbc, unsigned ty,
968                            buf *b, buf *bb, uint32 seq)
969 {
970   naclbox_ctx *bc = (naclbox_ctx *)bbc;
971   gcipher *c = bc->d[DIR_OUT].c;
972   poly1305_key polyk;
973   poly1305_ctx poly;
974   const octet *p = BCUR(b);
975   size_t sz = BLEFT(b);
976   octet *qmac, *qseq, *qpk;
977
978   /* --- Determine the ciphertext layout --- */
979
980   if (buf_ensure(bb, POLY1305_TAGSZ + SEQSZ + sz)) return (0);
981   qmac = BCUR(bb); qseq = qmac + POLY1305_TAGSZ; qpk = qseq + SEQSZ;
982   BSTEP(bb, POLY1305_TAGSZ + SEQSZ + sz);
983
984   /* --- Construct and set the nonce --- */
985
986   STORE32(qseq, seq);
987   memcpy(buf_u, qseq, SEQSZ); STORE32(buf_u + SEQSZ, ty);
988   GC_SETIV(c, buf_u);
989   TRACE_IV(buf_u, SALSA20_NONCESZ);
990
991   /* --- Determine the MAC key --- */
992
993   GC_ENCRYPT(c, 0, buf_u, POLY1305_KEYSZ + POLY1305_MASKSZ);
994   poly1305_keyinit(&polyk, buf_u, POLY1305_KEYSZ);
995   poly1305_macinit(&poly, &polyk, buf_u + POLY1305_KEYSZ);
996
997   /* --- Encrypt the message --- */
998
999   GC_ENCRYPT(c, p, qpk, sz);
1000   TRACE_CT(qpk, sz);
1001
1002   /* --- Compute the MAC --- */
1003
1004   poly1305_hash(&poly, qpk, sz);
1005   poly1305_done(&poly, qmac);
1006   TRACE_MAC(qmac, POLY1305_TAGSZ);
1007
1008   /* --- We're done --- */
1009
1010   return (0);
1011 }
1012
1013 static int naclbox_decrypt(bulkctx *bbc, unsigned ty,
1014                        buf *b, buf *bb, uint32 *seq)
1015 {
1016   naclbox_ctx *bc = (naclbox_ctx *)bbc;
1017   gcipher *c = bc->d[DIR_IN].c;
1018   poly1305_key polyk;
1019   poly1305_ctx poly;
1020   const octet *pmac, *pseq, *ppk;
1021   size_t psz = BLEFT(b);
1022   size_t sz;
1023   octet *q = BCUR(bb);
1024
1025   /* --- Break up the packet into its components --- */
1026
1027   if (psz < SEQSZ + POLY1305_TAGSZ) {
1028     T( trace(T_KEYSET, "keyset: block too small for keyset"); )
1029     return (KSERR_MALFORMED);
1030   }
1031   sz = psz - SEQSZ - POLY1305_TAGSZ;
1032   pmac = BCUR(b); pseq = pmac + POLY1305_TAGSZ; ppk = pseq + SEQSZ;
1033
1034   /* --- Construct and set the nonce --- */
1035
1036   memcpy(buf_u, pseq, SEQSZ); STORE32(buf_u + SEQSZ, ty);
1037   GC_SETIV(c, buf_u);
1038   TRACE_IV(buf_u, SALSA20_NONCESZ);
1039
1040   /* --- Determine the MAC key --- */
1041
1042   GC_ENCRYPT(c, 0, buf_u, POLY1305_KEYSZ + POLY1305_MASKSZ);
1043   poly1305_keyinit(&polyk, buf_u, POLY1305_KEYSZ);
1044   poly1305_macinit(&poly, &polyk, buf_u + POLY1305_KEYSZ);
1045
1046   /* --- Verify the MAC on the packet --- */
1047
1048   poly1305_hash(&poly, ppk, sz);
1049   poly1305_done(&poly, buf_u);
1050   TRACE_MAC(buf_u, POLY1305_TAGSZ);
1051   if (!ct_memeq(buf_u, pmac, POLY1305_TAGSZ)) {
1052     TRACE_MACERR(pmac, POLY1305_TAGSZ);
1053     return (KSERR_DECRYPT);
1054   }
1055
1056   /* --- Decrypt the packet --- */
1057
1058   GC_DECRYPT(c, ppk, q, sz);
1059
1060   /* --- Finished --- */
1061
1062   *seq = LOAD32(pseq);
1063   BSTEP(bb, sz);
1064   return (0);
1065 }
1066
1067 /*----- Bulk crypto transform table ---------------------------------------*/
1068
1069 const bulkops bulktab[] = {
1070
1071 #define COMMA ,
1072
1073 #define BULK(name, pre)                                                 \
1074   { name, pre##_getalgs, T( pre##_tracealgs COMMA )                     \
1075     pre##_checkalgs, pre##_samealgsp,                                   \
1076     pre##_alginfo, pre##_overhead, pre##_expsz,                         \
1077     pre##_genkeys, pre##_genchal, pre##_freealgs,                       \
1078     pre##_encrypt, pre##_decrypt, pre##_freectx,                        \
1079     pre##_chaltag, pre##_chalvrf, pre##_freechal }
1080
1081   BULK("v0", v0),
1082   BULK("iiv", iiv),
1083   BULK("naclbox", naclbox),
1084
1085 #undef BULK
1086   { 0 }
1087 };
1088
1089 /*----- That's all, folks -------------------------------------------------*/