chiark / gitweb /
server/admin.c: Publish `corked' and `mobile' flags in `peerinfo'.
[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; size_t tagsz;
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, "crypto: blkc = %.*s", strlen(a->b->name) - 4, a->b->name);
540 }
541 #endif
542
543 static int iiv_checkalgs(bulkalgs *aa, const algswitch *asw, dstr *e)
544 {
545   iiv_algs *a = (iiv_algs *)aa;
546
547   if (gencomp_checkalgs(&a->ga, asw, e)) return (-1);
548
549   if ((a->bksz = keysz(asw->hashsz, a->b->keysz)) == 0) {
550     a_format(e, "blkc", "%.*s", strlen(a->b->name) - 4, a->b->name,
551              "no-key-size", "%lu", (unsigned long)asw->hashsz,
552              A_END);
553     return (-1);
554   }
555   if (a->b->blksz < a->ga.c->blksz) {
556     a_format(e, "blkc", "%.*s", strlen(a->b->name) - 4, a->b->name,
557              "blksz-insufficient", A_END);
558     return (-1);
559   }
560   return (0);
561 }
562
563 static int iiv_samealgsp(const bulkalgs *aa, const bulkalgs *bb)
564 {
565   const iiv_algs *a = (const iiv_algs *)aa, *b = (const iiv_algs *)bb;
566   return (gencomp_samealgsp(&a->ga, &b->ga) && a->b == b->b);
567 }
568
569 static void iiv_alginfo(const bulkalgs *aa, admin *adm)
570 {
571   const iiv_algs *a = (const iiv_algs *)aa;
572   gencomp_alginfo(&a->ga, adm);
573   a_info(adm,
574          "blkc=%.*s", strlen(a->b->name) - 4, a->b->name,
575          "blkc-keysz=%lu", (unsigned long)a->bksz,
576          "blkc-blksz=%lu", (unsigned long)a->b->blksz,
577          A_END);
578 }
579
580 static size_t iiv_overhead(const bulkalgs *aa)
581   { const iiv_algs *a = (const iiv_algs *)aa; return (a->ga.tagsz + SEQSZ); }
582
583 static size_t iiv_expsz(const bulkalgs *aa)
584 {
585   const iiv_algs *a = (const iiv_algs *)aa;
586   return (gencomp_expsz(&a->ga));
587 }
588
589 static bulkctx *iiv_genkeys(const bulkalgs *aa, const struct rawkey *rk)
590 {
591   const iiv_algs *a = (const iiv_algs *)aa;
592   iiv_ctx *bc = CREATE(iiv_ctx);
593   octet k[MAXHASHSZ];
594   int i;
595
596   bc->tagsz = a->ga.tagsz;
597   for (i = 0; i < NDIR; i++) {
598     ks_derivekey(k, a->ga.cksz, rk, i, "encryption");
599     bc->d[i].c = GC_INIT(a->ga.c, k, a->ga.cksz);
600     ks_derivekey(k, a->bksz, rk, i, "blkc");
601     bc->d[i].b = GC_INIT(a->b, k, a->bksz);
602     ks_derivekey(k, a->ga.mksz, rk, i, "integrity");
603     bc->d[i].m = GM_KEY(a->ga.m, k, a->ga.mksz);
604   }
605   return (&bc->_b);
606 }
607
608 static bulkchal *iiv_genchal(const bulkalgs *aa)
609 {
610   const iiv_algs *a = (const iiv_algs *)aa;
611   return (gencomp_genchal(&a->ga));
612 }
613 #define iiv_chaltag gencomp_chaltag
614 #define iiv_chalvrf gencomp_chalvrf
615 #define iiv_freechal gencomp_freechal
616
617 static void iiv_freealgs(bulkalgs *aa)
618   { iiv_algs *a = (iiv_algs *)aa; DESTROY(a); }
619
620 static void iiv_freectx(bulkctx *bbc)
621 {
622   iiv_ctx *bc = (iiv_ctx *)bbc;
623   int i;
624
625   for (i = 0; i < NDIR; i++) {
626     GC_DESTROY(bc->d[i].c);
627     GC_DESTROY(bc->d[i].b);
628     GM_DESTROY(bc->d[i].m);
629   }
630   DESTROY(bc);
631 }
632
633 #define TRACE_PRESEQ(qseq, ivsz) do { IF_TRACING(T_KEYSET, {            \
634   trace_block(T_CRYPTO, "crypto: IV derivation input", (qseq), (ivsz)); \
635 }) } while (0)
636
637 static int iiv_encrypt(bulkctx *bbc, unsigned ty,
638                        buf *b, buf *bb, uint32 seq)
639 {
640   iiv_ctx *bc = (iiv_ctx *)bbc;
641   ghash *h;
642   gcipher *c = bc->d[DIR_OUT].c, *blkc = bc->d[DIR_OUT].b;
643   const octet *p = BCUR(b);
644   size_t sz = BLEFT(b);
645   octet *qmac, *qseq, *qpk;
646   size_t ivsz = GC_CLASS(c)->blksz, blkcsz = GC_CLASS(blkc)->blksz;
647   size_t tagsz = bc->tagsz;
648   octet t[4];
649
650   /* --- Determine the ciphertext layout --- */
651
652   if (buf_ensure(bb, tagsz + SEQSZ + sz)) return (0);
653   qmac = BCUR(bb); qseq = qmac + tagsz; qpk = qseq + SEQSZ;
654   BSTEP(bb, tagsz + SEQSZ + sz);
655
656   /* --- Store the type --- *
657    *
658    * This isn't transmitted, but it's covered by the MAC.
659    */
660
661   STORE32(t, ty);
662
663   /* --- Store the sequence number --- */
664
665   STORE32(qseq, seq);
666
667   /* --- Establish an initialization vector if necessary --- */
668
669   if (ivsz) {
670     memset(buf_u, 0, blkcsz - SEQSZ);
671     memcpy(buf_u + blkcsz - SEQSZ, qseq, SEQSZ);
672     TRACE_PRESEQ(buf_u, ivsz);
673     GC_ENCRYPT(blkc, buf_u, buf_u, blkcsz);
674     GC_SETIV(c, buf_u);
675     TRACE_IV(buf_u, ivsz);
676   }
677
678   /* --- Encrypt the packet --- */
679
680   GC_ENCRYPT(c, p, qpk, sz);
681   TRACE_CT(qpk, sz);
682
683   /* --- Compute a MAC over type, sequence number, and ciphertext --- */
684
685   if (tagsz) {
686     h = GM_INIT(bc->d[DIR_OUT].m);
687     GH_HASH(h, t, sizeof(t));
688     GH_HASH(h, qseq, SEQSZ + sz);
689     memcpy(qmac, GH_DONE(h, 0), tagsz);
690     GH_DESTROY(h);
691     TRACE_MAC(qmac, tagsz);
692   }
693
694   /* --- We're done --- */
695
696   return (0);
697 }
698
699 static int iiv_decrypt(bulkctx *bbc, unsigned ty,
700                        buf *b, buf *bb, uint32 *seq)
701 {
702   iiv_ctx *bc = (iiv_ctx *)bbc;
703   const octet *pmac, *pseq, *ppk;
704   size_t psz = BLEFT(b);
705   size_t sz;
706   octet *q = BCUR(bb);
707   ghash *h;
708   gcipher *c = bc->d[DIR_IN].c, *blkc = bc->d[DIR_IN].b;
709   size_t ivsz = GC_CLASS(c)->blksz, blkcsz = GC_CLASS(blkc)->blksz;
710   size_t tagsz = bc->tagsz;
711   octet t[4];
712
713   /* --- Break up the packet into its components --- */
714
715   if (psz < SEQSZ + tagsz) {
716     T( trace(T_KEYSET, "keyset: block too small for keyset"); )
717     return (KSERR_MALFORMED);
718   }
719   sz = psz - SEQSZ - tagsz;
720   pmac = BCUR(b); pseq = pmac + tagsz; ppk = pseq + SEQSZ;
721   STORE32(t, ty);
722
723   /* --- Verify the MAC on the packet --- */
724
725   if (tagsz) {
726     h = GM_INIT(bc->d[DIR_IN].m);
727     GH_HASH(h, t, sizeof(t));
728     GH_HASH(h, pseq, SEQSZ + sz);
729     CHECK_MAC(h, pmac, tagsz);
730   }
731
732   /* --- Decrypt the packet --- */
733
734   if (ivsz) {
735     memset(buf_u, 0, blkcsz - SEQSZ);
736     memcpy(buf_u + blkcsz - SEQSZ, pseq, SEQSZ);
737     TRACE_PRESEQ(buf_u, ivsz);
738     GC_ENCRYPT(blkc, buf_u, buf_u, blkcsz);
739     GC_SETIV(c, buf_u);
740     TRACE_IV(buf_u, ivsz);
741   }
742   GC_DECRYPT(c, ppk, q, sz);
743
744   /* --- Finished --- */
745
746   *seq = LOAD32(pseq);
747   BSTEP(bb, sz);
748   return (0);
749 }
750
751 /*----- The NaCl box transform --------------------------------------------*
752  *
753  * This transform is very similar to the NaCl `crypto_secretbox' transform
754  * described in Bernstein, `Cryptography in NaCl', with the difference that,
755  * rather than using XSalsa20, we use either Salsa20/r or ChaChar, because we
756  * have no need of XSalsa20's extended nonce.  The default cipher is Salsa20.
757  *
758  * Salsa20 and ChaCha accept a 64-bit nonce.  The low 32 bits are the
759  * sequence number, and the high 32 bits are the type, both big-endian.
760  *
761  *              +------+------+
762  *              | seq  | type |
763  *              +------+------+
764  *                 32     32
765  *
766  * A stream is generated by concatenating the raw output blocks generated
767  * with this nonce and successive counter values starting from zero.  The
768  * first 32 bytes of the stream are used as a key for Poly1305: the first 16
769  * bytes are the universal hash key r, and the second 16 bytes are the mask
770  * value s.
771  *
772  *              +------+------+ +------...------+
773  *              |  r   |  s   | |   keystream   |
774  *              +------+------+ +------...------+
775  *                128    128           sz
776  *
777  * The remainder of the stream is XORed with the incoming plaintext to form a
778  * ciphertext with the same length.  The ciphertext (only) is then tagged
779  * using Poly1305.  The tag, sequence number, and ciphertext are concatenated
780  * in this order, and transmitted.
781  *
782  *
783  *              +---...---+------+------...------+
784  *              |   tag   | seq  |   ciphertext  |
785  *              +---...---+------+------...------+
786  *                  128     32          sz
787  *
788  * Note that there is no need to authenticate the type separately, since it
789  * was used to select the cipher nonce, and hence the Poly1305 key.  The
790  * Poly1305 tag length is fixed.
791  */
792
793 typedef struct naclbox_algs {
794   bulkalgs _b;
795   const gccipher *c; size_t cksz;
796 } naclbox_algs;
797
798 typedef struct naclbox_ctx {
799   bulkctx _b;
800   struct { gcipher *c; } d[NDIR];
801 } naclbox_ctx;
802
803
804 static bulkalgs *naclbox_getalgs(const algswitch *asw, dstr *e,
805                                  key_file *kf, key *k)
806 {
807   naclbox_algs *a = CREATE(naclbox_algs);
808   const char *p;
809   char *qq;
810   unsigned long n;
811
812   /* --- Collect the selected cipher and check that it's supported --- */
813
814   p = key_getattr(kf, k, "cipher");
815   if (!p || strcmp(p, "salsa20") == 0) a->c = &salsa20;
816   else if (strcmp(p, "salsa20/12") == 0) a->c = &salsa2012;
817   else if (strcmp(p, "salsa20/8") == 0) a->c = &salsa208;
818   else if (strcmp(p, "chacha20") == 0) a->c = &chacha20;
819   else if (strcmp(p, "chacha12") == 0) a->c = &chacha12;
820   else if (strcmp(p, "chacha8") == 0) a->c = &chacha8;
821   else {
822     a_format(e, "unknown-cipher", "%s", p, A_END);
823     goto fail;
824   }
825
826   /* --- Collect the selected MAC, and check the tag length --- */
827
828   p = key_getattr(kf, k, "mac");
829   if (!p)
830     ;
831   else if (strncmp(p, "poly1305", 8) != 0 || (p[8] && p[8] != '/')) {
832     a_format(e, "unknown-mac", "%s", p, A_END);
833     goto fail;
834   } else if (p[8] == '/') {
835     n = strtoul(p + 9, &qq, 0);
836     if (*qq) {
837       a_format(e, "bad-tag-length-string", "%s", p + 9, A_END);
838       goto fail;
839     }
840     if (n != 128) {
841       a_format(e, "bad-tag-length", "%lu", n, A_END);
842       goto fail;
843     }
844   }
845
846   return (&a->_b);
847 fail:
848   DESTROY(a);
849   return (0);
850 }
851
852 #ifndef NTRACE
853 static void naclbox_tracealgs(const bulkalgs *aa)
854 {
855   const naclbox_algs *a = (const naclbox_algs *)aa;
856
857   trace(T_CRYPTO, "crypto: cipher = %s", a->c->name);
858   trace(T_CRYPTO, "crypto: mac = poly1305/128");
859 }
860 #endif
861
862 static int naclbox_checkalgs(bulkalgs *aa, const algswitch *asw, dstr *e)
863 {
864   naclbox_algs *a = (naclbox_algs *)aa;
865
866   if ((a->cksz = keysz(asw->hashsz, a->c->keysz)) == 0) {
867     a_format(e, "cipher", "%s", a->c->name,
868              "no-key-size", "%lu", (unsigned long)asw->hashsz,
869              A_END);
870     return (-1);
871   }
872   return (0);
873 }
874
875 static int naclbox_samealgsp(const bulkalgs *aa, const bulkalgs *bb)
876 {
877   const naclbox_algs *a = (const naclbox_algs *)aa,
878     *b = (const naclbox_algs *)bb;
879   return (a->c == b->c);
880 }
881
882 static void naclbox_alginfo(const bulkalgs *aa, admin *adm)
883 {
884   const naclbox_algs *a = (const naclbox_algs *)aa;
885   a_info(adm, "cipher=%s", a->c->name, "cipher-keysz=32", A_END);
886   a_info(adm, "mac=poly1305", "mac-tagsz=16", A_END);
887 }
888
889 static size_t naclbox_overhead(const bulkalgs *aa)
890   { return (POLY1305_TAGSZ + SEQSZ); }
891
892 static size_t naclbox_expsz(const bulkalgs *aa)
893   { return (MEG(2048)); }
894
895 static bulkctx *naclbox_genkeys(const bulkalgs *aa, const struct rawkey *rk)
896 {
897   const naclbox_algs *a = (const naclbox_algs *)aa;
898   naclbox_ctx *bc = CREATE(naclbox_ctx);
899   octet k[MAXHASHSZ];
900   int i;
901
902   for (i = 0; i < NDIR; i++) {
903     ks_derivekey(k, a->cksz, rk, i, "encryption");
904     bc->d[i].c = GC_INIT(a->c, k, a->cksz);
905   }
906   return (&bc->_b);
907 }
908
909 typedef struct naclbox_chal {
910   bulkchal _b;
911   gcipher *c;
912 } naclbox_chal;
913
914 static bulkchal *naclbox_genchal(const bulkalgs *aa)
915 {
916   const naclbox_algs *a = (const naclbox_algs *)aa;
917   naclbox_chal *c = CREATE(naclbox_chal);
918   rand_get(RAND_GLOBAL, buf_t, a->cksz);
919   c->c = GC_INIT(a->c, buf_t, a->cksz);
920   IF_TRACING(T_CHAL, {
921     trace(T_CHAL, "chal: generated new challenge key");
922     trace_block(T_CRYPTO, "chal: new key", buf_t, a->cksz);
923   })
924   c->_b.tagsz = 16;
925   return (&c->_b);
926 }
927
928 static int naclbox_chaltag(bulkchal *bc, const void *m, size_t msz, void *t)
929 {
930   naclbox_chal *c = (naclbox_chal *)bc;
931   octet b0[SALSA20_NONCESZ];
932   assert(msz <= sizeof(b0));
933   memcpy(b0, m, msz); memset(b0 + msz, 0, sizeof(b0) - msz);
934   GC_SETIV(c->c, b0);
935   GC_ENCRYPT(c->c, 0, t, c->_b.tagsz);
936   return (0);
937 }
938
939 static int naclbox_chalvrf(bulkchal *bc, const void *m, size_t msz,
940                            const void *t)
941 {
942   naclbox_chal *c = (naclbox_chal *)bc;
943   octet b0[SALSA20_NONCESZ], b1[16];
944   assert(msz <= sizeof(b0)); assert(c->_b.tagsz <= sizeof(b1));
945   memcpy(b0, m, msz); memset(b0 + msz, 0, sizeof(b0) - msz);
946   GC_SETIV(c->c, b0);
947   GC_ENCRYPT(c->c, 0, b1, c->_b.tagsz);
948   return (ct_memeq(t, b1, c->_b.tagsz) ? 0 : -1);
949 }
950
951 static void naclbox_freechal(bulkchal *bc)
952   { naclbox_chal *c = (naclbox_chal *)bc; GC_DESTROY(c->c); DESTROY(c); }
953
954 static void naclbox_freealgs(bulkalgs *aa)
955   { naclbox_algs *a = (naclbox_algs *)aa; DESTROY(a); }
956
957 static void naclbox_freectx(bulkctx *bbc)
958 {
959   naclbox_ctx *bc = (naclbox_ctx *)bbc;
960   int i;
961
962   for (i = 0; i < NDIR; i++) GC_DESTROY(bc->d[i].c);
963   DESTROY(bc);
964 }
965
966 static int naclbox_encrypt(bulkctx *bbc, unsigned ty,
967                            buf *b, buf *bb, uint32 seq)
968 {
969   naclbox_ctx *bc = (naclbox_ctx *)bbc;
970   gcipher *c = bc->d[DIR_OUT].c;
971   poly1305_key polyk;
972   poly1305_ctx poly;
973   const octet *p = BCUR(b);
974   size_t sz = BLEFT(b);
975   octet *qmac, *qseq, *qpk;
976
977   /* --- Determine the ciphertext layout --- */
978
979   if (buf_ensure(bb, POLY1305_TAGSZ + SEQSZ + sz)) return (0);
980   qmac = BCUR(bb); qseq = qmac + POLY1305_TAGSZ; qpk = qseq + SEQSZ;
981   BSTEP(bb, POLY1305_TAGSZ + SEQSZ + sz);
982
983   /* --- Construct and set the nonce --- */
984
985   STORE32(qseq, seq);
986   memcpy(buf_u, qseq, SEQSZ); STORE32(buf_u + SEQSZ, ty);
987   GC_SETIV(c, buf_u);
988   TRACE_IV(buf_u, SALSA20_NONCESZ);
989
990   /* --- Determine the MAC key --- */
991
992   GC_ENCRYPT(c, 0, buf_u, POLY1305_KEYSZ + POLY1305_MASKSZ);
993   poly1305_keyinit(&polyk, buf_u, POLY1305_KEYSZ);
994   poly1305_macinit(&poly, &polyk, buf_u + POLY1305_KEYSZ);
995
996   /* --- Encrypt the message --- */
997
998   GC_ENCRYPT(c, p, qpk, sz);
999   TRACE_CT(qpk, sz);
1000
1001   /* --- Compute the MAC --- */
1002
1003   poly1305_hash(&poly, qpk, sz);
1004   poly1305_done(&poly, qmac);
1005   TRACE_MAC(qmac, POLY1305_TAGSZ);
1006
1007   /* --- We're done --- */
1008
1009   return (0);
1010 }
1011
1012 static int naclbox_decrypt(bulkctx *bbc, unsigned ty,
1013                        buf *b, buf *bb, uint32 *seq)
1014 {
1015   naclbox_ctx *bc = (naclbox_ctx *)bbc;
1016   gcipher *c = bc->d[DIR_IN].c;
1017   poly1305_key polyk;
1018   poly1305_ctx poly;
1019   const octet *pmac, *pseq, *ppk;
1020   size_t psz = BLEFT(b);
1021   size_t sz;
1022   octet *q = BCUR(bb);
1023
1024   /* --- Break up the packet into its components --- */
1025
1026   if (psz < SEQSZ + POLY1305_TAGSZ) {
1027     T( trace(T_KEYSET, "keyset: block too small for keyset"); )
1028     return (KSERR_MALFORMED);
1029   }
1030   sz = psz - SEQSZ - POLY1305_TAGSZ;
1031   pmac = BCUR(b); pseq = pmac + POLY1305_TAGSZ; ppk = pseq + SEQSZ;
1032
1033   /* --- Construct and set the nonce --- */
1034
1035   memcpy(buf_u, pseq, SEQSZ); STORE32(buf_u + SEQSZ, ty);
1036   GC_SETIV(c, buf_u);
1037   TRACE_IV(buf_u, SALSA20_NONCESZ);
1038
1039   /* --- Determine the MAC key --- */
1040
1041   GC_ENCRYPT(c, 0, buf_u, POLY1305_KEYSZ + POLY1305_MASKSZ);
1042   poly1305_keyinit(&polyk, buf_u, POLY1305_KEYSZ);
1043   poly1305_macinit(&poly, &polyk, buf_u + POLY1305_KEYSZ);
1044
1045   /* --- Verify the MAC on the packet --- */
1046
1047   poly1305_hash(&poly, ppk, sz);
1048   poly1305_done(&poly, buf_u);
1049   if (!ct_memeq(buf_u, pmac, POLY1305_TAGSZ)) {
1050     TRACE_MACERR(pmac, POLY1305_TAGSZ);
1051     return (KSERR_DECRYPT);
1052   }
1053
1054   /* --- Decrypt the packet --- */
1055
1056   GC_DECRYPT(c, ppk, q, sz);
1057
1058   /* --- Finished --- */
1059
1060   *seq = LOAD32(pseq);
1061   BSTEP(bb, sz);
1062   return (0);
1063 }
1064
1065 /*----- Bulk crypto transform table ---------------------------------------*/
1066
1067 const bulkops bulktab[] = {
1068
1069 #define COMMA ,
1070
1071 #define BULK(name, pre)                                                 \
1072   { name, pre##_getalgs, T( pre##_tracealgs COMMA )                     \
1073     pre##_checkalgs, pre##_samealgsp,                                   \
1074     pre##_alginfo, pre##_overhead, pre##_expsz,                         \
1075     pre##_genkeys, pre##_genchal, pre##_freealgs,                       \
1076     pre##_encrypt, pre##_decrypt, pre##_freectx,                        \
1077     pre##_chaltag, pre##_chalvrf, pre##_freechal }
1078
1079   BULK("v0", v0),
1080   BULK("iiv", iiv),
1081   BULK("naclbox", naclbox),
1082
1083 #undef BULK
1084   { 0 }
1085 };
1086
1087 /*----- That's all, folks -------------------------------------------------*/