From: Mark Wooding Date: Thu, 26 May 2016 08:26:09 +0000 (+0100) Subject: server/, keys/: Support Bernstein's X25519 and Hamburg's X448 algorithms. X-Git-Tag: 1.0.0pre19~2 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/tripe/commitdiff_plain/26936c8341691d67655a055956656f2506d53a63 server/, keys/: Support Bernstein's X25519 and Hamburg's X448 algorithms. --- diff --git a/keys/tripe-keys.conf.5.in b/keys/tripe-keys.conf.5.in index ab4c9e16..4fc0485a 100644 --- a/keys/tripe-keys.conf.5.in +++ b/keys/tripe-keys.conf.5.in @@ -148,7 +148,7 @@ or .B ec (elliptic curves). The default is .BR dh . -.ne 7 +.ne 9 .TP .I kx-genalg Key generation algorithm name to pass to @@ -166,9 +166,11 @@ kx kx-genalg _ dh dh ec ec +x25519 x25519 +x448 x448 _ .TE -.ne 7 +.ne 9 .TP .I kx-param-genalg Key generation algorithm name to pass to @@ -186,9 +188,11 @@ kx kx-param-genalg _ dh dh-param ec ec-param +x25519 empty +x448 empty _ .TE -.ne 7 +.ne 9 .TP .I kx-param Options to pass to @@ -205,8 +209,11 @@ kx kx-param _ dh \-LS \-b3072 \-B256 ec \-Cnist-p256 +x25519 \fInone +x448 \fInone _ .TE +.ne 9 .TP .I kx-attrs Additional attributes to set on the parameters @@ -214,8 +221,22 @@ Additional attributes to set on the parameters as .IB key = value pairs separated by spaces. -Default is -.BR serialization=constlen . +Default depends on +.I kx +as follows. +.TS +center; +| ci | ci | +| lb | lb |. +_ +kx kx-attrs +_ +dh serialization=constlen +ec serialization=constlen +x25519 \fIempty +x448 \fIempty +_ +.TE .TP .I kx-expire Expiry time for generated keys. Default is @@ -278,7 +299,7 @@ iiv rijndael-cbc naclbox chacha20 _ .TE -.ne 7 +.ne 8 .TP .I sig Signature scheme to use. Must be one of those recognized by @@ -295,6 +316,8 @@ kx sig _ dh dsa ec ecdsa +x25519 ed25519 +x448 ed448 _ .TE .ne 12 diff --git a/keys/tripe-keys.in b/keys/tripe-keys.in index 62b62b6e..cfa740bd 100644 --- a/keys/tripe-keys.in +++ b/keys/tripe-keys.in @@ -239,12 +239,21 @@ def conf_defaults(): ('upload-hook', ': run upload hook'), ('kx', 'dh'), ('kx-genalg', lambda: {'dh': 'dh', - 'ec': 'ec'}[conf['kx']]), + 'ec': 'ec', + 'x25519': 'x25519', + 'x448': 'x448'}[conf['kx']]), ('kx-param-genalg', lambda: {'dh': 'dh-param', - 'ec': 'ec-param'}[conf['kx']]), + 'ec': 'ec-param', + 'x25519': 'empty', + 'x448': 'empty'}[conf['kx']]), ('kx-param', lambda: {'dh': '-LS -b3072 -B256', - 'ec': '-Cnist-p256'}[conf['kx']]), - ('kx-attrs', 'serialization=constlen'), + 'ec': '-Cnist-p256', + 'x25519': '', + 'x448': ''}[conf['kx']]), + ('kx-attrs', lambda: {'dh': 'serialization=constlen', + 'ec': 'serialization=constlen', + 'x25519': '', + 'x448': ''}[conf['kx']]), ('kx-expire', 'now + 1 year'), ('kx-warn-days', '28'), ('bulk', 'iiv'), @@ -259,7 +268,10 @@ def conf_defaults(): or '%s-hmac/%d' % (conf['hash'], C.gchashes[conf['hash']].hashsz * 4)), - ('sig', lambda: {'dh': 'dsa', 'ec': 'ecdsa'}[conf['kx']]), + ('sig', lambda: {'dh': 'dsa', + 'ec': 'ecdsa', + 'x25519': 'ed25519', + 'x448': 'ed448'}[conf['kx']]), ('sig-fresh', 'always'), ('sig-genalg', lambda: {'kcdsa': 'dh', 'dsa': 'dsa', diff --git a/keys/tripe-keys.master b/keys/tripe-keys.master index 121bd910..8e165245 100644 --- a/keys/tripe-keys.master +++ b/keys/tripe-keys.master @@ -18,12 +18,13 @@ ###-------------------------------------------------------------------------- ### Crypto parameters. -## The key-exchange type. May be `dh' or `ec'. +## The key-exchange type. May be `dh', `ec', `x25519', or `x448'. # kx = dh ## Key-generation parameters for key exchange group. # kx-param = -LS -b3072 -B256 # kx-param = -Pnist-p256 +# kx-param = ## Expiry time for peer key-exchange keys. # kx-expire = now + 1 year diff --git a/server/dh.c b/server/dh.c index 314da5e4..5c27a079 100644 --- a/server/dh.c +++ b/server/dh.c @@ -639,6 +639,172 @@ static const char *ecdh_gestr(const dhgrp *gg, const dhge *YY) 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 = 32; }, \ + { 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[] = { @@ -657,6 +823,10 @@ 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 } diff --git a/server/tests.at b/server/tests.at index 88b9d160..f3f7c2e4 100644 --- a/server/tests.at +++ b/server/tests.at @@ -586,10 +586,10 @@ WITH_3TRIPES([alice], [bob], [carol], [-nslip -Tmx], for p in $princs; do TRIPECTL -d$p RELOAD; done AT_DATA([algs-alpha], [dnl -kx-group=ec kx-group-order-bits=256 kx-group-elt-bits=512 +kx-group=curve25519 kx-group-order-bits=252 kx-group-elt-bits=255 hash=sha256 mgf=sha256-mgf hash-sz=32 bulk-transform=naclbox bulk-overhead=20 -cipher=salsa20 cipher-keysz=32 +cipher=chacha20 cipher-keysz=32 mac=poly1305 mac-tagsz=16 cipher-data-limit=2147483648 ]) diff --git a/server/tripe.8.in b/server/tripe.8.in index c19ee57a..9b3be609 100644 --- a/server/tripe.8.in +++ b/server/tripe.8.in @@ -349,6 +349,69 @@ key add \-aec \-pparam \-talice \e \-e"now + 1 year" tripe .VE .RE +.sv -1 +.TP +.B x25519 +.RS +Use Bernstein's X25519 Diffie\(enHellman function. +This is technically a variant on +the general elliptic curve Diffie\(enHellman +available through the +.B ec +setting, +but carefully designed and heavily optimized. +.PP +To create +.B x25519 +keys, +say something like +.VS +key add \-aempty \-eforever \e + \-tparam tripe\-param kx-group=x25519 +.VE +to construct a parameters key +(see +.BR key (1) +for details); +and create the private keys by +.VS +key add \-ax25519 \-pparam \-talice \e + \-e"now + 1 year" tripe +.VE +.RE +.sv -1 +.TP +.B x448 +.RS +Use Hamburg's X448 Diffie\(enHellman function. +Like +.B x25519 +above, +this is technically a variant on +the general elliptic curve Diffie\(enHellman +available through the +.B ec +setting, +but carefully designed and heavily optimized. +.PP +To create +.B x448 +keys, +say something like +.VS +key add \-aempty \-eforever \e + \-tparam tripe\-param kx-group=x448 +.VE +to construct a parameters key +(see +.BR key (1) +for details); +and create the private keys by +.VS +key add \-ax448 \-pparam \-talice \e + \-e"now + 1 year" tripe +.VE +.RE Note that the .BR tripe-keys (8) program provides a rather more convenient means for generating and diff --git a/server/tripe.h b/server/tripe.h index ad2c0bd7..56cd0b40 100644 --- a/server/tripe.h +++ b/server/tripe.h @@ -110,6 +110,8 @@ #include #include #include +#include +#include #include "priv.h" #include "protocol.h" diff --git a/t/keyring-alpha b/t/keyring-alpha index ef20b68f..321bc090 100644 --- a/t/keyring-alpha +++ b/t/keyring-alpha @@ -1,5 +1,5 @@ -65604204:tripe-ec:bob struct:[p=ec,public:0x6df064afcdc923160114d2919f014bcef1051bf5cb3071194088a10be4f0c992,0xea0f0b538cb3ad46d07d9b83eff95458b691bdfbf09188ccd7b0758bebd8f107,private=struct:[x=integer,private,burn:26559628286452801356420934030260728558957937100654818426187327519091722521190],curve=string,shared:nist%2dp256] forever forever bulk=naclbox&hash=sha256 -b10d3366:tripe-ec-param struct:[curve=string,shared:nist%2dp256] forever forever bulk=naclbox&hash=sha256 -1aac2ad7:tripe-ec:bob-new struct:[p=ec,public:0xebf0cb581592dc6244a47e9d2e6bc79f76ecb9e5f6e34d69f9f0d07eab188351,0xa6ec5ff761242a0eef1565fd7a6604dbab7b4a0552226b60f2359bccd3e80f48,private=struct:[x=integer,private,burn:15276384741843750980963471236080551062792600396841148726840678168354415102951],curve=string,shared:nist%2dp256] forever forever bulk=naclbox&hash=sha256 -ec1faca7:tripe-ec:alice struct:[p=ec,public:0xa886b00e1457196c1fd91f11a94cf4a081169602c5e2b576d4182eca470ec253,0xb0fa9a01d4205c912d97c4b4c8d8c5e0af869bd7cdef2139aff7579ca590b4c2,private=struct:[x=integer,private,burn:27337377592101678962721737273774069706724348359128065055711824790983665511674],curve=string,shared:nist%2dp256] forever forever bulk=naclbox&hash=sha256 -73bad30f:tripe-ec:carol struct:[p=ec,public:0xac7b854c5e38a74a005a8940cfe7e9cac692bfb12316de782167632b38ced9fc,0xc4467936d15ba07f4ca5e6a7bbf2afb526dec70de0f0ad78f74010e0998a66cd,private=struct:[x=integer,private,burn:62821717637637708743367607162182045550925703241285672642684065475493697147942],curve=string,shared:nist%2dp256] forever forever bulk=naclbox&hash=sha256 +6f825e20:tripe-x25519:bob struct:[pub=binary,public:r+C4uNU0b06HsBunjoYEuzrij92jZi81/jPaQWjMAG4=,private=struct:[priv=binary,private,burn:jxcgIQSi6Otuvfl0Xd8JXL3p5mNFyuMKxCm4e1Zu2Us=]] forever forever hash=sha256&cipher=chacha20&bulk=naclbox +03349b54:tripe-x25519:bob-new struct:[pub=binary,public:T1Xkv+kA2inWUsoF1HMhQV9l7FFUVAuqJaIfSIbo/wY=,private=struct:[priv=binary,private,burn:yYvE82HsJlk3wOSi1gXJL0laeo1f+Af4u+fjIzU7Hoo=]] forever forever hash=sha256&cipher=chacha20&bulk=naclbox +abff7e38:tripe-x25519-param string,shared:%3cempty%3e forever forever hash=sha256&cipher=chacha20&bulk=naclbox +fbf10a4e:tripe-x25519:alice struct:[pub=binary,public:n27vXTI/1lyxTlx3iDPAYfuhuRrGTc5/ohJfFsvQRl8=,private=struct:[priv=binary,private,burn:9OsXq+xPsDeAujcy6+tLBTyfXuqBYhrKazWzR/6cH5w=]] forever forever hash=sha256&cipher=chacha20&bulk=naclbox +4c758f1e:tripe-x25519:carol struct:[pub=binary,public:yi7XVssUkQePU/1ybS6XkwrqvXqWaN04XboBj/r+jmA=,private=struct:[priv=binary,private,burn:++CCD35eVRUPsML4B4rT4n+QiUpBcQbdO5+WF82b/Bk=]] forever forever hash=sha256&cipher=chacha20&bulk=naclbox