chiark / gitweb /
365aa1760abc7bddb5ee18bcdcb3c31125cb5fbf
[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 = strrchr(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 /*----- 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   if (!ct_memeq(buf_u, pmac, POLY1305_TAGSZ)) {
1051     TRACE_MACERR(pmac, POLY1305_TAGSZ);
1052     return (KSERR_DECRYPT);
1053   }
1054
1055   /* --- Decrypt the packet --- */
1056
1057   GC_DECRYPT(c, ppk, q, sz);
1058
1059   /* --- Finished --- */
1060
1061   *seq = LOAD32(pseq);
1062   BSTEP(bb, sz);
1063   return (0);
1064 }
1065
1066 /*----- Bulk crypto transform table ---------------------------------------*/
1067
1068 const bulkops bulktab[] = {
1069
1070 #define COMMA ,
1071
1072 #define BULK(name, pre)                                                 \
1073   { name, pre##_getalgs, T( pre##_tracealgs COMMA )                     \
1074     pre##_checkalgs, pre##_samealgsp,                                   \
1075     pre##_alginfo, pre##_overhead, pre##_expsz,                         \
1076     pre##_genkeys, pre##_genchal, pre##_freealgs,                       \
1077     pre##_encrypt, pre##_decrypt, pre##_freectx,                        \
1078     pre##_chaltag, pre##_chalvrf, pre##_freechal }
1079
1080   BULK("v0", v0),
1081   BULK("iiv", iiv),
1082   BULK("naclbox", naclbox),
1083
1084 #undef BULK
1085   { 0 }
1086 };
1087
1088 /*----- That's all, folks -------------------------------------------------*/