3 * Catcrypt key-encapsulation
5 * (c) 2004 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of Catacomb.
12 * Catacomb is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
17 * Catacomb 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 Library General Public License for more details.
22 * You should have received a copy of the GNU Library General Public
23 * License along with Catacomb; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
28 /*----- Header files ------------------------------------------------------*/
30 #define _FILE_OFFSET_BITS 64
34 #include <mLib/alloc.h>
35 #include <mLib/dstr.h>
36 #include <mLib/macros.h>
37 #include <mLib/report.h>
52 #include "blowfish-cbc.h"
53 #include "chacha20-poly1305.h"
60 /*----- Bulk crypto -------------------------------------------------------*/
62 /* --- Authenticated encryption schemes --- */
64 typedef struct aead_encctx
{
68 union { gaead_enc
*enc
; gaead_dec
*dec
; } ed
;
73 static bulk
*aead_internalinit(key
*k
, const gcaead
*aec
)
75 aead_encctx
*ctx
= CREATE(aead_encctx
);
79 if ((ctx
->nsz
= keysz_pad(4, aec
->noncesz
)) == 0)
80 die(EXIT_FAILURE
, "no suitable nonce size for `%s'", aec
->name
);
81 ctx
->tsz
= keysz(0, ctx
->aec
->tagsz
);
86 static bulk
*aead_init(key
*k
, const char *calg
, const char *halg
)
94 if ((q
= key_getattr(0, k
, "cipher")) != 0) calg
= q
;
95 if (!calg
) aec
= &chacha20_poly1305
;
96 else if ((aec
= gaead_byname(calg
)) == 0)
97 die(EXIT_FAILURE
, "AEAD scheme `%s' not found in key `%s'",
101 return (aead_internalinit(k
, aec
));
104 static int aead_commonsetup(aead_encctx
*ctx
, gcipher
*cx
)
108 n
= ksz
= keysz(0, ctx
->aec
->keysz
);
109 if (n
< ctx
->nsz
) n
= ctx
->nsz
;
110 if (n
< ctx
->tsz
) n
= ctx
->tsz
;
113 GC_ENCRYPT(cx
, 0, ctx
->t
, ksz
);
114 ctx
->key
= GAEAD_KEY(ctx
->aec
, ctx
->t
, ksz
);
118 static size_t aead_overhead(bulk
*b
)
119 { aead_encctx
*ctx
= (aead_encctx
*)b
; return (ctx
->aec
->ohd
+ ctx
->tsz
); }
121 static void aead_commondestroy(aead_encctx
*ctx
)
123 if (ctx
->key
) GAEAD_DESTROY(ctx
->key
);
128 static int aead_encsetup(bulk
*b
, gcipher
*cx
)
130 aead_encctx
*ctx
= (aead_encctx
*)b
;
131 ctx
->ed
.enc
= 0; return (aead_commonsetup(ctx
, cx
));
134 static const char *aead_encdoit(bulk
*b
, uint32 seq
, buf
*bb
,
135 const void *p
, size_t sz
)
137 aead_encctx
*ctx
= (aead_encctx
*)b
;
141 memset(ctx
->t
+ 4, 0, ctx
->nsz
- 4); STORE32_B(ctx
->t
, seq
);
143 ctx
->ed
.enc
= GAEAD_ENC(ctx
->key
, ctx
->t
, ctx
->nsz
, 0, sz
, ctx
->tsz
);
145 GAEAD_REINIT(ctx
->ed
.enc
, ctx
->t
, ctx
->nsz
, 0, sz
, ctx
->tsz
);
146 t
= buf_get(bb
, ctx
->tsz
); assert(t
);
147 rc
= GAEAD_ENCRYPT(ctx
->ed
.enc
, p
, sz
, bb
); assert(rc
>= 0);
148 rc
= GAEAD_DONE(ctx
->ed
.enc
, 0, bb
, t
, ctx
->tsz
); assert(rc
>= 0);
152 static void aead_encdestroy(bulk
*b
)
154 aead_encctx
*ctx
= (aead_encctx
*)b
;
155 if (ctx
->ed
.enc
) GAEAD_DESTROY(ctx
->ed
.enc
);
156 aead_commondestroy(ctx
);
159 static int aead_decsetup(bulk
*b
, gcipher
*cx
)
161 aead_encctx
*ctx
= (aead_encctx
*)b
;
162 ctx
->ed
.dec
= 0; return (aead_commonsetup(ctx
, cx
));
165 static const char *aead_decdoit(bulk
*b
, uint32 seq
, buf
*bb
,
166 const void *p
, size_t sz
)
168 aead_encctx
*ctx
= (aead_encctx
*)b
;
173 memset(ctx
->t
+ 4, 0, ctx
->nsz
- 4); STORE32_B(ctx
->t
, seq
);
175 ctx
->ed
.dec
= GAEAD_DEC(ctx
->key
, ctx
->t
, ctx
->nsz
, 0, sz
, ctx
->tsz
);
177 GAEAD_REINIT(ctx
->ed
.enc
, ctx
->t
, ctx
->nsz
, 0, sz
, ctx
->tsz
);
179 buf_init(&bin
, (/*unconst*/ void *)p
, sz
);
180 t
= buf_get(&bin
, ctx
->tsz
); if (!t
) return ("no tag");
181 rc
= GAEAD_DECRYPT(ctx
->ed
.dec
, BCUR(&bin
), BLEFT(&bin
), bb
);
183 rc
= GAEAD_DONE(ctx
->ed
.dec
, 0, bb
, t
, ctx
->tsz
); assert(rc
>= 0);
184 if (!rc
) return ("authentication failure");
188 static void aead_decdestroy(bulk
*b
)
190 aead_encctx
*ctx
= (aead_encctx
*)b
;
191 if (ctx
->ed
.dec
) GAEAD_DESTROY(ctx
->ed
.dec
);
192 aead_commondestroy(ctx
);
195 static const struct bulkops aead_encops
= {
196 aead_init
, aead_encsetup
, aead_overhead
,
197 aead_encdoit
, aead_encdestroy
199 aead_init
, aead_decsetup
, aead_overhead
,
200 aead_decdoit
, aead_decdestroy
203 /* --- NaCl `secretbox' in terms of AEAD --- */
205 static bulk
*naclbox_init(key
*k
, const char *calg
, const char *halg
)
213 if ((q
= key_getattr(0, k
, "cipher")) != 0) calg
= q
;
214 if (!calg
|| STRCMP(calg
, ==, "salsa20")) aec
= &salsa20_naclbox
;
215 else if (STRCMP(calg
, ==, "salsa20/12")) aec
= &salsa2012_naclbox
;
216 else if (STRCMP(calg
, ==, "salsa20/8")) aec
= &salsa208_naclbox
;
217 else if (STRCMP(calg
, ==, "chacha20")) aec
= &chacha20_naclbox
;
218 else if (STRCMP(calg
, ==, "chacha12")) aec
= &chacha12_naclbox
;
219 else if (STRCMP(calg
, ==, "chacha8")) aec
= &chacha8_naclbox
;
222 "unknown or inappropriate encryption scheme `%s' in key `%s'",
227 return (aead_internalinit(k
, aec
));
230 static const bulkops naclbox_encops
= {
231 naclbox_init
, aead_encsetup
, aead_overhead
,
232 aead_encdoit
, aead_encdestroy
233 }, naclbox_decops
= {
234 naclbox_init
, aead_decsetup
, aead_overhead
,
235 aead_decdoit
, aead_decdestroy
238 /* --- Generic composition --- */
240 typedef struct gencomp_encctx
{
246 octet
*t
; size_t tsz
;
249 static bulk
*gencomp_init(key
*k
, const char *calg
, const char *halg
)
251 gencomp_encctx
*ctx
= CREATE(gencomp_encctx
);
253 dstr d
= DSTR_INIT
, t
= DSTR_INIT
;
257 if ((q
= key_getattr(0, k
, "cipher")) != 0) calg
= q
;
258 if (!calg
) ctx
->cc
= &blowfish_cbc
;
259 else if ((ctx
->cc
= gcipher_byname(calg
)) == 0) {
260 die(EXIT_FAILURE
, "encryption scheme `%s' not found in key `%s'",
265 if ((q
= key_getattr(0, k
, "mac")) == 0) {
266 dstr_putf(&d
, "%s-hmac", halg
);
269 if ((ctx
->mc
= gmac_byname(q
)) == 0) {
271 "message authentication code `%s' not found in key `%s'",
278 static int gencomp_setup(bulk
*b
, gcipher
*cx
)
280 gencomp_encctx
*ctx
= (gencomp_encctx
*)b
;
286 cn
= keysz(0, ctx
->cc
->keysz
); if (cn
> n
) n
= cn
;
287 mn
= keysz(0, ctx
->mc
->keysz
); if (mn
> n
) n
= mn
;
288 ctx
->t
= kd
= xmalloc(n
); ctx
->tsz
= n
;
289 GC_ENCRYPT(cx
, 0, kd
, cn
);
290 ctx
->c
= GC_INIT(ctx
->cc
, kd
, cn
);
291 GC_ENCRYPT(cx
, 0, kd
, mn
);
292 ctx
->m
= GM_KEY(ctx
->mc
, kd
, mn
);
296 static size_t gencomp_overhead(bulk
*b
)
298 gencomp_encctx
*ctx
= (gencomp_encctx
*)b
;
299 return (ctx
->cc
->blksz
+ ctx
->mc
->hashsz
); }
301 static void gencomp_destroy(bulk
*b
)
303 gencomp_encctx
*ctx
= (gencomp_encctx
*)b
;
311 static const char *gencomp_encdoit(bulk
*b
, uint32 seq
, buf
*bb
,
312 const void *p
, size_t sz
)
314 gencomp_encctx
*ctx
= (gencomp_encctx
*)b
;
316 ghash
*h
= GM_INIT(ctx
->m
);
319 if (ctx
->cc
->blksz
) {
320 GC_ENCRYPT(ctx
->cx
, 0, ctx
->t
, ctx
->cc
->blksz
);
321 GC_SETIV(ctx
->c
, ctx
->t
);
323 tag
= buf_get(bb
, ctx
->mc
->hashsz
); assert(tag
);
324 ct
= buf_get(bb
, sz
); assert(ct
);
325 GC_ENCRYPT(ctx
->c
, p
, ct
, sz
);
332 static const char *gencomp_decdoit(bulk
*b
, uint32 seq
, buf
*bb
,
333 const void *p
, size_t sz
)
335 gencomp_encctx
*ctx
= (gencomp_encctx
*)b
;
337 const octet
*tag
, *ct
;
342 buf_init(&bin
, (/*unconst*/ void *)p
, sz
);
343 if ((tag
= buf_get(&bin
, ctx
->mc
->hashsz
)) == 0) return ("no tag");
344 ct
= BCUR(&bin
); sz
= BLEFT(&bin
);
345 pt
= buf_get(bb
, sz
); assert(pt
);
350 ok
= ct_memeq(tag
, GH_DONE(h
, 0), ctx
->mc
->hashsz
);
352 if (!ok
) return ("authentication failure");
354 if (ctx
->cc
->blksz
) {
355 GC_ENCRYPT(ctx
->cx
, 0, ctx
->t
, ctx
->cc
->blksz
);
356 GC_SETIV(ctx
->c
, ctx
->t
);
358 GC_DECRYPT(ctx
->c
, ct
, pt
, sz
);
362 static const bulkops gencomp_encops
= {
363 gencomp_init
, gencomp_setup
, gencomp_overhead
,
364 gencomp_encdoit
, gencomp_destroy
365 }, gencomp_decops
= {
366 gencomp_init
, gencomp_setup
, gencomp_overhead
,
367 gencomp_decdoit
, gencomp_destroy
370 const struct bulktab bulktab
[] = {
371 { "gencomp", &gencomp_encops
, &gencomp_decops
},
372 { "naclbox", &naclbox_encops
, &naclbox_decops
},
373 { "aead", &aead_encops
, &aead_decops
},
377 /*----- Key encapsulation -------------------------------------------------*/
381 typedef struct rsa_encctx
{
386 static kem
*rsa_encinit(key
*k
, void *kd
)
388 rsa_encctx
*re
= CREATE(rsa_encctx
);
389 rsa_pubcreate(&re
->rp
, kd
);
393 static int rsa_encdoit(kem
*k
, dstr
*d
, ghash
*h
)
395 rsa_encctx
*re
= (rsa_encctx
*)k
;
396 mp
*x
= mprand_range(MP_NEW
, re
->rp
.rp
->n
, &rand_global
, 0);
397 mp
*y
= rsa_pubop(&re
->rp
, MP_NEW
, x
);
398 size_t n
= mp_octets(re
->rp
.rp
->n
);
400 mp_storeb(x
, d
->buf
, n
);
401 GH_HASH(h
, d
->buf
, n
);
402 mp_storeb(y
, d
->buf
, n
);
409 static const char *rsa_lengthcheck(mp
*n
)
411 if (mp_bits(n
) < 1020) return ("key too short");
415 static const char *rsa_enccheck(kem
*k
)
417 rsa_encctx
*re
= (rsa_encctx
*)k
;
419 if ((e
= rsa_lengthcheck(re
->rp
.rp
->n
)) != 0) return (e
);
423 static void rsa_encdestroy(kem
*k
)
425 rsa_encctx
*re
= (rsa_encctx
*)k
;
426 rsa_pubdestroy(&re
->rp
);
430 static const kemops rsa_encops
= {
431 rsa_pubfetch
, sizeof(rsa_pub
),
432 rsa_encinit
, rsa_encdoit
, rsa_enccheck
, rsa_encdestroy
435 typedef struct rsa_decctx
{
440 static kem
*rsa_decinit(key
*k
, void *kd
)
442 rsa_decctx
*rd
= CREATE(rsa_decctx
);
443 rsa_privcreate(&rd
->rp
, kd
, &rand_global
);
447 static int rsa_decdoit(kem
*k
, dstr
*d
, ghash
*h
)
449 rsa_decctx
*rd
= (rsa_decctx
*)k
;
450 mp
*x
= mp_loadb(MP_NEW
, d
->buf
, d
->len
);
454 if (MP_CMP(x
, >=, rd
->rp
.rp
->n
)) {
458 n
= mp_octets(rd
->rp
.rp
->n
);
460 x
= rsa_privop(&rd
->rp
, x
, x
);
468 static const char *rsa_deccheck(kem
*k
)
470 rsa_decctx
*rd
= (rsa_decctx
*)k
;
472 if ((e
= rsa_lengthcheck(rd
->rp
.rp
->n
)) != 0) return (e
);
476 static void rsa_decdestroy(kem
*k
)
478 rsa_decctx
*rd
= (rsa_decctx
*)k
;
479 rsa_privdestroy(&rd
->rp
);
483 static const kemops rsa_decops
= {
484 rsa_privfetch
, sizeof(rsa_priv
),
485 rsa_decinit
, rsa_decdoit
, rsa_deccheck
, rsa_decdestroy
488 /* --- DH and EC --- */
490 typedef struct dh_encctx
{
497 static dh_encctx
*dh_doinit(key
*k
, const gprime_param
*gp
, mp
*y
,
498 group
*(*makegroup
)(const gprime_param
*),
501 dh_encctx
*de
= CREATE(dh_encctx
);
505 if ((de
->g
= makegroup(gp
)) == 0)
506 die(EXIT_FAILURE
, "bad %s group in key `%s'", what
, t
.buf
);
508 de
->y
= G_CREATE(de
->g
);
509 if (G_FROMINT(de
->g
, de
->y
, y
))
510 die(EXIT_FAILURE
, "bad public key `%s'", t
.buf
);
515 static dh_encctx
*ec_doinit(key
*k
, const char *cstr
, const ec
*y
)
517 dh_encctx
*de
= CREATE(dh_encctx
);
523 if ((e
= ec_getinfo(&ei
, cstr
)) != 0 ||
524 (de
->g
= group_ec(&ei
)) == 0)
525 die(EXIT_FAILURE
, "bad elliptic curve spec in key `%s': %s", t
.buf
, e
);
527 de
->y
= G_CREATE(de
->g
);
528 if (G_FROMEC(de
->g
, de
->y
, y
))
529 die(EXIT_FAILURE
, "bad public curve point `%s'", t
.buf
);
534 static kem
*dh_encinit(key
*k
, void *kd
)
537 dh_encctx
*de
= dh_doinit(k
, &dp
->dp
, dp
->y
, group_prime
, "prime");
541 static kem
*bindh_encinit(key
*k
, void *kd
)
544 dh_encctx
*de
= dh_doinit(k
, &dp
->dp
, dp
->y
, group_binary
, "binary");
548 static kem
*ec_encinit(key
*k
, void *kd
)
551 dh_encctx
*de
= ec_doinit(k
, ep
->cstr
, &ep
->p
);
555 static int dh_encdoit(kem
*k
, dstr
*d
, ghash
*h
)
557 dh_encctx
*de
= (dh_encctx
*)k
;
558 mp
*r
= mprand_range(MP_NEW
, de
->g
->r
, &rand_global
, 0);
559 ge
*x
= G_CREATE(de
->g
);
560 ge
*y
= G_CREATE(de
->g
);
561 size_t n
= de
->g
->noctets
;
564 G_EXP(de
->g
, x
, de
->g
->g
, r
);
565 G_EXP(de
->g
, y
, de
->y
, r
);
567 buf_init(&b
, d
->buf
, n
);
568 G_TORAW(de
->g
, &b
, y
);
569 GH_HASH(h
, BBASE(&b
), BLEN(&b
));
570 buf_init(&b
, d
->buf
, n
);
571 G_TORAW(de
->g
, &b
, x
);
572 GH_HASH(h
, BBASE(&b
), BLEN(&b
));
580 static const char *dh_enccheck(kem
*k
)
582 dh_encctx
*de
= (dh_encctx
*)k
;
584 if ((e
= G_CHECK(de
->g
, &rand_global
)) != 0)
586 if (group_check(de
->g
, de
->y
))
587 return ("public key not in subgroup");
591 static void dh_encdestroy(kem
*k
)
593 dh_encctx
*de
= (dh_encctx
*)k
;
594 G_DESTROY(de
->g
, de
->y
);
596 G_DESTROYGROUP(de
->g
);
600 static const kemops dh_encops
= {
601 dh_pubfetch
, sizeof(dh_pub
),
602 dh_encinit
, dh_encdoit
, dh_enccheck
, dh_encdestroy
605 static const kemops bindh_encops
= {
606 dh_pubfetch
, sizeof(dh_pub
),
607 bindh_encinit
, dh_encdoit
, dh_enccheck
, dh_encdestroy
610 static const kemops ec_encops
= {
611 ec_pubfetch
, sizeof(ec_pub
),
612 ec_encinit
, dh_encdoit
, dh_enccheck
, dh_encdestroy
615 static kem
*dh_decinit(key
*k
, void *kd
)
618 dh_encctx
*de
= dh_doinit(k
, &dp
->dp
, dp
->y
, group_prime
, "prime");
619 de
->x
= MP_COPY(dp
->x
);
623 static kem
*bindh_decinit(key
*k
, void *kd
)
626 dh_encctx
*de
= dh_doinit(k
, &dp
->dp
, dp
->y
, group_binary
, "binary");
627 de
->x
= MP_COPY(dp
->x
);
631 static kem
*ec_decinit(key
*k
, void *kd
)
634 dh_encctx
*de
= ec_doinit(k
, ep
->cstr
, &ep
->p
);
635 de
->x
= MP_COPY(ep
->x
);
639 static int dh_decdoit(kem
*k
, dstr
*d
, ghash
*h
)
641 dh_encctx
*de
= (dh_encctx
*)k
;
642 ge
*x
= G_CREATE(de
->g
);
643 size_t n
= de
->g
->noctets
;
644 void *p
= xmalloc(n
);
648 buf_init(&b
, d
->buf
, d
->len
);
649 if (G_FROMRAW(de
->g
, &b
, x
) || group_check(de
->g
, x
))
651 G_EXP(de
->g
, x
, x
, de
->x
);
653 G_TORAW(de
->g
, &b
, x
);
654 GH_HASH(h
, BBASE(&b
), BLEN(&b
));
655 GH_HASH(h
, d
->buf
, d
->len
);
663 static const kemops dh_decops
= {
664 dh_privfetch
, sizeof(dh_priv
),
665 dh_decinit
, dh_decdoit
, dh_enccheck
, dh_encdestroy
668 static const kemops bindh_decops
= {
669 dh_privfetch
, sizeof(dh_priv
),
670 bindh_decinit
, dh_decdoit
, dh_enccheck
, dh_encdestroy
673 static const kemops ec_decops
= {
674 ec_privfetch
, sizeof(ec_priv
),
675 ec_decinit
, dh_decdoit
, dh_enccheck
, dh_encdestroy
678 /* --- X25519 and similar schemes --- */
684 #define XDHDEF(xdh, XDH) \
686 static kem *xdh##_encinit(key *k, void *kd) { return (CREATE(kem)); } \
687 static void xdh##_encdestroy(kem *k) { DESTROY(k); } \
689 static const char *xdh##_enccheck(kem *k) \
691 xdh##_pub *kd = k->kd; \
693 if (kd->pub.sz != XDH##_PUBSZ) \
694 return ("incorrect " #XDH "public key length"); \
698 static int xdh##_encdoit(kem *k, dstr *d, ghash *h) \
700 octet t[XDH##_KEYSZ], z[XDH##_OUTSZ]; \
701 xdh##_pub *kd = k->kd; \
703 rand_get(RAND_GLOBAL, t, sizeof(t)); \
704 dstr_ensure(d, XDH##_PUBSZ); \
705 xdh((octet *)d->buf, t, xdh##_base); \
706 xdh(z, t, kd->pub.k); \
707 d->len += XDH##_PUBSZ; \
708 GH_HASH(h, d->buf, XDH##_PUBSZ); \
709 GH_HASH(h, z, XDH##_OUTSZ); \
713 static const char *xdh##_deccheck(kem *k) \
715 xdh##_priv *kd = k->kd; \
717 if (kd->priv.sz != XDH##_KEYSZ) \
718 return ("incorrect " #XDH " private key length"); \
719 if (kd->pub.sz != XDH##_PUBSZ) \
720 return ("incorrect " #XDH " public key length"); \
724 static int xdh##_decdoit(kem *k, dstr *d, ghash *h) \
726 octet z[XDH##_OUTSZ]; \
727 xdh##_priv *kd = k->kd; \
730 if (d->len != XDH##_PUBSZ) goto done; \
731 xdh(z, kd->priv.k, (const octet *)d->buf); \
732 GH_HASH(h, d->buf, XDH##_PUBSZ); \
733 GH_HASH(h, z, XDH##_OUTSZ); \
739 static const kemops xdh##_encops = { \
740 xdh##_pubfetch, sizeof(xdh##_pub), \
741 xdh##_encinit, xdh##_encdoit, xdh##_enccheck, xdh##_encdestroy \
744 static const kemops xdh##_decops = { \
745 xdh##_privfetch, sizeof(xdh##_priv), \
746 xdh##_encinit, xdh##_decdoit, xdh##_deccheck, xdh##_encdestroy \
752 /* --- Symmetric --- */
754 typedef struct symm_ctx
{
760 static kem
*symm_init(key
*k
, void *kd
)
766 s
= CREATE(symm_ctx
);
769 s
->kp
.e
= KENC_BINARY
;
773 if ((err
= key_unpack(&s
->kp
, kd
, &d
)) != 0) {
774 die(EXIT_FAILURE
, "failed to unpack symmetric key `%s': %s",
775 d
.buf
, key_strerror(err
));
781 static int symm_decdoit(kem
*k
, dstr
*d
, ghash
*h
)
783 symm_ctx
*s
= (symm_ctx
*)k
;
785 GH_HASH(h
, s
->kb
.k
, s
->kb
.sz
);
786 GH_HASH(h
, d
->buf
, d
->len
);
790 static int symm_encdoit(kem
*k
, dstr
*d
, ghash
*h
)
792 dstr_ensure(d
, h
->ops
->c
->hashsz
);
793 d
->len
+= h
->ops
->c
->hashsz
;
794 rand_get(RAND_GLOBAL
, d
->buf
, d
->len
);
795 return (symm_decdoit(k
, d
, h
));
798 static const char *symm_check(kem
*k
) { return (0); }
800 static void symm_destroy(kem
*k
)
801 { symm_ctx
*s
= (symm_ctx
*)k
; key_unpackdone(&s
->kp
); }
803 static const kemops symm_encops
= {
805 symm_init
, symm_encdoit
, symm_check
, symm_destroy
808 static const kemops symm_decops
= {
810 symm_init
, symm_decdoit
, symm_check
, symm_destroy
813 /* --- The switch table --- */
815 const struct kemtab kemtab
[] = {
816 { "rsa", &rsa_encops
, &rsa_decops
},
817 { "dh", &dh_encops
, &dh_decops
},
818 { "bindh", &bindh_encops
, &bindh_decops
},
819 { "ec", &ec_encops
, &ec_decops
},
820 #define XDHTAB(xdh, XDH) \
821 { #xdh, &xdh##_encops, &xdh##_decops },
824 { "symm", &symm_encops
, &symm_decops
},
828 /* --- @getkem@ --- *
830 * Arguments: @key *k@ = the key to load
831 * @const char *app@ = application name
832 * @int wantpriv@ = nonzero if we want to decrypt
833 * @bulk **bc@ = bulk crypto context to set up
835 * Returns: A key-encapsulating thing.
840 kem
*getkem(key
*k
, const char *app
, int wantpriv
, bulk
**bc
)
842 const char *kalg
, *halg
= 0, *balg
= 0;
849 const struct kemtab
*kt
;
851 const struct bulktab
*bt
;
857 /* --- Setup stuff --- */
861 /* --- Get the KEM name --- *
863 * Take the attribute if it's there; otherwise use the key type.
867 if ((q
= key_getattr(0, k
, "kem")) != 0) {
870 } else if (STRNCMP(k
->type
, ==, app
, n
) && k
->type
[n
] == '-') {
871 dstr_puts(&d
, k
->type
);
874 die(EXIT_FAILURE
, "no KEM for key `%s'", t
.buf
);
877 /* --- Grab the bulk encryption scheme --- *
879 * Grab it from the KEM if it's there, but override it from the attribute.
882 if (p
&& (p
= strchr(p
, '/')) != 0) {
886 if ((q
= key_getattr(0, k
, "bulk")) != 0)
889 /* --- Grab the hash function --- */
891 if (p
&& (p
= strchr(p
, '/')) != 0) {
895 if ((q
= key_getattr(0, k
, "hash")) != 0)
898 /* --- Instantiate the KEM --- */
900 for (kt
= kemtab
; kt
->name
; kt
++) {
901 if (STRCMP(kt
->name
, ==, kalg
))
904 die(EXIT_FAILURE
, "key encapsulation mechanism `%s' not found in key `%s'",
907 ko
= wantpriv ? kt
->decops
: kt
->encops
;
913 kd
= xmalloc(ko
->kdsz
);
914 kp
= key_fetchinit(ko
->kf
, 0, kd
);
915 if ((e
= key_fetch(kp
, k
)) != 0) {
916 die(EXIT_FAILURE
, "error fetching key `%s': %s",
917 t
.buf
, key_strerror(e
));
920 kk
= ko
->init(k
, kd
);
925 /* --- Set up the bulk crypto --- */
929 else if ((kk
->hc
= ghash_byname(halg
)) == 0) {
930 die(EXIT_FAILURE
, "hash algorithm `%s' not found in key `%s'",
937 for (bt
= bulktab
, bo
= 0; bt
->name
; bt
++) {
938 if (STRCMP(balg
, ==, bt
->name
))
939 { balg
= 0; goto b_found
; }
940 n
= strlen(bt
->name
);
941 if (STRNCMP(balg
, ==, bt
->name
, n
) && balg
[n
] == '-')
942 { balg
+= n
+ 1; goto b_found
; }
947 bo
= wantpriv ? bt
->decops
: bt
->encops
;
948 *bc
= bo
->init(k
, balg
, kk
->hc
->name
);
952 if ((q
= key_getattr(0, k
, "kdf")) == 0) {
953 dstr_putf(&d
, "%s-mgf", kk
->hc
->name
);
956 if ((kk
->cxc
= gcipher_byname(q
)) == 0) {
957 die(EXIT_FAILURE
, "encryption scheme (KDF) `%s' not found in key `%s'",
961 /* --- Tidy up --- */
968 /* --- @setupkem@ --- *
970 * Arguments: @kem *k@ = key-encapsulation thing
971 * @dstr *d@ = key-encapsulation data
972 * @bulk *bc@ = bulk crypto context to set up
974 * Returns: Zero on success, nonzero on failure.
976 * Use: Initializes all the various symmetric things from a KEM.
979 int setupkem(kem
*k
, dstr
*d
, bulk
*bc
)
987 if (k
->ops
->doit(k
, d
, h
))
989 n
= keysz(GH_CLASS(h
)->hashsz
, k
->cxc
->keysz
);
993 k
->cx
= GC_INIT(k
->cxc
, kd
, n
);
994 bc
->ops
->setup(bc
, k
->cx
);
1002 /* --- @freekem@ --- *
1004 * Arguments: @kem *k@ = key-encapsulation thing
1008 * Use: Frees up a key-encapsulation thing.
1011 void freekem(kem
*k
)
1016 key_fetchdone(k
->kp
);
1023 /*----- That's all, folks -------------------------------------------------*/