X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb/blobdiff_plain/66ff643c652defc000809488f58db090052ca75e..6a024d24d97cb5d42c0091571735475b849f59f4:/progs/cc-kem.c diff --git a/progs/cc-kem.c b/progs/cc-kem.c index 6c4d7f30..1e99e05d 100644 --- a/progs/cc-kem.c +++ b/progs/cc-kem.c @@ -43,14 +43,128 @@ #include "ec-keys.h" #include "dh.h" #include "rsa.h" +#include "x25519.h" +#include "x448.h" #include "rmd160.h" #include "blowfish-cbc.h" +#include "poly1305.h" +#include "salsa20.h" +#include "chacha.h" #include "cc.h" /*----- Bulk crypto -------------------------------------------------------*/ +/* --- NaCl `secretbox' --- */ + +typedef struct naclbox_encctx { + bulk b; + const gccipher *cc; + gcipher *c; +} naclbox_encctx; + +static bulk *naclbox_init(key *k, const char *calg, const char *halg) +{ + naclbox_encctx *ctx = CREATE(naclbox_encctx); + dstr t = DSTR_INIT; + const char *q; + + key_fulltag(k, &t); + + if ((q = key_getattr(0, k, "cipher")) != 0) calg = q; + if (!calg || strcmp(calg, "salsa20") == 0) ctx->cc = &salsa20; + else if (strcmp(calg, "salsa20/12") == 0) ctx->cc = &salsa2012; + else if (strcmp(calg, "salsa20/8") == 0) ctx->cc = &salsa208; + else if (strcmp(calg, "chacha20") == 0) ctx->cc = &chacha20; + else if (strcmp(calg, "chacha12") == 0) ctx->cc = &chacha12; + else if (strcmp(calg, "chacha8") == 0) ctx->cc = &chacha8; + else { + die(EXIT_FAILURE, + "unknown or inappropriate encryption scheme `%s' in key `%s'", + calg, t.buf); + } + + dstr_destroy(&t); + return (&ctx->b); +} + +static int naclbox_setup(bulk *b, gcipher *cx) +{ + naclbox_encctx *ctx = (naclbox_encctx *)b; + octet k[SALSA20_KEYSZ]; + + GC_ENCRYPT(cx, 0, k, sizeof(k)); + ctx->c = GC_INIT(ctx->cc, k, sizeof(k)); + return (0); +} + +static size_t naclbox_overhead(bulk *b) { return (POLY1305_TAGSZ); } + +static void naclbox_destroy(bulk *b) +{ + naclbox_encctx *ctx = (naclbox_encctx *)b; + + GC_DESTROY(ctx->c); + DESTROY(ctx); +} + +static const char *naclbox_encdoit(bulk *b, uint32 seq, buf *bb, + const void *p, size_t sz) +{ + naclbox_encctx *ctx = (naclbox_encctx *)b; + octet t[32]; + poly1305_key ak; + poly1305_ctx a; + octet *tag, *ct; + + STORE32(t, seq); STORE32(t + 4, 0); GC_SETIV(ctx->c, t); + GC_ENCRYPT(ctx->c, 0, t, POLY1305_KEYSZ + POLY1305_MASKSZ); + poly1305_keyinit(&ak, t, POLY1305_KEYSZ); + poly1305_macinit(&a, &ak, t + POLY1305_KEYSZ); + + tag = buf_get(bb, POLY1305_TAGSZ); assert(tag); + ct = buf_get(bb, sz); assert(ct); + GC_ENCRYPT(ctx->c, p, ct, sz); + poly1305_hash(&a, ct, sz); + poly1305_done(&a, tag); + return (0); +} + +static const char *naclbox_decdoit(bulk *b, uint32 seq, buf *bb, + const void *p, size_t sz) +{ + naclbox_encctx *ctx = (naclbox_encctx *)b; + buf bin; + octet t[32]; + poly1305_key ak; + poly1305_ctx a; + octet *tag, *ct, *pt; + + STORE32(t, seq); STORE32(t + 4, 0); GC_SETIV(ctx->c, t); + GC_ENCRYPT(ctx->c, 0, t, POLY1305_KEYSZ + POLY1305_MASKSZ); + poly1305_keyinit(&ak, t, POLY1305_KEYSZ); + poly1305_macinit(&a, &ak, t + POLY1305_KEYSZ); + + buf_init(&bin, (/*unconst*/ void *)p, sz); + if ((tag = buf_get(&bin, POLY1305_TAGSZ)) == 0) return ("no tag"); + ct = BCUR(&bin); sz = BLEFT(&bin); + poly1305_hash(&a, ct, sz); + poly1305_done(&a, t); + if (!ct_memeq(t, tag, POLY1305_TAGSZ)) return ("authentication failure"); + pt = buf_get(bb, sz); assert(pt); + GC_DECRYPT(ctx->c, ct, pt, sz); + return (0); +} + +static const bulkops naclbox_encops = { + naclbox_init, naclbox_setup, naclbox_overhead, + naclbox_encdoit, naclbox_destroy +}, naclbox_decops = { + naclbox_init, naclbox_setup, naclbox_overhead, + naclbox_decdoit, naclbox_destroy +}; + /* --- Generic composition --- */ typedef struct gencomp_encctx { @@ -185,6 +299,7 @@ static const bulkops gencomp_encops = { const struct bulktab bulktab[] = { { "gencomp", &gencomp_encops, &gencomp_decops }, + { "naclbox", &naclbox_encops, &naclbox_decops }, { 0, 0, 0 } }; @@ -489,6 +604,80 @@ static const kemops ec_decops = { ec_decinit, dh_decdoit, dh_enccheck, dh_encdestroy }; +/* --- X25519 and similar schemes --- */ + +#define XDHS(_) \ + _(x25519, X25519) \ + _(x448, X448) + +#define XDHDEF(xdh, XDH) \ + \ + static kem *xdh##_encinit(key *k, void *kd) { return (CREATE(kem)); } \ + static void xdh##_encdestroy(kem *k) { DESTROY(k); } \ + \ + static const char *xdh##_enccheck(kem *k) \ + { \ + xdh##_pub *kd = k->kd; \ + \ + if (kd->pub.sz != XDH##_PUBSZ) \ + return ("incorrect " #XDH "public key length"); \ + return (0); \ + } \ + \ + static int xdh##_encdoit(kem *k, dstr *d, ghash *h) \ + { \ + octet t[XDH##_KEYSZ], z[XDH##_OUTSZ]; \ + xdh##_pub *kd = k->kd; \ + \ + rand_get(RAND_GLOBAL, t, sizeof(t)); \ + dstr_ensure(d, XDH##_PUBSZ); \ + xdh((octet *)d->buf, t, xdh##_base); \ + xdh(z, t, kd->pub.k); \ + d->len += XDH##_PUBSZ; \ + GH_HASH(h, d->buf, XDH##_PUBSZ); \ + GH_HASH(h, z, XDH##_OUTSZ); \ + return (0); \ + } \ + \ + static const char *xdh##_deccheck(kem *k) \ + { \ + xdh##_priv *kd = k->kd; \ + \ + if (kd->priv.sz != XDH##_KEYSZ) \ + return ("incorrect " #XDH " private key length"); \ + if (kd->pub.sz != XDH##_PUBSZ) \ + return ("incorrect " #XDH " public key length"); \ + return (0); \ + } \ + \ + static int xdh##_decdoit(kem *k, dstr *d, ghash *h) \ + { \ + octet z[XDH##_OUTSZ]; \ + xdh##_priv *kd = k->kd; \ + int rc = -1; \ + \ + if (d->len != XDH##_PUBSZ) goto done; \ + xdh(z, kd->priv.k, (const octet *)d->buf); \ + GH_HASH(h, d->buf, XDH##_PUBSZ); \ + GH_HASH(h, z, XDH##_OUTSZ); \ + rc = 0; \ + done: \ + return (rc); \ + } \ + \ + static const kemops xdh##_encops = { \ + xdh##_pubfetch, sizeof(xdh##_pub), \ + xdh##_encinit, xdh##_encdoit, xdh##_enccheck, xdh##_encdestroy \ + }; \ + \ + static const kemops xdh##_decops = { \ + xdh##_privfetch, sizeof(xdh##_priv), \ + xdh##_encinit, xdh##_decdoit, xdh##_deccheck, xdh##_encdestroy \ + }; + +XDHS(XDHDEF) +#undef XDHDEF + /* --- Symmetric --- */ typedef struct symm_ctx { @@ -557,6 +746,10 @@ const struct kemtab kemtab[] = { { "dh", &dh_encops, &dh_decops }, { "bindh", &bindh_encops, &bindh_decops }, { "ec", &ec_encops, &ec_decops }, +#define XDHTAB(xdh, XDH) \ + { #xdh, &xdh##_encops, &xdh##_decops }, + XDHS(XDHTAB) +#undef XDHTAB { "symm", &symm_encops, &symm_decops }, { 0, 0, 0 } }; @@ -667,16 +860,6 @@ k_found:; halg, t.buf); } - dstr_reset(&d); - if ((q = key_getattr(0, k, "kdf")) == 0) { - dstr_putf(&d, "%s-mgf", kk->hc->name); - q = d.buf; - } - if ((kk->cxc = gcipher_byname(q)) == 0) { - die(EXIT_FAILURE, "encryption scheme (KDF) `%s' not found in key `%s'", - q, t.buf); - } - if (!balg) bt = bulktab; else { @@ -694,6 +877,16 @@ k_found:; *bc = bo->init(k, balg, kk->hc->name); (*bc)->ops = bo; + dstr_reset(&d); + if ((q = key_getattr(0, k, "kdf")) == 0) { + dstr_putf(&d, "%s-mgf", kk->hc->name); + q = d.buf; + } + if ((kk->cxc = gcipher_byname(q)) == 0) { + die(EXIT_FAILURE, "encryption scheme (KDF) `%s' not found in key `%s'", + q, t.buf); + } + /* --- Tidy up --- */ dstr_destroy(&d);