.B ec
(elliptic curves). The default is
.BR dh .
-.ne 7
+.ne 9
.TP
.I kx-genalg
Key generation algorithm name to pass to
_
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
_
dh dh-param
ec ec-param
+x25519 empty
+x448 empty
_
.TE
-.ne 7
+.ne 9
.TP
.I kx-param
Options to pass to
_
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
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
naclbox chacha20
_
.TE
-.ne 7
+.ne 8
.TP
.I sig
Signature scheme to use. Must be one of those recognized by
_
dh dsa
ec ecdsa
+x25519 ed25519
+x448 ed448
_
.TE
.ne 12
('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'),
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',
###--------------------------------------------------------------------------
### 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
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[] = {
DH("dh", intdh)
DH("ec", ecdh)
+#define XDHDH(xdh, XDH, gname, groupbits, fieldbits) DH(#xdh, xdh)
+ XDHS(XDHDH)
+#undef XDHDH
+
#undef DH
{ 0 }
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
])
\-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
#include <catacomb/ec.h>
#include <catacomb/ec-raw.h>
#include <catacomb/ec-keys.h>
+#include <catacomb/x25519.h>
+#include <catacomb/x448.h>
#include "priv.h"
#include "protocol.h"
-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