KLOAD_HALF(pre, ty, TY, priv, PRIV, setgroup, setpriv, setpub) \
KLOAD_HALF(pre, ty, TY, pub, PUB, setgroup, { kd->k = 0; }, setpub)
+enum { DHSER_V0, DHSER_CONSTLEN };
+
+static int get_serialization(key_file *kf, key *k, dstr *e)
+{
+ const char *p = key_getattr(kf, k, "serialization");
+ if (!p || strcmp(p, "v0") == 0) return (DHSER_V0);
+ else if (strcmp(p, "constlen") == 0) return (DHSER_CONSTLEN);
+ else {
+ a_format(e, "unknown-serialization-format", "%s", p, A_END);
+ return (-1);
+ }
+}
+
#ifndef NTRACE
static void setupstr(mptext_stringctx *sc)
{ sc->buf = (char *)buf_u; sc->lim = sc->buf + sizeof(buf_u); }
mpmont mm;
mp *q, *G;
size_t gesz;
+ int ser;
} intdh_grp;
typedef struct intdh_sc { mp *x; } intdh_sc;
typedef struct intdh_ge { mp *X; } intdh_ge;
-static dhgrp *intdh_mkgroup(const dh_param *dp)
+static dhgrp *intdh_mkgroup(key_file *kf, key *k,
+ const dh_param *dp, dstr *e)
{
- intdh_grp *g = CREATE(intdh_grp);
+ intdh_grp *g;
+ int ser;
+
+ if ((ser = get_serialization(kf, k, e)) < 0) return (0);
+ g = CREATE(intdh_grp);
+ g->ser = ser;
g->_g.scsz = mp_octets(dp->q);
g->gesz = mp_octets(dp->p);
mpmont_create(&g->mm, dp->p);
}
KLOAD(intdh, dh, DH,
- { kd->grp = intdh_mkgroup(&p.dp); },
+ { if ((kd->grp = intdh_mkgroup(kf, k, &p.dp, e)) == 0) goto fail; },
{ kd->k = intdh_mptosc(kd->grp, p.x); },
{ kd->K = intdh_mptoge(kd->grp, p.y); })
static int intdh_samegrpp(const dhgrp *gg, const dhgrp *hh)
{
const intdh_grp *g = (const intdh_grp *)gg, *h = (const intdh_grp *)hh;
- return (MP_EQ(g->mm.m, h->mm.m) && MP_EQ(g->q, h->q) && MP_EQ(g->G, h->G));
+ return (MP_EQ(g->mm.m, h->mm.m) &&
+ MP_EQ(g->q, h->q) && MP_EQ(g->G, h->G) &&
+ g->ser == h->ser);
}
static void intdh_freegrp(dhgrp *gg)
const octet *p;
switch (fmt) {
- case DHFMT_VAR: case DHFMT_HASH:
+ case DHFMT_HASH: if (g->ser == DHSER_CONSTLEN) goto std;
+ case DHFMT_VAR:
if ((t = buf_getmp(b)) == 0) return (0);
break;
- case DHFMT_STD:
+ case DHFMT_STD: std:
if ((p = buf_get(b, g->gesz)) == 0) return (0);
t = mp_loadb(MP_NEW, p, g->gesz);
break;
t = mpmont_reduce(&g->mm, MP_NEW, Y->X);
switch (fmt) {
- case DHFMT_VAR: case DHFMT_HASH:
+ case DHFMT_HASH: if (g->ser == DHSER_CONSTLEN) goto std;
+ case DHFMT_VAR:
rc = buf_putmp(b, t);
break;
- case DHFMT_STD:
+ case DHFMT_STD: std:
if ((p = buf_get(b, g->gesz)) == 0)
rc = -1;
else {
dhgrp _g;
ec_info ei;
ec P;
+ int ser;
} ecdh_grp;
typedef struct ecdh_sc { mp *x; } ecdh_sc;
typedef struct ecdh_ge { ec Q; } ecdh_ge;
-static dhgrp *ecdh_mkgroup(const char *cstr, dstr *e)
+static dhgrp *ecdh_mkgroup(key_file *kf, key *k, const char *cstr, dstr *e)
{
ecdh_grp *g;
ec_info ei;
+ int ser;
const char *err;
+ if ((ser = get_serialization(kf, k, e)) < 0) return (0);
if ((err = ec_getinfo(&ei, cstr)) != 0) {
a_format(e, "decode-failed", "%s", err, A_END);
return (0);
}
g = CREATE(ecdh_grp);
+ g->ser = ser;
g->ei = ei;
EC_CREATE(&g->P); EC_IN(g->ei.c, &g->P, &g->ei.g);
g->_g.scsz = mp_octets(g->ei.r);
}
KLOAD(ecdh, ec, EC,
- { if ((kd->grp = ecdh_mkgroup(p.cstr, e)) == 0) goto fail; },
+ { if ((kd->grp = ecdh_mkgroup(kf, k, p.cstr, e)) == 0) goto fail; },
{ kd->k = ecdh_mptosc(kd->grp, p.x); },
{ if ((kd->K = ecdh_ectoge(kd->grp, &p.p)) == 0) {
a_format(e, "bad-public-vector", A_END);
static int ecdh_samegrpp(const dhgrp *gg, const dhgrp *hh)
{
const ecdh_grp *g = (const ecdh_grp *)gg, *h = (const ecdh_grp *)hh;
- return (ec_sameinfop(&g->ei, &h->ei));
+ return (ec_sameinfop(&g->ei, &h->ei) &&
+ g->ser == h->ser);
}
static void ecdh_freegrp(dhgrp *gg)
ec T = EC_INIT;
switch (fmt) {
- case DHFMT_VAR: case DHFMT_HASH: if (buf_getec(b, &T)) return (0); break;
- case DHFMT_STD: if (ec_getraw(g->ei.c, b, &T)) return (0); break;
+ case DHFMT_HASH: if (g->ser == DHSER_CONSTLEN) goto std;
+ case DHFMT_VAR: if (buf_getec(b, &T)) return (0); break;
+ case DHFMT_STD: std: if (ec_getraw(g->ei.c, b, &T)) return (0); break;
default:
abort();
}
EC_OUT(g->ei.c, &T, &Y->Q);
switch (fmt) {
- case DHFMT_VAR: case DHFMT_HASH: rc = buf_putec(b, &T); break;
- case DHFMT_STD: rc = ec_putraw(g->ei.c, b, &T); break;
+ case DHFMT_HASH: if (g->ser == DHSER_CONSTLEN) goto std;
+ case DHFMT_VAR: rc = buf_putec(b, &T); break;
+ case DHFMT_STD: std: rc = ec_putraw(g->ei.c, b, &T); break;
default: abort();
}
EC_DESTROY(&T);
static void ecdh_freege(const dhgrp *gg, dhge *YY)
{ ecdh_ge *Y = (ecdh_ge *)YY; EC_DESTROY(&Y->Q); DESTROY(Y); }
+/*----- The X25519 and similar groups -------------------------------------*/
+
+#define XDHS(_) \
+ _(x25519, X25519, "curve25519", 252, 255) \
+ _(x448, X448, "ed448-goldilocks", 446, 448)
+
+#ifdef NTRACE
+# define XDHTRACE(xdh, XDH, gname)
+#else
+
+ static const char *binstr(const octet *p, size_t sz)
+ {
+ char *q;
+
+ for (q = (char *)buf_u; sz--; p++, q += 2) sprintf(q, "%02x", *p);
+ return ((const char *)buf_u);
+ }
+
+# define XDHTRACE(xdh, XDH, gname) \
+ static void xdh##_tracegrp(const dhgrp *g) \
+ { trace(T_CRYPTO, "crypto: group type `" gname "'"); } \
+ \
+ static const char *xdh##_scstr(const dhgrp *g, const dhsc *xx) \
+ { \
+ const xdh##_sc *x = (const xdh##_sc *)xx; \
+ return (binstr(x->x, XDH##_KEYSZ)); \
+ } \
+ \
+ static const char *xdh##_gestr(const dhgrp *g, const dhge *YY) \
+ { \
+ const xdh##_ge *Y = (const xdh##_ge *)YY; \
+ return (binstr(Y->X, XDH##_PUBSZ)); \
+ }
+#endif
+
+#define XDHDEF(xdh, XDH, gname, groupbits, fieldbits) \
+ \
+ typedef struct xdh##_sc { octet x[XDH##_KEYSZ]; } xdh##_sc; \
+ typedef struct xdh##_ge { octet X[XDH##_PUBSZ]; } xdh##_ge; \
+ \
+ XDHTRACE(xdh, XDH, gname) \
+ \
+ static dhsc *xdh##_bintosc(const key_bin *b) \
+ { \
+ xdh##_sc *x; \
+ \
+ if (b->sz != XDH##_KEYSZ) return (0); \
+ x = CREATE(xdh##_sc); \
+ memcpy(x->x, b->k, XDH##_KEYSZ); \
+ return ((dhsc *)x); \
+ } \
+ \
+ static dhge *xdh##_bintoge(const key_bin *b) \
+ { \
+ xdh##_ge *Y; \
+ \
+ if (b->sz != XDH##_PUBSZ) return (0); \
+ Y = CREATE(xdh##_ge); \
+ memcpy(Y->X, b->k, XDH##_PUBSZ); \
+ return ((dhge *)Y); \
+ } \
+ \
+ KLOAD(xdh, xdh, XDH, \
+ { kd->grp = CREATE(dhgrp); \
+ kd->grp->scsz = XDH##_KEYSZ; \
+ }, \
+ { if ((kd->k = xdh##_bintosc(&p.priv)) == 0) { \
+ a_format(e, "bad-private-key", A_END); \
+ goto fail; \
+ } \
+ }, \
+ { if ((kd->K = xdh##_bintoge(&p.pub)) == 0) { \
+ a_format(e, "bad-public-vector", A_END); \
+ goto fail; \
+ } \
+ }) \
+ \
+ static const char *xdh##_checkgrp(const dhgrp *g) \
+ { return (0); } \
+ \
+ static void xdh##_grpinfo(const dhgrp *g, admin *adm) \
+ { \
+ a_info(adm, \
+ "kx-group=" gname, \
+ "kx-group-order-bits=%d", (groupbits), \
+ "kx-group-elt-bits=%d", (fieldbits), \
+ A_END); \
+ } \
+ \
+ static int xdh##_samegrpp(const dhgrp *g, const dhgrp *hh) \
+ { return (1); } \
+ \
+ static void xdh##_freegrp(dhgrp *g) \
+ { DESTROY(g); } \
+ \
+ static dhsc *xdh##_ldsc(const dhgrp *g, const void *p, size_t sz) \
+ { \
+ xdh##_sc *x; \
+ if (sz != XDH##_KEYSZ) return (0); \
+ x = CREATE(xdh##_sc); \
+ memcpy(x->x, p, XDH##_KEYSZ); \
+ return ((dhsc *)x); \
+ } \
+ \
+ static int xdh##_stsc(const dhgrp *g, void *p, size_t sz, \
+ const dhsc *xx) \
+ { \
+ const xdh##_sc *x = (const xdh##_sc *)xx; \
+ if (sz != XDH##_KEYSZ) return (-1); \
+ memcpy(p, x->x, XDH##_KEYSZ); \
+ return (0); \
+ } \
+ \
+ static dhsc *xdh##_randsc(const dhgrp *g) \
+ { \
+ xdh##_sc *x = CREATE(xdh##_sc); \
+ rand_get(RAND_GLOBAL, x->x, XDH##_KEYSZ); \
+ return ((dhsc *)x); \
+ } \
+ \
+ static void xdh##_freesc(const dhgrp *g, dhsc *xx) \
+ { xdh##_sc *x = (xdh##_sc *)xx; DESTROY(x); } \
+ \
+ static dhge *xdh##_ldge(const dhgrp *g, buf *b, int fmt) \
+ { \
+ xdh##_ge *Y; \
+ const octet *p; \
+ \
+ if ((p = buf_get(b, XDH##_PUBSZ)) == 0) return (0); \
+ Y = CREATE(xdh##_ge); memcpy(Y->X, p, XDH##_PUBSZ); \
+ return ((dhge *)Y); \
+ } \
+ \
+ static int xdh##_stge(const dhgrp *g, buf *b, \
+ const dhge *YY, int fmt) \
+ { \
+ const xdh##_ge *Y = (const xdh##_ge *)YY; \
+ return (buf_put(b, Y->X, XDH##_PUBSZ)); \
+ } \
+ \
+ static int xdh##_checkge(const dhgrp *g, const dhge *YY) \
+ { return (0); } \
+ \
+ static int xdh##_eq(const dhgrp *g, const dhge *YY, const dhge *ZZ) \
+ { \
+ const xdh##_ge \
+ *Y = (const xdh##_ge *)YY, *Z = (const xdh##_ge *)ZZ; \
+ return (ct_memeq(Y->X, Z->X, XDH##_PUBSZ)); \
+ } \
+ \
+ static dhge *xdh##_mul(const dhgrp *g, \
+ const dhsc *xx, const dhge *YY) \
+ { \
+ const xdh##_sc *x = (const xdh##_sc *)xx; \
+ const xdh##_ge *Y = (const xdh##_ge *)YY; \
+ xdh##_ge *Z = CREATE(xdh##_ge); \
+ \
+ xdh(Z->X, x->x, Y ? Y->X : xdh##_base); \
+ return ((dhge *)Z); \
+ } \
+ \
+ static void xdh##_freege(const dhgrp *g, dhge *YY) \
+ { xdh##_ge *Y = (xdh##_ge *)YY; DESTROY(Y); }
+
+XDHS(XDHDEF)
+
+#undef XDHDEF
+
/*----- Diffie--Hellman group table ---------------------------------------*/
const dhops dhtab[] = {
DH("dh", intdh)
DH("ec", ecdh)
+#define XDHDH(xdh, XDH, gname, groupbits, fieldbits) DH(#xdh, xdh)
+ XDHS(XDHDH)
+#undef XDHDH
+
#undef DH
{ 0 }