5 * Catcrypt key-encapsulation
7 * (c) 2004 Straylight/Edgeware
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of Catacomb.
14 * Catacomb is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
19 * Catacomb is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public
25 * License along with Catacomb; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
30 /*----- Header files ------------------------------------------------------*/
32 #define _FILE_OFFSET_BITS 64
36 #include <mLib/alloc.h>
37 #include <mLib/dstr.h>
38 #include <mLib/report.h>
50 #include "blowfish-cbc.h"
54 /*----- Key encapsulation -------------------------------------------------*/
58 typedef struct rsa_encctx
{
63 static kem
*rsa_encinit(key
*k
, void *kd
)
65 rsa_encctx
*re
= CREATE(rsa_encctx
);
66 rsa_pubcreate(&re
->rp
, kd
);
70 static int rsa_encdoit(kem
*k
, dstr
*d
, ghash
*h
)
72 rsa_encctx
*re
= (rsa_encctx
*)k
;
73 mp
*x
= mprand_range(MP_NEW
, re
->rp
.rp
->n
, &rand_global
, 0);
74 mp
*y
= rsa_pubop(&re
->rp
, MP_NEW
, x
);
75 size_t n
= mp_octets(re
->rp
.rp
->n
);
77 mp_storeb(x
, d
->buf
, n
);
78 GH_HASH(h
, d
->buf
, n
);
79 mp_storeb(y
, d
->buf
, n
);
86 static const char *rsa_lengthcheck(mp
*n
)
88 if (mp_bits(n
) < 1020) return ("key too short");
92 static const char *rsa_enccheck(kem
*k
)
94 rsa_encctx
*re
= (rsa_encctx
*)k
;
96 if ((e
= rsa_lengthcheck(re
->rp
.rp
->n
)) != 0) return (e
);
100 static void rsa_encdestroy(kem
*k
)
102 rsa_encctx
*re
= (rsa_encctx
*)k
;
103 rsa_pubdestroy(&re
->rp
);
107 static const kemops rsa_encops
= {
108 rsa_pubfetch
, sizeof(rsa_pub
),
109 rsa_encinit
, rsa_encdoit
, rsa_enccheck
, rsa_encdestroy
112 typedef struct rsa_decctx
{
117 static kem
*rsa_decinit(key
*k
, void *kd
)
119 rsa_decctx
*rd
= CREATE(rsa_decctx
);
120 rsa_privcreate(&rd
->rp
, kd
, &rand_global
);
124 static int rsa_decdoit(kem
*k
, dstr
*d
, ghash
*h
)
126 rsa_decctx
*rd
= (rsa_decctx
*)k
;
127 mp
*x
= mp_loadb(MP_NEW
, d
->buf
, d
->len
);
131 if (MP_CMP(x
, >=, rd
->rp
.rp
->n
)) {
135 n
= mp_octets(rd
->rp
.rp
->n
);
137 x
= rsa_privop(&rd
->rp
, x
, x
);
145 static const char *rsa_deccheck(kem
*k
)
147 rsa_decctx
*rd
= (rsa_decctx
*)k
;
149 if ((e
= rsa_lengthcheck(rd
->rp
.rp
->n
)) != 0) return (e
);
153 static void rsa_decdestroy(kem
*k
)
155 rsa_decctx
*rd
= (rsa_decctx
*)k
;
156 rsa_privdestroy(&rd
->rp
);
160 static const kemops rsa_decops
= {
161 rsa_privfetch
, sizeof(rsa_priv
),
162 rsa_decinit
, rsa_decdoit
, rsa_deccheck
, rsa_decdestroy
165 /* --- DH and EC --- */
167 typedef struct dh_encctx
{
174 static dh_encctx
*dh_doinit(key
*k
, const gprime_param
*gp
, mp
*y
,
175 group
*(*makegroup
)(const gprime_param
*),
178 dh_encctx
*de
= CREATE(dh_encctx
);
182 if ((de
->g
= makegroup(gp
)) == 0)
183 die(EXIT_FAILURE
, "bad %s group in key `%s'", what
, t
.buf
);
185 de
->y
= G_CREATE(de
->g
);
186 if (G_FROMINT(de
->g
, de
->y
, y
))
187 die(EXIT_FAILURE
, "bad public key `%s'", t
.buf
);
192 static dh_encctx
*ec_doinit(key
*k
, const char *cstr
, const ec
*y
)
194 dh_encctx
*de
= CREATE(dh_encctx
);
200 if ((e
= ec_getinfo(&ei
, cstr
)) != 0 ||
201 (de
->g
= group_ec(&ei
)) == 0)
202 die(EXIT_FAILURE
, "bad elliptic curve spec in key `%s': %s", t
.buf
, e
);
204 de
->y
= G_CREATE(de
->g
);
205 if (G_FROMEC(de
->g
, de
->y
, y
))
206 die(EXIT_FAILURE
, "bad public curve point `%s'", t
.buf
);
211 static kem
*dh_encinit(key
*k
, void *kd
)
214 dh_encctx
*de
= dh_doinit(k
, &dp
->dp
, dp
->y
, group_prime
, "prime");
218 static kem
*bindh_encinit(key
*k
, void *kd
)
221 dh_encctx
*de
= dh_doinit(k
, &dp
->dp
, dp
->y
, group_binary
, "binary");
225 static kem
*ec_encinit(key
*k
, void *kd
)
228 dh_encctx
*de
= ec_doinit(k
, ep
->cstr
, &ep
->p
);
232 static int dh_encdoit(kem
*k
, dstr
*d
, ghash
*h
)
234 dh_encctx
*de
= (dh_encctx
*)k
;
235 mp
*r
= mprand_range(MP_NEW
, de
->g
->r
, &rand_global
, 0);
236 ge
*x
= G_CREATE(de
->g
);
237 ge
*y
= G_CREATE(de
->g
);
238 size_t n
= de
->g
->noctets
;
241 G_EXP(de
->g
, x
, de
->g
->g
, r
);
242 G_EXP(de
->g
, y
, de
->y
, r
);
244 buf_init(&b
, d
->buf
, n
);
245 G_TORAW(de
->g
, &b
, y
);
246 GH_HASH(h
, BBASE(&b
), BLEN(&b
));
247 buf_init(&b
, d
->buf
, n
);
248 G_TORAW(de
->g
, &b
, x
);
249 GH_HASH(h
, BBASE(&b
), BLEN(&b
));
257 static const char *dh_enccheck(kem
*k
)
259 dh_encctx
*de
= (dh_encctx
*)k
;
261 if ((e
= G_CHECK(de
->g
, &rand_global
)) != 0)
263 if (group_check(de
->g
, de
->y
))
264 return ("public key not in subgroup");
268 static void dh_encdestroy(kem
*k
)
270 dh_encctx
*de
= (dh_encctx
*)k
;
271 G_DESTROY(de
->g
, de
->y
);
273 G_DESTROYGROUP(de
->g
);
277 static const kemops dh_encops
= {
278 dh_pubfetch
, sizeof(dh_pub
),
279 dh_encinit
, dh_encdoit
, dh_enccheck
, dh_encdestroy
282 static const kemops bindh_encops
= {
283 dh_pubfetch
, sizeof(dh_pub
),
284 bindh_encinit
, dh_encdoit
, dh_enccheck
, dh_encdestroy
287 static const kemops ec_encops
= {
288 ec_pubfetch
, sizeof(ec_pub
),
289 ec_encinit
, dh_encdoit
, dh_enccheck
, dh_encdestroy
292 static kem
*dh_decinit(key
*k
, void *kd
)
295 dh_encctx
*de
= dh_doinit(k
, &dp
->dp
, dp
->y
, group_prime
, "prime");
296 de
->x
= MP_COPY(dp
->x
);
300 static kem
*bindh_decinit(key
*k
, void *kd
)
303 dh_encctx
*de
= dh_doinit(k
, &dp
->dp
, dp
->y
, group_binary
, "binary");
304 de
->x
= MP_COPY(dp
->x
);
308 static kem
*ec_decinit(key
*k
, void *kd
)
311 dh_encctx
*de
= ec_doinit(k
, ep
->cstr
, &ep
->p
);
312 de
->x
= MP_COPY(ep
->x
);
316 static int dh_decdoit(kem
*k
, dstr
*d
, ghash
*h
)
318 dh_encctx
*de
= (dh_encctx
*)k
;
319 ge
*x
= G_CREATE(de
->g
);
320 size_t n
= de
->g
->noctets
;
321 void *p
= xmalloc(n
);
325 buf_init(&b
, d
->buf
, d
->len
);
326 if (G_FROMRAW(de
->g
, &b
, x
) || group_check(de
->g
, x
))
328 G_EXP(de
->g
, x
, x
, de
->x
);
330 G_TORAW(de
->g
, &b
, x
);
331 GH_HASH(h
, BBASE(&b
), BLEN(&b
));
332 GH_HASH(h
, d
->buf
, d
->len
);
340 static const kemops dh_decops
= {
341 dh_privfetch
, sizeof(dh_priv
),
342 dh_decinit
, dh_decdoit
, dh_enccheck
, dh_encdestroy
345 static const kemops bindh_decops
= {
346 dh_privfetch
, sizeof(dh_priv
),
347 bindh_decinit
, dh_decdoit
, dh_enccheck
, dh_encdestroy
350 static const kemops ec_decops
= {
351 ec_privfetch
, sizeof(ec_priv
),
352 ec_decinit
, dh_decdoit
, dh_enccheck
, dh_encdestroy
355 /* --- Symmetric --- */
357 typedef struct symm_ctx
{
363 static kem
*symm_init(key
*k
, void *kd
)
369 s
= CREATE(symm_ctx
);
372 s
->kp
.e
= KENC_BINARY
;
376 if ((err
= key_unpack(&s
->kp
, kd
, &d
)) != 0) {
377 die(EXIT_FAILURE
, "failed to unpack symmetric key `%s': %s",
378 d
.buf
, key_strerror(err
));
384 static int symm_decdoit(kem
*k
, dstr
*d
, ghash
*h
)
386 symm_ctx
*s
= (symm_ctx
*)k
;
388 GH_HASH(h
, s
->kb
.k
, s
->kb
.sz
);
389 GH_HASH(h
, d
->buf
, d
->len
);
393 static int symm_encdoit(kem
*k
, dstr
*d
, ghash
*h
)
395 dstr_ensure(d
, h
->ops
->c
->hashsz
);
396 d
->len
+= h
->ops
->c
->hashsz
;
397 rand_get(RAND_GLOBAL
, d
->buf
, d
->len
);
398 return (symm_decdoit(k
, d
, h
));
401 static const char *symm_check(kem
*k
) { return (0); }
403 static void symm_destroy(kem
*k
)
404 { symm_ctx
*s
= (symm_ctx
*)k
; key_unpackdone(&s
->kp
); }
406 static const kemops symm_encops
= {
408 symm_init
, symm_encdoit
, symm_check
, symm_destroy
411 static const kemops symm_decops
= {
413 symm_init
, symm_decdoit
, symm_check
, symm_destroy
416 /* --- The switch table --- */
418 const struct kemtab kemtab
[] = {
419 { "rsa", &rsa_encops
, &rsa_decops
},
420 { "dh", &dh_encops
, &dh_decops
},
421 { "bindh", &bindh_encops
, &bindh_decops
},
422 { "ec", &ec_encops
, &ec_decops
},
423 { "symm", &symm_encops
, &symm_decops
},
427 /* --- @getkem@ --- *
429 * Arguments: @key *k@ = the key to load
430 * @const char *app@ = application name
431 * @int wantpriv@ = nonzero if we want to decrypt
433 * Returns: A key-encapsulating thing.
438 kem
*getkem(key
*k
, const char *app
, int wantpriv
)
440 const char *kalg
, *halg
= 0, *calg
= 0;
447 const struct kemtab
*kt
;
453 /* --- Setup stuff --- */
457 /* --- Get the KEM name --- *
459 * Take the attribute if it's there; otherwise use the key type.
463 if ((q
= key_getattr(0, k
, "kem")) != 0) {
466 } else if (strncmp(k
->type
, app
, n
) == 0 && k
->type
[n
] == '-') {
467 dstr_puts(&d
, k
->type
);
470 die(EXIT_FAILURE
, "no KEM for key `%s'", t
.buf
);
473 /* --- Grab the encryption scheme --- *
475 * Grab it from the KEM if it's there, but override it from the attribute.
478 if (p
&& (p
= strchr(p
, '/')) != 0) {
482 if ((q
= key_getattr(0, k
, "cipher")) != 0)
485 /* --- Grab the hash function --- */
487 if (p
&& (p
= strchr(p
, '/')) != 0) {
491 if ((q
= key_getattr(0, k
, "hash")) != 0)
494 /* --- Instantiate the KEM --- */
496 for (kt
= kemtab
; kt
->name
; kt
++) {
497 if (strcmp(kt
->name
, kalg
) == 0)
500 die(EXIT_FAILURE
, "key encapsulation mechanism `%s' not found in key `%s'",
503 ko
= wantpriv ? kt
->decops
: kt
->encops
;
509 kd
= xmalloc(ko
->kdsz
);
510 kp
= key_fetchinit(ko
->kf
, 0, kd
);
511 if ((e
= key_fetch(kp
, k
)) != 0) {
512 die(EXIT_FAILURE
, "error fetching key `%s': %s",
513 t
.buf
, key_strerror(e
));
516 kk
= ko
->init(k
, kd
);
521 /* --- Set up the algorithms --- */
525 else if ((kk
->h
= ghash_byname(halg
)) == 0) {
526 die(EXIT_FAILURE
, "hash algorithm `%s' not found in key `%s'",
531 kk
->c
= &blowfish_cbc
;
532 else if ((kk
->c
= gcipher_byname(calg
)) == 0) {
533 die(EXIT_FAILURE
, "encryption scheme `%s' not found in key `%s'",
538 if ((q
= key_getattr(0, k
, "kdf")) == 0) {
539 dstr_putf(&d
, "%s-mgf", kk
->h
->name
);
542 if ((kk
->cx
= gcipher_byname(q
)) == 0) {
543 die(EXIT_FAILURE
, "encryption scheme (KDF) `%s' not found in key `%s'",
548 if ((q
= key_getattr(0, k
, "mac")) == 0) {
549 dstr_putf(&d
, "%s-hmac", kk
->h
->name
);
552 if ((kk
->m
= gmac_byname(q
)) == 0) {
554 "message authentication code `%s' not found in key `%s'",
558 /* --- Tidy up --- */
565 /* --- @setupkem@ --- *
567 * Arguments: @kem *k@ = key-encapsulation thing
568 * @dstr *d@ = key-encapsulation data
569 * @gcipher **cx@ = key-expansion function (for IVs)
570 * @gcipher **c@ = where to put initialized encryption scheme
571 * @gmac **m@ = where to put initialized MAC
573 * Returns: Zero on success, nonzero on failure.
575 * Use: Initializes all the various symmetric things from a KEM.
578 int setupkem(kem
*k
, dstr
*d
, gcipher
**cx
, gcipher
**c
, gmac
**m
)
586 if (k
->ops
->doit(k
, d
, h
))
588 n
= keysz(GH_CLASS(h
)->hashsz
, k
->cx
->keysz
);
592 *cx
= GC_INIT(k
->cx
, kd
, n
);
594 cn
= keysz(0, k
->c
->keysz
); n
= cn
;
595 mn
= keysz(0, k
->m
->keysz
); if (mn
> n
) n
= mn
;
597 GC_ENCRYPT(*cx
, 0, kd
, cn
);
598 *c
= GC_INIT(k
->c
, kd
, cn
);
599 GC_ENCRYPT(*cx
, 0, kd
, mn
);
600 *m
= GM_KEY(k
->m
, kd
, mn
);
609 /* --- @freekem@ --- *
611 * Arguments: @kem *k@ = key-encapsulation thing
615 * Use: Frees up a key-encapsulation thing.
623 key_fetchdone(k
->kp
);
629 /*----- That's all, folks -------------------------------------------------*/