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; | |
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); | |
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); | |
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) | |
b87bffcb | 544 | { |
c70a7c5c MW |
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) { | |
b87bffcb MW |
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 | ||
c70a7c5c MW |
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 | } | |
b87bffcb MW |
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 | ||
c70a7c5c MW |
637 | static int iiv_encrypt(bulkctx *bbc, unsigned ty, |
638 | buf *b, buf *bb, uint32 seq) | |
b87bffcb | 639 | { |
c70a7c5c | 640 | iiv_ctx *bc = (iiv_ctx *)bbc; |
b87bffcb | 641 | ghash *h; |
c70a7c5c | 642 | gcipher *c = bc->d[DIR_OUT].c, *blkc = bc->d[DIR_OUT].b; |
b87bffcb MW |
643 | const octet *p = BCUR(b); |
644 | size_t sz = BLEFT(b); | |
645 | octet *qmac, *qseq, *qpk; | |
b87bffcb | 646 | size_t ivsz = GC_CLASS(c)->blksz, blkcsz = GC_CLASS(blkc)->blksz; |
c70a7c5c | 647 | size_t tagsz = bc->tagsz; |
b87bffcb MW |
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 | ||
c70a7c5c | 665 | STORE32(qseq, seq); |
b87bffcb MW |
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) { | |
c70a7c5c | 686 | h = GM_INIT(bc->d[DIR_OUT].m); |
b87bffcb MW |
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 | ||
c70a7c5c MW |
699 | static int iiv_decrypt(bulkctx *bbc, unsigned ty, |
700 | buf *b, buf *bb, uint32 *seq) | |
b87bffcb | 701 | { |
c70a7c5c | 702 | iiv_ctx *bc = (iiv_ctx *)bbc; |
b87bffcb MW |
703 | const octet *pmac, *pseq, *ppk; |
704 | size_t psz = BLEFT(b); | |
705 | size_t sz; | |
706 | octet *q = BCUR(bb); | |
707 | ghash *h; | |
c70a7c5c | 708 | gcipher *c = bc->d[DIR_IN].c, *blkc = bc->d[DIR_IN].b; |
b87bffcb | 709 | size_t ivsz = GC_CLASS(c)->blksz, blkcsz = GC_CLASS(blkc)->blksz; |
c70a7c5c | 710 | size_t tagsz = bc->tagsz; |
b87bffcb MW |
711 | octet t[4]; |
712 | ||
713 | /* --- Break up the packet into its components --- */ | |
714 | ||
715 | if (psz < SEQSZ + tagsz) { | |
c70a7c5c | 716 | T( trace(T_KEYSET, "keyset: block too small for keyset"); ) |
b87bffcb MW |
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) { | |
c70a7c5c | 726 | h = GM_INIT(bc->d[DIR_IN].m); |
b87bffcb MW |
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 | ||
de8edc7f MW |
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 | ||
a93aacce MW |
1065 | /*----- Bulk crypto transform table ---------------------------------------*/ |
1066 | ||
fddd7fb7 | 1067 | const bulkops bulktab[] = { |
a93aacce | 1068 | |
c70a7c5c MW |
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 } | |
a93aacce | 1078 | |
c70a7c5c MW |
1079 | BULK("v0", v0), |
1080 | BULK("iiv", iiv), | |
de8edc7f | 1081 | BULK("naclbox", naclbox), |
a93aacce MW |
1082 | |
1083 | #undef BULK | |
1084 | { 0 } | |
1085 | }; | |
1086 | ||
1087 | /*----- That's all, folks -------------------------------------------------*/ |