From: Mark Wooding Date: Wed, 12 Apr 2017 17:39:01 +0000 (+0100) Subject: pubkey.c, ...: Support Bernstein's `X25519' key-agreement algorithm. X-Git-Tag: 1.2.0~36^2~2 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/catacomb-python/commitdiff_plain/848ba392a415557f73bbca53e2dc350348f96849 pubkey.c, ...: Support Bernstein's `X25519' key-agreement algorithm. --- diff --git a/catacomb-python.h b/catacomb-python.h index 8f8da9d..679920f 100644 --- a/catacomb-python.h +++ b/catacomb-python.h @@ -87,6 +87,7 @@ #include #include #include +#include #include #include diff --git a/catacomb.c b/catacomb.c index 49d0f40..1d6f7f6 100644 --- a/catacomb.c +++ b/catacomb.c @@ -45,6 +45,7 @@ static const struct nameval consts[] = { C(KF_NONSECRET), C(KF_BURN), C(KF_OPT), C(EC_XONLY), C(EC_YBIT), C(EC_LSB), C(EC_CMPR), C(EC_EXPLY), C(EC_SORT), + C(X25519_KEYSZ), C(X25519_PUBSZ), C(X25519_OUTSZ), #define ENTRY(tag, val, str) C(KERR_##tag), KEY_ERRORS(ENTRY) #undef ENTRY diff --git a/catacomb/__init__.py b/catacomb/__init__.py index 9963572..115e8fe 100644 --- a/catacomb/__init__.py +++ b/catacomb/__init__.py @@ -458,6 +458,43 @@ class _tmp: def sign(me, msg, enc): return me.privop(enc.encode(msg, me.n.nbits)) _augment(RSAPriv, _tmp) +###-------------------------------------------------------------------------- +### Bernstein's elliptic curve crypto. + +X25519_BASE = \ + bytes('0900000000000000000000000000000000000000000000000000000000000000') + +Z128 = bytes('00000000000000000000000000000000') + +class _BoxyPub (object): + def __init__(me, pub, *kw, **kwargs): + if len(pub) != me._PUBSZ: raise ValueError, 'bad public key' + super(_BoxyPub, me).__init__(*kw, **kwargs) + me.pub = pub + +class _BoxyPriv (_BoxyPub): + def __init__(me, priv, pub = None, *kw, **kwargs): + if len(priv) != me._KEYSZ: raise ValueError, 'bad private key' + if pub is None: pub = me._op(priv, me._BASE) + super(_BoxyPriv, me).__init__(pub = pub, *kw, **kwargs) + me.priv = priv + def agree(me, you): return me._op(me.priv, you.pub) + def boxkey(me, recip): + return me._hashkey(me.agree(recip)) + def box(me, recip, n, m): + return secret_box(me.boxkey(recip), n, m) + def unbox(me, recip, n, c): + return secret_unbox(me.boxkey(recip, n, c)) + +class X25519Pub (_BoxyPub): + _PUBSZ = X25519_PUBSZ + _BASE = X25519_BASE + +class X25519Priv (_BoxyPriv, X25519Pub): + _KEYSZ = X25519_KEYSZ + def _op(me, k, X): return x25519(k, X) + def _hashkey(me, z): return hsalsa20_prf(z, Z128) + ###-------------------------------------------------------------------------- ### Built-in named curves and prime groups. diff --git a/pubkey.c b/pubkey.c index 311152a..50fa78c 100644 --- a/pubkey.c +++ b/pubkey.c @@ -1118,6 +1118,24 @@ end: return (rc); } +/*----- X25519 ------------------------------------------------------------*/ + +static PyObject *meth_x25519(PyObject *me, PyObject *arg) +{ + const char *k, *p; + Py_ssize_t ksz, psz; + PyObject *rc = 0; + if (!PyArg_ParseTuple(arg, "s#s#:x25519", &k, &ksz, &p, &psz)) goto end; + if (ksz != X25519_KEYSZ) VALERR("bad key length"); + if (psz != X25519_PUBSZ) VALERR("bad public length"); + rc = bytestring_pywrap(0, X25519_OUTSZ); + x25519((octet *)PyString_AS_STRING(rc), + (const octet *)k, (const octet *)p); + return (rc); +end: + return (0); +} + /*----- Global stuff ------------------------------------------------------*/ static PyMethodDef methods[] = { @@ -1132,6 +1150,8 @@ static PyMethodDef methods[] = { KWMETH(_pss_decode, 0) KWMETH(_RSAPriv_generate, "\ generate(NBITS, [event = pgen_nullev, rng = rand, nsteps = 0]) -> R") + METH (x25519, "\ +x25519(KEY, PUBLIC) -> SHARED") #undef METHNAME { 0 } };