Commit | Line | Data |
---|---|---|
a93aacce MW |
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 | * | |
11ad66c2 MW |
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. | |
a93aacce | 16 | * |
11ad66c2 MW |
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. | |
a93aacce MW |
21 | * |
22 | * You should have received a copy of the GNU General Public License | |
11ad66c2 | 23 | * along with TrIPE. If not, see <https://www.gnu.org/licenses/>. |
a93aacce MW |
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 | ||
9a361a98 MW |
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 | ||
c70a7c5c MW |
52 | /*----- Common functionality for generic-composition transforms -----------*/ |
53 | ||
a93aacce MW |
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) { \ | |
9a361a98 | 63 | TRACE_MACERR(_pmac, _tagsz); \ |
a93aacce MW |
64 | return (KSERR_DECRYPT); \ |
65 | } \ | |
66 | } while (0) | |
67 | ||
c70a7c5c MW |
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; | |
e14a412e | 75 | gmac *m; |
c70a7c5c MW |
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); | |
73d383c0 | 100 | if ((q = strrchr(d.buf, '/')) != 0) |
c70a7c5c MW |
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 | ||
a93aacce MW |
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 | ||
c70a7c5c MW |
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 | } | |
a93aacce | 308 | |
c70a7c5c MW |
309 | static size_t v0_expsz(const bulkalgs *aa) |
310 | { const v0_algs *a = (const v0_algs *)aa; return (gencomp_expsz(&a->ga)); } | |
a93aacce | 311 | |
c70a7c5c | 312 | static bulkctx *v0_genkeys(const bulkalgs *aa, const struct rawkey *rk) |
a93aacce | 313 | { |
c70a7c5c MW |
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; | |
a93aacce | 357 | ghash *h; |
c70a7c5c | 358 | gcipher *c = bc->d[DIR_OUT].c; |
a93aacce MW |
359 | const octet *p = BCUR(b); |
360 | size_t sz = BLEFT(b); | |
361 | octet *qmac, *qseq, *qiv, *qpk; | |
a93aacce | 362 | size_t ivsz = GC_CLASS(c)->blksz; |
c70a7c5c | 363 | size_t tagsz = bc->tagsz; |
a93aacce MW |
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 | ||
c70a7c5c | 381 | STORE32(qseq, seq); |
a93aacce MW |
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) { | |
c70a7c5c | 399 | h = GM_INIT(bc->d[DIR_OUT].m); |
a93aacce MW |
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 | ||
c70a7c5c MW |
412 | static int v0_decrypt(bulkctx *bbc, unsigned ty, |
413 | buf *b, buf *bb, uint32 *seq) | |
a93aacce | 414 | { |
c70a7c5c | 415 | v0_ctx *bc = (v0_ctx *)bbc; |
a93aacce MW |
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; | |
c70a7c5c | 421 | gcipher *c = bc->d[DIR_IN].c; |
a93aacce | 422 | size_t ivsz = GC_CLASS(c)->blksz; |
c70a7c5c | 423 | size_t tagsz = bc->tagsz; |
a93aacce MW |
424 | octet t[4]; |
425 | ||
426 | /* --- Break up the packet into its components --- */ | |
427 | ||
428 | if (psz < ivsz + SEQSZ + tagsz) { | |
c70a7c5c | 429 | T( trace(T_KEYSET, "keyset: block too small for keyset"); ) |
a93aacce MW |
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) { | |
c70a7c5c | 439 | h = GM_INIT(bc->d[DIR_IN].m); |
a93aacce MW |
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 | ||
b87bffcb MW |
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 | ||
c70a7c5c MW |
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); | |
ed621603 MW |
539 | trace(T_CRYPTO, |
540 | "crypto: blkc = %.*s", (int)strlen(a->b->name) - 4, a->b->name); | |
c70a7c5c MW |
541 | } |
542 | #endif | |
543 | ||
544 | static int iiv_checkalgs(bulkalgs *aa, const algswitch *asw, dstr *e) | |
b87bffcb | 545 | { |
c70a7c5c MW |
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) { | |
b87bffcb MW |
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 | ||
c70a7c5c MW |
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 | } | |
b87bffcb MW |
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 | ||
c70a7c5c MW |
638 | static int iiv_encrypt(bulkctx *bbc, unsigned ty, |
639 | buf *b, buf *bb, uint32 seq) | |
b87bffcb | 640 | { |
c70a7c5c | 641 | iiv_ctx *bc = (iiv_ctx *)bbc; |
b87bffcb | 642 | ghash *h; |
c70a7c5c | 643 | gcipher *c = bc->d[DIR_OUT].c, *blkc = bc->d[DIR_OUT].b; |
b87bffcb MW |
644 | const octet *p = BCUR(b); |
645 | size_t sz = BLEFT(b); | |
646 | octet *qmac, *qseq, *qpk; | |
b87bffcb | 647 | size_t ivsz = GC_CLASS(c)->blksz, blkcsz = GC_CLASS(blkc)->blksz; |
c70a7c5c | 648 | size_t tagsz = bc->tagsz; |
b87bffcb MW |
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 | ||
c70a7c5c | 666 | STORE32(qseq, seq); |
b87bffcb MW |
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) { | |
c70a7c5c | 687 | h = GM_INIT(bc->d[DIR_OUT].m); |
b87bffcb MW |
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 | ||
c70a7c5c MW |
700 | static int iiv_decrypt(bulkctx *bbc, unsigned ty, |
701 | buf *b, buf *bb, uint32 *seq) | |
b87bffcb | 702 | { |
c70a7c5c | 703 | iiv_ctx *bc = (iiv_ctx *)bbc; |
b87bffcb MW |
704 | const octet *pmac, *pseq, *ppk; |
705 | size_t psz = BLEFT(b); | |
706 | size_t sz; | |
707 | octet *q = BCUR(bb); | |
708 | ghash *h; | |
c70a7c5c | 709 | gcipher *c = bc->d[DIR_IN].c, *blkc = bc->d[DIR_IN].b; |
b87bffcb | 710 | size_t ivsz = GC_CLASS(c)->blksz, blkcsz = GC_CLASS(blkc)->blksz; |
c70a7c5c | 711 | size_t tagsz = bc->tagsz; |
b87bffcb MW |
712 | octet t[4]; |
713 | ||
714 | /* --- Break up the packet into its components --- */ | |
715 | ||
716 | if (psz < SEQSZ + tagsz) { | |
c70a7c5c | 717 | T( trace(T_KEYSET, "keyset: block too small for keyset"); ) |
b87bffcb MW |
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) { | |
c70a7c5c | 727 | h = GM_INIT(bc->d[DIR_IN].m); |
b87bffcb MW |
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 | ||
de8edc7f MW |
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); | |
e713954a | 1050 | TRACE_MAC(buf_u, POLY1305_TAGSZ); |
de8edc7f MW |
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 | ||
a93aacce MW |
1067 | /*----- Bulk crypto transform table ---------------------------------------*/ |
1068 | ||
fddd7fb7 | 1069 | const bulkops bulktab[] = { |
a93aacce | 1070 | |
c70a7c5c MW |
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 } | |
a93aacce | 1080 | |
c70a7c5c MW |
1081 | BULK("v0", v0), |
1082 | BULK("iiv", iiv), | |
de8edc7f | 1083 | BULK("naclbox", naclbox), |
a93aacce MW |
1084 | |
1085 | #undef BULK | |
1086 | { 0 } | |
1087 | }; | |
1088 | ||
1089 | /*----- That's all, folks -------------------------------------------------*/ |