From 204d480b9f065082728d39d981f505d3bff58bb2 Mon Sep 17 00:00:00 2001 Message-Id: <204d480b9f065082728d39d981f505d3bff58bb2.1717123932.git.mdw@distorted.org.uk> From: Mark Wooding Date: Thu, 26 May 2016 09:26:09 +0100 Subject: [PATCH] algorithms.c: Add support for Poly1305. Organization: Straylight/Edgeware From: Mark Wooding --- algorithms.c | 357 ++++++++++++++++++++++++++++++++++++++++++++++ catacomb-python.h | 1 + debian/control | 2 +- setup.py | 2 +- 4 files changed, 360 insertions(+), 2 deletions(-) diff --git a/algorithms.c b/algorithms.c index b2eff8b..4561b9a 100644 --- a/algorithms.c +++ b/algorithms.c @@ -1185,6 +1185,357 @@ static PyTypeObject gmhash_pytype_skel = { 0 /* @tp_is_gc@ */ }; +/*----- Special snowflake for Poly1305 ------------------------------------*/ + +PyTypeObject *poly1305cls_pytype, *poly1305key_pytype, *poly1305hash_pytype; + +typedef struct poly1305key_pyobj { + PyHeapTypeObject ty; + poly1305_key k; +} poly1305key_pyobj; + +typedef struct poly1305hash_pyobj { + PyObject_HEAD + unsigned f; +#define f_mask 1u + poly1305_ctx ctx; +} poly1305hash_pyobj; + +#define P1305_F(o) (((poly1305hash_pyobj *)(o))->f) +#define P1305_CTX(o) (&((poly1305hash_pyobj *)(o))->ctx) +CONVFUNC(poly1305hash, poly1305_ctx *, P1305_CTX) + +static PyObject *poly1305hash_pynew(PyTypeObject *ty, + PyObject *arg, PyObject *kw) +{ + char *kwlist[] = { "mask", 0 }; + poly1305key_pyobj *pk = (poly1305key_pyobj *)ty; + poly1305hash_pyobj *ph; + char *m = 0; + int sz; + + if (!PyArg_ParseTupleAndKeywords(arg, kw, "|s#:new", kwlist, &m, &sz)) + return (0); + if (m && sz != POLY1305_MASKSZ) VALERR("bad mask length"); + ph = PyObject_NEW(poly1305hash_pyobj, ty); + ph->f = 0; + if (m) ph->f |= f_mask; + poly1305_macinit(&ph->ctx, &pk->k, m); + Py_INCREF(ty); + return ((PyObject *)ph); +end: + return (0); +} + +static PyObject *poly1305key_pynew(PyTypeObject *ty, + PyObject *arg, PyObject *kw) +{ + char *kwlist[] = { "k", 0 }; + poly1305key_pyobj *pk; + char *k; + int sz; + + if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &k, &sz)) + goto end; + if (keysz(sz, poly1305_keysz) != sz) VALERR("bad key length"); + + pk = newtype(ty, 0, 0); + pk->ty.ht_name = PyString_FromString("poly1305(keyed)"); + pk->ty.ht_type.tp_basicsize = sizeof(poly1305hash_pyobj); + pk->ty.ht_type.tp_name = PyString_AS_STRING(pk->ty.ht_name); + pk->ty.ht_type.tp_base = poly1305hash_pytype; + Py_INCREF(poly1305key_pytype); + pk->ty.ht_type.tp_flags = (Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HEAPTYPE); + pk->ty.ht_type.tp_alloc = PyType_GenericAlloc; + pk->ty.ht_type.tp_free = 0; + pk->ty.ht_type.tp_new = poly1305hash_pynew; + typeready(&pk->ty.ht_type); + + poly1305_keyinit(&pk->k, k, sz); + return ((PyObject *)pk); + +end: + return (0); +} + +static PyObject *poly1305clsget_name(PyObject *me, void *hunoz) + { return (PyString_FromString("poly1305")); } + +static PyObject *poly1305clsget_keysz(PyObject *me, void *hunoz) + { return (keysz_pywrap(poly1305_keysz)); } + +static PyObject *poly1305clsget_masksz(PyObject *me, void *hunoz) + { return (PyInt_FromLong(POLY1305_MASKSZ)); } + +static PyObject *poly1305clsget_tagsz(PyObject *me, void *hunoz) + { return (PyInt_FromLong(POLY1305_TAGSZ)); } + +static PyObject *polymeth_copy(PyObject *me, PyObject *arg) +{ + poly1305hash_pyobj *ph; + if (!PyArg_ParseTuple(arg, ":copy")) return (0); + ph = PyObject_NEW(poly1305hash_pyobj, me->ob_type); + poly1305_copy(&ph->ctx, P1305_CTX(me)); + Py_INCREF(me->ob_type); + return ((PyObject *)ph); +} + +static PyObject *polymeth_hash(PyObject *me, PyObject *arg) +{ + char *p; + int sz; + if (!PyArg_ParseTuple(arg, "s#:hash", &p, &sz)) return (0); + poly1305_hash(P1305_CTX(me), p, sz); + RETURN_ME; +} + +#define POLYMETH_HASHU_(n, W, w) \ + static PyObject *polymeth_hashu##w(PyObject *me, PyObject *arg) \ + { \ + uint##n x; \ + octet b[SZ_##W]; \ + if (!PyArg_ParseTuple(arg, "O&:hashu" #w, convu##n, &x)) goto end; \ + STORE##W(b, n); poly1305_hash(P1305_CTX(me), b, sizeof(b)); \ + RETURN_ME; \ + end: \ + return (0); \ + } +DOUINTCONV(POLYMETH_HASHU_) + +#define POLYMETH_HASHBUF_(n, W, w) \ + static PyObject *polymeth_hashbuf##w(PyObject *me, PyObject *arg) \ + { \ + char *p; \ + int sz; \ + octet b[SZ_##W]; \ + if (!PyArg_ParseTuple(arg, "s#:hashbuf" #w, &p, &sz)) goto end; \ + if (sz > MASK##n) TYERR("string too long"); \ + STORE##W(b, n); poly1305_hash(P1305_CTX(me), b, sizeof(b)); \ + poly1305_hash(P1305_CTX(me), p, sz); \ + RETURN_ME; \ + end: \ + return (0); \ + } +DOUINTCONV(POLYMETH_HASHBUF_) + +static PyObject *polymeth_hashstrz(PyObject *me, PyObject *arg) +{ + char *p; + if (!PyArg_ParseTuple(arg, "s:hashstrz", &p)) return (0); + poly1305_hash(P1305_CTX(me), p, strlen(p) + 1); + RETURN_ME; +} + +static PyObject *polymeth_flush(PyObject *me, PyObject *arg) +{ + if (!PyArg_ParseTuple(arg, ":flush")) return (0); + poly1305_flush(P1305_CTX(me)); + RETURN_ME; +} + +static PyObject *polymeth_concat(PyObject *me, PyObject *arg) +{ + PyObject *pre, *suff; + if (!PyArg_ParseTuple(arg, "OO:concat", &pre, &suff)) return (0); + if (!PyObject_TypeCheck(pre, poly1305hash_pytype) || + !PyObject_TypeCheck(suff, poly1305hash_pytype)) + TYERR("wanted a poly1305hash"); + if (me->ob_type != pre->ob_type || me->ob_type != suff->ob_type) + TYERR("key mismatch"); + if (P1305_CTX(pre)->nbuf) VALERR("prefix is not block-aligned"); + poly1305_concat(P1305_CTX(me), P1305_CTX(pre), P1305_CTX(suff)); + RETURN_ME; +end: + return (0); +} + +static PyObject *polymeth_done(PyObject *me, PyObject *arg) +{ + PyObject *rc; + if (!PyArg_ParseTuple(arg, ":done")) return (0); + if (!(P1305_F(me) & f_mask)) VALERR("no mask"); + rc = bytestring_pywrap(0, POLY1305_TAGSZ); + poly1305_done(P1305_CTX(me), PyString_AS_STRING(rc)); + return (rc); +end: + return (0); +} + +static PyGetSetDef poly1305cls_pygetset[] = { +#define GETSETNAME(op, name) poly1305cls##op##_##name + GET (keysz, "PC.keysz -> acceptable key sizes") + GET (masksz, "PC.masksz -> mask size") + GET (tagsz, "PC.tagsz -> MAC output size") + GET (name, "PC.name -> name of this kind of MAC") +#undef GETSETNAME + { 0 } +}; + +static PyMethodDef poly1305hash_pymethods[] = { +#define METHNAME(name) polymeth_##name + METH (copy, "P.copy() -> PP") + METH (hash, "P.hash(M)") +#define METHU_(n, W, w) METH(hashu##w, "P.hashu" #w "(WORD)") + DOUINTCONV(METHU_) +#undef METHU_ +#define METHBUF_(n, W, w) METH(hashbuf##w, "P.hashbuf" #w "(BYTES)") + DOUINTCONV(METHBUF_) +#undef METHBUF_ + METH (hashstrz, "P.hashstrz(STRING)") + METH (flush, "P.flush()") + METH (concat, "P.concat(PREFIX, SUFFIX)") + METH (done, "P.done() -> TAG") +#undef METHNAME + { 0 } +}; + +static PyTypeObject poly1305cls_pytype_skel = { + PyObject_HEAD_INIT(0) 0, /* Header */ + "Poly1305Class", /* @tp_name@ */ + sizeof(PyHeapTypeObject), /* @tp_basicsize@ */ + 0, /* @tp_itemsize@ */ + + 0, /* @tp_dealloc@ */ + 0, /* @tp_print@ */ + 0, /* @tp_getattr@ */ + 0, /* @tp_setattr@ */ + 0, /* @tp_compare@ */ + 0, /* @tp_repr@ */ + 0, /* @tp_as_number@ */ + 0, /* @tp_as_sequence@ */ + 0, /* @tp_as_mapping@ */ + 0, /* @tp_hash@ */ + 0, /* @tp_call@ */ + 0, /* @tp_str@ */ + 0, /* @tp_getattro@ */ + 0, /* @tp_setattro@ */ + 0, /* @tp_as_buffer@ */ + Py_TPFLAGS_DEFAULT | /* @tp_flags@ */ + Py_TPFLAGS_BASETYPE, + + /* @tp_doc@ */ +"Poly1305 metametaclass. Best not to ask.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + 0, /* @tp_iter@ */ + 0, /* @tp_iternext@ */ + 0, /* @tp_methods@ */ + 0, /* @tp_members@ */ + poly1305cls_pygetset, /* @tp_getset@ */ + 0, /* @tp_base@ */ + 0, /* @tp_dict@ */ + 0, /* @tp_descr_get@ */ + 0, /* @tp_descr_set@ */ + 0, /* @tp_dictoffset@ */ + 0, /* @tp_init@ */ + PyType_GenericAlloc, /* @tp_alloc@ */ + abstract_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + +static PyTypeObject poly1305key_pytype_skel = { + PyObject_HEAD_INIT(0) 0, /* Header */ + "poly1305", /* @tp_name@ */ + sizeof(poly1305key_pyobj), /* @tp_basicsize@ */ + 0, /* @tp_itemsize@ */ + + 0, /* @tp_dealloc@ */ + 0, /* @tp_print@ */ + 0, /* @tp_getattr@ */ + 0, /* @tp_setattr@ */ + 0, /* @tp_compare@ */ + 0, /* @tp_repr@ */ + 0, /* @tp_as_number@ */ + 0, /* @tp_as_sequence@ */ + 0, /* @tp_as_mapping@ */ + 0, /* @tp_hash@ */ + 0, /* @tp_call@ */ + 0, /* @tp_str@ */ + 0, /* @tp_getattro@ */ + 0, /* @tp_setattro@ */ + 0, /* @tp_as_buffer@ */ + Py_TPFLAGS_DEFAULT | /* @tp_flags@ */ + Py_TPFLAGS_BASETYPE, + + /* @tp_doc@ */ +"Poly1305 key.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + 0, /* @tp_iter@ */ + 0, /* @tp_iternext@ */ + 0, /* @tp_methods@ */ + 0, /* @tp_members@ */ + 0, /* @tp_getset@ */ + 0, /* @tp_base@ */ + 0, /* @tp_dict@ */ + 0, /* @tp_descr_get@ */ + 0, /* @tp_descr_set@ */ + 0, /* @tp_dictoffset@ */ + 0, /* @tp_init@ */ + PyType_GenericAlloc, /* @tp_alloc@ */ + poly1305key_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + +static PyTypeObject poly1305hash_pytype_skel = { + PyObject_HEAD_INIT(0) 0, /* Header */ + "Poly1305Hash", /* @tp_name@ */ + sizeof(poly1305hash_pyobj), /* @tp_basicsize@ */ + 0, /* @tp_itemsize@ */ + + 0, /* @tp_dealloc@ */ + 0, /* @tp_print@ */ + 0, /* @tp_getattr@ */ + 0, /* @tp_setattr@ */ + 0, /* @tp_compare@ */ + 0, /* @tp_repr@ */ + 0, /* @tp_as_number@ */ + 0, /* @tp_as_sequence@ */ + 0, /* @tp_as_mapping@ */ + 0, /* @tp_hash@ */ + 0, /* @tp_call@ */ + 0, /* @tp_str@ */ + 0, /* @tp_getattro@ */ + 0, /* @tp_setattro@ */ + 0, /* @tp_as_buffer@ */ + Py_TPFLAGS_DEFAULT | /* @tp_flags@ */ + Py_TPFLAGS_BASETYPE, + + /* @tp_doc@ */ +"Poly1305 MAC context base class.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + 0, /* @tp_iter@ */ + 0, /* @tp_iternext@ */ + poly1305hash_pymethods, /* @tp_methods@ */ + 0, /* @tp_members@ */ + 0, /* @tp_getset@ */ + 0, /* @tp_base@ */ + 0, /* @tp_dict@ */ + 0, /* @tp_descr_get@ */ + 0, /* @tp_descr_set@ */ + 0, /* @tp_dictoffset@ */ + 0, /* @tp_init@ */ + PyType_GenericAlloc, /* @tp_alloc@ */ + abstract_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + + /*----- Pseudorandom permutations -----------------------------------------*/ static PyTypeObject *gcprp_pytype, *gprp_pytype; @@ -1467,6 +1818,9 @@ void algorithms_pyinit(void) INITTYPE(gcmac, type); INITTYPE(gmac, type); INITTYPE(gmhash, ghash); + INITTYPE(poly1305cls, type); + INITTYPE_META(poly1305key, type, poly1305cls); + INITTYPE(poly1305hash, root); INITTYPE(gcprp, type); INITTYPE(gprp, root); addmethods(methods); @@ -1497,6 +1851,9 @@ void algorithms_pyinsert(PyObject *mod) INSERT("GMAC", gmac_pytype); INSERT("GMACHash", gmhash_pytype); INSERT("gcmacs", gcmacs()); + INSERT("Poly1305Class", poly1305cls_pytype); + INSERT("poly1305", poly1305key_pytype); + INSERT("Poly1305Hash", poly1305hash_pytype); INSERT("GCPRP", gcprp_pytype); INSERT("GPRP", gprp_pytype); INSERT("gcprps", gcprps()); diff --git a/catacomb-python.h b/catacomb-python.h index ecdbc30..0949562 100644 --- a/catacomb-python.h +++ b/catacomb-python.h @@ -62,6 +62,7 @@ #include #include #include +#include #include #include #include diff --git a/debian/control b/debian/control index 444feba..c9e5b41 100644 --- a/debian/control +++ b/debian/control @@ -5,7 +5,7 @@ XS-Python-Version: >= 2.6, << 2.8 Maintainer: Mark Wooding Build-Depends: debhelper (>= 9), pkg-config, python, python2.6-dev, python2.7-dev, - mlib-dev (>= 2.2.2.1), catacomb-dev (>= 2.2.5+14) + mlib-dev (>= 2.2.2.1), catacomb-dev (>= 2.3.0.1+3) Standards-Version: 3.8.0 Package: python-catacomb diff --git a/setup.py b/setup.py index 161e2af..fe0ed53 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ import distutils.core as DC import mdwsetup as MS -MS.pkg_config('catacomb', '2.2.0') +MS.pkg_config('catacomb', '2.3.0.1+4') MS.pkg_config('mLib', '2.0.4') cat = DC.Extension('catacomb._base', -- [mdw]