From 46e6ad89d596d0987f00440c77e42c36f7d347f7 Mon Sep 17 00:00:00 2001 Message-Id: <46e6ad89d596d0987f00440c77e42c36f7d347f7.1716575390.git.mdw@distorted.org.uk> From: Mark Wooding Date: Mon, 26 Sep 2005 12:58:11 +0000 Subject: [PATCH] Checkin, Debianized and more or less complete. Organization: Straylight/Edgeware From: mdw --- .gdbinit | 1 + MANIFEST.in | 6 +- Makefile | 4 +- algorithms.c | 39 + buffer.c | 540 +++++++++++ bytestring.c | 22 +- catacomb-python.h | 36 +- catacomb.c | 112 ++- catacomb/__init__.py | 6 +- debian/changelog | 5 + debian/control | 27 + debian/copyright | 16 + debian/rules | 67 ++ ec.c | 2 +- key.c | 2035 +++++++++++++++++++++++++++++++++++++++++- pubkey.c | 2 +- setup.py | 15 +- share.c | 640 +++++++++++++ 18 files changed, 3526 insertions(+), 49 deletions(-) create mode 100644 buffer.c create mode 100644 debian/changelog create mode 100644 debian/control create mode 100644 debian/copyright create mode 100755 debian/rules create mode 100644 share.c diff --git a/.gdbinit b/.gdbinit index b48f913..3be9630 100644 --- a/.gdbinit +++ b/.gdbinit @@ -3,3 +3,4 @@ dir py/python2.4-2.4+2.4.1rc2 set env LD_LIBRARY_PATH=/home/mdw/src/catacomb/deb-build/.libs set env PYTHONPATH=/usr/lib/python2.4/lib-dynload cd build/lib.linux-i686-2.4 +## set args test.py diff --git a/MANIFEST.in b/MANIFEST.in index a00416c..eed9938 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,7 @@ include README Makefile MANIFEST MANIFEST.in include *.c *.h -recursive-include catacomb *.py +include algorithms.py +include pwsafe +include debian/rules debian/control debian/changelog debian/copyright +recursive-include catacomb *.py +prune py diff --git a/Makefile b/Makefile index 37f171f..b0564e4 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ ## Makefile PYTHON = python -prefix=/usr/local +prefix = /usr/local all: setup.py $(PYTHON) setup.py build @@ -16,4 +16,4 @@ dist: setup.py install: setup.py $(PYTHON) setup.py install --prefix $(prefix) -.PHONY: all clean dist +.PHONY: all clean dist install diff --git a/algorithms.c b/algorithms.c index 2113cc5..bd094fd 100644 --- a/algorithms.c +++ b/algorithms.c @@ -777,9 +777,48 @@ static PyGetSetDef gchash_pygetset[] = { { 0 } }; +#define GHMETH_HASHU_(n, W, w) \ + static PyObject *ghmeth_hashu##w(PyObject *me, PyObject *arg) \ + { \ + uint##n x; \ + if (!PyArg_ParseTuple(arg, "O&:hashu" #w, convu##n, &x)) goto end; \ + GH_HASHU##W(GHASH_H(me), x); \ + RETURN_ME; \ + end: \ + return (0); \ + } +DOUINTCONV(GHMETH_HASHU_) + +#define GHMETH_HASHBUF_(n, W, w) \ + static PyObject *ghmeth_hashbuf##w(PyObject *me, PyObject *arg) \ + { \ + char *p; \ + int sz; \ + if (!PyArg_ParseTuple(arg, "s#:hashbuf" #w, &p, &sz)) goto end; \ + if (sz > MASK##n) TYERR("string too long"); \ + GH_HASHBUF##W(GHASH_H(me), p, sz); \ + RETURN_ME; \ + end: \ + return (0); \ + } +DOUINTCONV(GHMETH_HASHBUF_) + +static PyObject *ghmeth_hashstrz(PyObject *me, PyObject *arg) +{ + char *p; + if (!PyArg_ParseTuple(arg, "s:hashstrz", &p)) return (0); + GH_HASHSTRZ(GHASH_H(me), p); + RETURN_ME; +} + static PyMethodDef ghash_pymethods[] = { #define METHNAME(name) ghmeth_##name METH (hash, "H.hash(M)") +#define METHU_(n, W, w) METH(hashu##w, "H.hashu" #w "(WORD)") + DOUINTCONV(METHU_) +#define METHBUF_(n, W, w) METH(hashbuf##w, "H.hashbuf" #w "(BYTES)") + DOUINTCONV(METHBUF_) + METH (hashstrz, "H.hashstrz(STRING)") METH (done, "H.done() -> HASH") #undef METHNAME { 0 } diff --git a/buffer.c b/buffer.c new file mode 100644 index 0000000..8dc885a --- /dev/null +++ b/buffer.c @@ -0,0 +1,540 @@ +/* -*-c-*- + * + * $Id$ + * + * Reading and writing buffers of stuff + * + * (c) 2005 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of the Python interface to Catacomb. + * + * Catacomb/Python is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Catacomb/Python is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Catacomb/Python; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/*----- Header files ------------------------------------------------------*/ + +#include "catacomb-python.h" + +/*----- Data structures ---------------------------------------------------*/ + +typedef struct buf_pyobj { + PyObject_HEAD + buf b; +} buf_pyobj; + +static PyTypeObject *rbuf_pytype, *wbuf_pytype; +#define RBUF_PYCHECK(o) PyObject_TypeCheck((o), rbuf_pytype) +#define WBUF_PYCHECK(o) PyObject_TypeCheck((o), wbuf_pytype) +#define BUF_B(o) (&((buf_pyobj *)(o))->b) + +/*----- Exceptions --------------------------------------------------------*/ + +static PyObject *buferr; + +#define BUFERR() do { PyErr_SetNone(buferr); goto end; } while (0) + +/*----- Read buffers ------------------------------------------------------*/ + +static PyObject *rbuf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) +{ + char *p, *q; + int n; + buf_pyobj *me = 0; + static char *kwlist[] = { "data", 0 }; + + if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &p, &n)) + goto end; + me = (buf_pyobj *)ty->tp_alloc(ty, 0); + q = xmalloc(n); + memcpy(q, p, n); + buf_init(&me->b, q, n); +end: + return ((PyObject *)me); +} + +static void buf_pydealloc(PyObject *me) + { xfree(BBASE(BUF_B(me))); FREEOBJ(me); } + +static int rbuf_pysegcount(PyObject *me, int *nn) + { if (nn) *nn = BSZ(BUF_B(me)); return (1); } + +static int rbuf_pyreadbuf(PyObject *me, int seg, void **q) + { assert(seg == 0); *q = BBASE(BUF_B(me)); return (BSZ(BUF_B(me))); } + +static PyObject *rbmeth_skip(PyObject *me, PyObject *arg) +{ + size_t n; + + if (!PyArg_ParseTuple(arg, "O&:skip", convszt, &n)) goto end; + if (!buf_get(BUF_B(me), n)) BUFERR(); + RETURN_ME; +end: + return (0); +} + +static PyObject *rbmeth_get(PyObject *me, PyObject *arg) +{ + void *p; + size_t n; + + if (!PyArg_ParseTuple(arg, "O&:get", convszt, &n)) goto end; + if ((p = buf_get(BUF_B(me), n)) == 0) BUFERR(); + return (bytestring_pywrap(p, n)); +end: + return (0); +} + +#define RBMETH_GETU_(n, W, w) \ + static PyObject *rbmeth_getu##w(PyObject *me, PyObject *arg) \ + { \ + uint##n x; \ + if (!PyArg_ParseTuple(arg, ":getu" #w)) goto end; \ + if (buf_getu##w(BUF_B(me), &x)) BUFERR(); \ + return (getu32(x)); \ + end: \ + return (0); \ + } +DOUINTCONV(RBMETH_GETU_) + +#define RBMETH_GETBLK_(n, W, w) \ + static PyObject *rbmeth_getblk##w(PyObject *me, PyObject *arg) \ + { \ + size_t sz; \ + char *q; \ + if (!PyArg_ParseTuple(arg, ":getblk" #w)) goto end; \ + if ((q = buf_getmem##w(BUF_B(me), &sz)) == 0) BUFERR(); \ + return (bytestring_pywrap(q, sz)); \ + end: \ + return (0); \ + } +BUF_DOSUFFIXES(RBMETH_GETBLK_) + +static PyObject *rbmeth_getmp(PyObject *me, PyObject *arg) +{ + mp *x; + if (!PyArg_ParseTuple(arg, ":getmp")) goto end; + if ((x = buf_getmp(BUF_B(me))) == 0) BUFERR(); + return (mp_pywrap(x)); +end: + return (0); +} + +static PyObject *rbmeth_getgf(PyObject *me, PyObject *arg) +{ + mp *x; + if (!PyArg_ParseTuple(arg, ":getgf")) goto end; + if ((x = buf_getmp(BUF_B(me))) == 0) BUFERR(); + return (gf_pywrap(x)); +end: + return (0); +} + +static PyObject *rbmeth_getecpt(PyObject *me, PyObject *arg, PyObject *kw) +{ + PyObject *cobj = Py_None; + static char *kwlist[] = { "curve", 0 }; + ec pt = EC_INIT; + if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O:getecpt", kwlist, &cobj)) + goto end; + if (cobj == Py_None) cobj = (PyObject *)ecpt_pytype; + if (!PyType_Check(cobj) || + !PyType_IsSubtype((PyTypeObject *)cobj, ecpt_pytype)) + TYERR("expected elliptic curve type"); + if (buf_getec(BUF_B(me), &pt)) BUFERR(); + return (ecpt_pywrapout(cobj, &pt)); +end: + return (0); +} + +static PyObject *rbmeth_getecptraw(PyObject *me, PyObject *arg) +{ + PyTypeObject *cobj = ecpt_pytype; + ec pt = EC_INIT; + if (!PyArg_ParseTuple(arg, "O!:getecptraw", eccurve_pytype, &cobj)) + goto end; + if (ec_getraw(ECCURVE_C(cobj), BUF_B(me), &pt)) BUFERR(); + return (ecpt_pywrapout(cobj, &pt)); +end: + return (0); +} + +static PyObject *rbmeth_getge(PyObject *me, PyObject *arg) +{ + PyObject *gobj; + ge *x = 0; + if (!PyArg_ParseTuple(arg, "O!:getge", group_pytype, &gobj)) goto end; + x = G_CREATE(GROUP_G(gobj)); + if (G_FROMBUF(GROUP_G(gobj), BUF_B(me), x)) BUFERR(); + return (ge_pywrap(gobj, x)); +end: + if (x) G_DESTROY(GROUP_G(gobj), x); + return (0); +} + +static PyObject *rbmeth_getgeraw(PyObject *me, PyObject *arg) +{ + PyObject *gobj; + ge *x = 0; + if (!PyArg_ParseTuple(arg, "O!:getgeraw", group_pytype, &gobj)) goto end; + x = G_CREATE(GROUP_G(gobj)); + if (G_FROMRAW(GROUP_G(gobj), BUF_B(me), x)) BUFERR(); + return (ge_pywrap(gobj, x)); +end: + if (x) G_DESTROY(GROUP_G(gobj), x); + return (0); +} + +static PyObject *rbget_size(PyObject *me, void *hunoz) + { return (PyInt_FromLong(BSZ(BUF_B(me)))); } +static PyObject *rbget_left(PyObject *me, void *hunoz) + { return (PyInt_FromLong(BLEFT(BUF_B(me)))); } +static PyObject *rbget_endp(PyObject *me, void *hunoz) + { return (getbool(!BLEFT(BUF_B(me)))); } + +static PyGetSetDef rbuf_pygetset[] = { +#define GETSETNAME(op, name) rb##op##_##name + GET (size, "RBUF.size -> SIZE") + GET (left, "RBUF.left -> REMAINDER") + GET (endp, "RBUF.endp -> BOOL") +#undef GETSETNAME + { 0 } +}; + +static PyMethodDef rbuf_pymethods[] = { +#define METHNAME(func) rbmeth_##func + METH (skip, "RBUF.skip(N)") + METH (get, "RBUF.get(N) -> BYTES") +#define RBMETH_DECL_GETU_(n, W, w) \ + METH(getu##w, "RBUF.getu" #w "() -> INT") + DOUINTCONV(RBMETH_DECL_GETU_) +#define RBMETH_DECL_GETBLK_(n, W, w) \ + METH(getblk##w, "RBUF.getblk" #w "() -> INT") + BUF_DOSUFFIXES(RBMETH_DECL_GETBLK_) + METH (getmp, "RBUF.getmp() -> X") + METH (getgf, "RBUF.getgf() -> X") + KWMETH(getecpt, "RBUF.getecpt(curve = None) -> P") + METH (getecptraw, "RBUF.getecptraw(CURVE) -> P") + METH (getge, "RBUF.getge(GROUP) -> X") + METH (getgeraw, "RBUF.getgeraw(GROUP) -> X") +#undef METHNAME + { 0 } +}; + +static PyBufferProcs rbuf_pybuffer = { + rbuf_pyreadbuf, /* @bf_getreadbuffer@ */ + 0, /* @bf_getwritebuffer@ */ + rbuf_pysegcount, /* @bf_getsegcount@ */ + 0 /* @bf_getcharbuffer@ */ +}; + +static PyTypeObject rbuf_pytype_skel = { + PyObject_HEAD_INIT(0) 0, /* Header */ + "catacomb.ReadBuffer", /* @tp_name@ */ + sizeof(buf_pyobj), /* @tp_basicsize@ */ + 0, /* @tp_itemsize@ */ + + buf_pydealloc, /* @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@ */ + &rbuf_pybuffer, /* @tp_as_buffer@ */ + Py_TPFLAGS_DEFAULT | /* @tp_flags@ */ + Py_TPFLAGS_BASETYPE, + + /* @tp_doc@ */ + "A read buffer.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + 0, /* @tp_iter@ */ + 0, /* @tp_iternexr@ */ + rbuf_pymethods, /* @tp_methods@ */ + 0, /* @tp_members@ */ + rbuf_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@ */ + rbuf_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + +/*----- Write buffers -----------------------------------------------------*/ + +static void ensure(PyObject *me, size_t n) +{ + buf *b = BUF_B(me); + + if (BLEFT(b) < n) { + size_t nn = BSZ(b); + octet *p; + size_t want = BLEFT(b) + n; + while (nn < want) nn <<= 1; + p = xrealloc(BBASE(b), nn, BSZ(b)); + BCUR(b) = p + BLEN(b); + BLIM(b) = p + nn; + BBASE(b) = p; + } +} + +static PyObject *wbuf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) +{ + char *p; + size_t n = 64; + buf_pyobj *me = 0; + static char *kwlist[] = { "size", 0 }; + + if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:new", kwlist, + convszt, &n)) + goto end; + me = (buf_pyobj *)ty->tp_alloc(ty, 0); + p = xmalloc(n); + buf_init(&me->b, p, n); +end: + return ((PyObject *)me); +} + +static int wbuf_pysegcount(PyObject *me, int *nn) + { if (nn) *nn = BLEN(BUF_B(me)); return (1); } + +static int wbuf_pyreadbuf(PyObject *me, int seg, void **q) + { assert(seg == 0); *q = BBASE(BUF_B(me)); return (BLEN(BUF_B(me))); } + +static PyObject *wbmeth_zero(PyObject *me, PyObject *arg) +{ + void *p; + size_t n; + if (!PyArg_ParseTuple(arg, "O&:zero", convszt, &n)) return (0); + ensure(me, n); + p = buf_get(BUF_B(me), n); assert(p && BOK(BUF_B(me))); + memset(p, 0, n); + RETURN_ME; +} + +static PyObject *wbmeth_put(PyObject *me, PyObject *arg) +{ + void *p; + int n; + if (!PyArg_ParseTuple(arg, "s#:put", &p, &n)) return (0); + ensure(me, n); + buf_put(BUF_B(me), p, n); assert(BOK(BUF_B(m))); + RETURN_ME; +} + +#define WBMETH_PUTU_(n, W, w) \ + static PyObject *wbmeth_putu##w(PyObject *me, PyObject *arg) \ + { \ + uint##n i; \ + if (!PyArg_ParseTuple(arg, "O&:putu" #w, convu##n, &i)) return (0); \ + ensure(me, SZ_##n); \ + buf_putu##w(BUF_B(me), i); assert(BOK(BUF_B(me))); \ + RETURN_ME; \ + } +DOUINTCONV(WBMETH_PUTU_) + +#define SZ_z 1 +#define WBMETH_PUTBLK_(n, W, w) \ + static PyObject *wbmeth_putblk##w(PyObject *me, PyObject *arg) \ + { \ + char *p; \ + int sz; \ + if (!PyArg_ParseTuple(arg, "s#:putblk" #w, &p, &sz)) return (0); \ + ensure(me, sz + SZ_##n); \ + buf_putmem##w(BUF_B(me), p, sz); assert(BOK(BUF_B(me))); \ + RETURN_ME; \ + } +BUF_DOSUFFIXES(WBMETH_PUTBLK_) + +static PyObject *wbmeth_putmp(PyObject *me, PyObject *arg) +{ + mp *x = 0; + if (!PyArg_ParseTuple(arg, "O&:putmp", convmp, &x)) return (0); + ensure(me, mp_octets(x) + 2); + buf_putmp(BUF_B(me), x); assert(BOK(BUF_B(me))); + RETURN_ME; +} + +static PyObject *wbmeth_putgf(PyObject *me, PyObject *arg) +{ + mp *x = 0; + if (!PyArg_ParseTuple(arg, "O&:putgf", convgf, &x)) return (0); + ensure(me, mp_octets(x) + 2); + buf_putmp(BUF_B(me), x); assert(BOK(BUF_B(me))); + MP_DROP(x); + RETURN_ME; +} + +static PyObject *wbmeth_putecpt(PyObject *me, PyObject *arg) +{ + ec pt = EC_INIT; + if (!PyArg_ParseTuple(arg, "O&:putecpt", convecpt, &pt)) return (0); + if (EC_ATINF(&pt)) ensure(me, 2); + else ensure(me, 4 + mp_octets(pt.x) + mp_octets(pt.y)); + buf_putec(BUF_B(me), &pt); assert(BOK(BUF_B(me))); + EC_DESTROY(&pt); + RETURN_ME; +} + +static PyObject *wbmeth_putecptraw(PyObject *me, PyObject *arg) +{ + PyObject *ptobj; + ec pt = EC_INIT; + if (!PyArg_ParseTuple(arg, "O!:putecptraw", ecptcurve_pytype, &ptobj)) + return (0); + EC_OUT(ECPT_C(ptobj), &pt, ECPT_P(ptobj)); + ensure(me, ECPT_C(ptobj)->f->noctets * 2 + 1); + ec_putraw(ECPT_C(ptobj), BUF_B(me), &pt); assert(BOK(BUF_B(me))); + EC_DESTROY(&pt); + RETURN_ME; +} + +static PyObject *wbmeth_putge(PyObject *me, PyObject *arg) +{ + PyObject *geobj; + if (!PyArg_ParseTuple(arg, "O!:putge", ge_pytype, &geobj)) return (0); + ensure(me, GE_G(geobj)->noctets); + G_TOBUF(GE_G(geobj), BUF_B(me), GE_X(geobj)); assert(BOK(BUF_B(me))); + RETURN_ME; +} + +static PyObject *wbmeth_putgeraw(PyObject *me, PyObject *arg) +{ + PyObject *geobj; + if (!PyArg_ParseTuple(arg, "O!:putgeraw", ge_pytype, &geobj)) return (0); + ensure(me, GE_G(geobj)->noctets); + G_TORAW(GE_G(geobj), BUF_B(me), GE_X(geobj)); assert(BOK(BUF_B(me))); + RETURN_ME; +} + +static PyObject *wbget_size(PyObject *me, void *hunoz) + { return (PyInt_FromLong(BLEN(BUF_B(me)))); } + +static PyGetSetDef wbuf_pygetset[] = { +#define GETSETNAME(op, name) wb##op##_##name + GET (size, "WBUF.size -> SIZE") +#undef GETSETNAME + { 0 } +}; + +static PyMethodDef wbuf_pymethods[] = { +#define METHNAME(func) wbmeth_##func + METH (zero, "WBUF.skip(N)") + METH (put, "WBUF.put(BYTES)") +#define WBMETH_DECL_PUTU_(n, W, w) \ + METH(putu##w, "WBUF.putu" #w "(INT)") + DOUINTCONV(WBMETH_DECL_PUTU_) +#define WBMETH_DECL_PUTBLK_(n, W, w) \ + METH(putblk##w, "WBUF.putblk" #w "(BYTES)") + BUF_DOSUFFIXES(WBMETH_DECL_PUTBLK_) + METH (putmp, "WBUF.putmp(X)") + METH (putgf, "WBUF.putgf(X)") + KWMETH(putecpt, "WBUF.putecpt(P)") + METH (putecptraw, "WBUF.putecptraw(P)") + METH (putge, "WBUF.putge(X)") + METH (putgeraw, "WBUF.putgeraw(X)") +#undef METHNAME + { 0 } +}; + +static PyBufferProcs wbuf_pybuffer = { + wbuf_pyreadbuf, /* @bf_getreadbuffer@ */ + 0, /* @bf_getwritebuffer@ */ + wbuf_pysegcount, /* @bf_getsegcount@ */ + 0 /* @bf_getcharbuffer@ */ +}; + +static PyTypeObject wbuf_pytype_skel = { + PyObject_HEAD_INIT(0) 0, /* Header */ + "catacomb.WriteBuffer", /* @tp_name@ */ + sizeof(buf_pyobj), /* @tp_basicsize@ */ + 0, /* @tp_itemsize@ */ + + buf_pydealloc, /* @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@ */ + &wbuf_pybuffer, /* @tp_as_buffer@ */ + Py_TPFLAGS_DEFAULT | /* @tp_flags@ */ + Py_TPFLAGS_BASETYPE, + + /* @tp_doc@ */ + "A write buffer.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + 0, /* @tp_iter@ */ + 0, /* @tp_iternexr@ */ + wbuf_pymethods, /* @tp_methods@ */ + 0, /* @tp_members@ */ + wbuf_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@ */ + wbuf_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + +/*----- Initialization ----------------------------------------------------*/ + +void buffer_pyinit(void) +{ + INITTYPE(rbuf, root); + INITTYPE(wbuf, root); +} + +void buffer_pyinsert(PyObject *mod) +{ + INSEXC("BufferError", buferr, PyExc_Exception, 0); + INSERT("ReadBuffer", rbuf_pytype); + INSERT("WriteBuffer", wbuf_pytype); +} + +/*----- That's all, folks -------------------------------------------------*/ diff --git a/bytestring.c b/bytestring.c index 394d2f9..28d62b7 100644 --- a/bytestring.c +++ b/bytestring.c @@ -34,9 +34,9 @@ PyTypeObject *bytestring_pytype; -PyObject *bytestring_pywrap(const void *p, size_t n) +static PyObject *dowrap(PyTypeObject *ty, const void *p, size_t n) { - PyStringObject *x = PyObject_NewVar(PyStringObject, bytestring_pytype, n); + PyStringObject *x = (PyStringObject *)ty->tp_alloc(ty, n); if (p) memcpy(x->ob_sval, p, n); x->ob_sval[n] = 0; #ifdef CACHE_HASH @@ -46,8 +46,22 @@ PyObject *bytestring_pywrap(const void *p, size_t n) return ((PyObject *)x); } +PyObject *bytestring_pywrap(const void *p, size_t n) + { return (dowrap(bytestring_pytype, p, n)); } + PyObject *bytestring_pywrapbuf(buf *b) - { return bytestring_pywrap(BCUR(b), BLEFT(b)); } + { return (dowrap(bytestring_pytype, BCUR(b), BLEFT(b))); } + +static PyObject *bytestring_pynew(PyTypeObject *ty, + PyObject *arg, PyObject *kw) +{ + const char *p; + int n; + static char *kwlist[] = { "data", 0 }; + if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &p, &n)) + return (0); + return (dowrap(ty, p, n)); +} #define BINOP(name, op) \ static PyObject *bytestring_py##name(PyObject *x, PyObject *y) { \ @@ -160,7 +174,7 @@ static PyTypeObject bytestring_pytype_skel = { 0, /* @tp_dictoffset@ */ 0, /* @tp_init@ */ PyType_GenericAlloc, /* @tp_alloc@ */ - 0, /* @tp_new@ */ + bytestring_pynew, /* @tp_new@ */ 0, /* @tp_free@ */ 0 /* @tp_is_gc@ */ }; diff --git a/catacomb-python.h b/catacomb-python.h index ff99a78..b9b1fd5 100644 --- a/catacomb-python.h +++ b/catacomb-python.h @@ -39,9 +39,13 @@ #include #include +#undef ULLONG_MAX +#undef ULONG_LONG_MAX + #include #include #include +#include #include @@ -104,6 +108,9 @@ #include #include +#include +#include + /*----- Utility macros ----------------------------------------------------*/ #define RETURN_OBJ(obj) do { Py_INCREF(obj); return (obj); } while (0) @@ -122,6 +129,10 @@ #define ZDIVERR(str) EXCERR(PyExc_ZeroDivisionError, str) #define SYNERR(str) EXCERR(PyExc_SyntaxError, str) #define SYSERR(str) EXCERR(PyExc_SystemError, str) +#define INDEXERR(idx) do { \ + PyErr_SetObject(PyExc_KeyError, idx); \ + goto end; \ +} while (0) #define OSERR(name) do { \ PyErr_SetFromErrnoWithFilename(PyExc_OSError, name); \ goto end; \ @@ -152,6 +163,9 @@ PyModule_AddObject(mod, name, _o); \ } while (0) +#define INSEXC(name, var, base, meth) \ + INSERT(name, var = mkexc(mod, base, name, meth)) + #define METH(func, doc) \ { #func, METHNAME(func), METH_VARARGS, doc }, #define KWMETH(func, doc) \ @@ -166,11 +180,11 @@ #define MEMBER(name, ty, f, doc) \ { #name, ty, offsetof(MEMBERSTRUCT, name), f, doc }, -#define MODULES(DO) \ - DO(bytestring) \ - DO(rand) DO(algorithms) DO(pubkey) DO(pgen) \ - DO(mp) DO(field) DO(ec) DO(group) \ - DO(passphrase) +#define MODULES(_) \ + _(bytestring) _(buffer) \ + _(rand) _(algorithms) _(pubkey) _(pgen) \ + _(mp) _(field) _(ec) _(group) \ + _(passphrase) _(share) _(key) #define DOMODINIT(m) m##_pyinit(); #define DOMODINSERT(m) m##_pyinsert(mod); #define INIT_MODULES do { MODULES(DOMODINIT) } while (0) @@ -236,7 +250,6 @@ extern mp *getfe(field *, PyObject *); typedef struct fe_pyobj { PyObject_HEAD field *f; - PyObject *fobj; /* to keep it alive */ mp *x; } fe_pyobj; @@ -271,7 +284,7 @@ extern PyObject *ecpt_pywrapout(void *, ec *); extern int toecpt(ec_curve *, ec *, PyObject *); extern int getecpt(ec_curve *, ec *, PyObject *); extern void getecptout(ec *, PyObject *); -extern int convec(PyObject *, void *); +extern int convecpt(PyObject *, void *); typedef struct eccurve_pyobj { PyHeapTypeObject ty; @@ -460,8 +473,6 @@ extern PyTypeObject *gmac_pytype; extern PyObject *gmac_pywrap(PyObject *, gmac *, unsigned); extern int convgmac(PyObject *, void *); -/*----- Public key crypto -------------------------------------------------*/ - /*----- Key generation ----------------------------------------------------*/ typedef struct pfilt_pyobj { @@ -500,14 +511,17 @@ extern PyObject *mexp_common(PyObject *, PyObject *, size_t, void (*drop)(void *)); extern int convulong(PyObject *, void *); -extern int convu32(PyObject *, void *); +#define DECL_CONVU_(n) extern int convu##n(PyObject *, void *); +DOUINTSZ(DECL_CONVU_) extern int convmpw(PyObject *, void *); extern int convuint(PyObject *, void *); extern int convszt(PyObject *, void *); extern int convbool(PyObject *, void *); extern PyObject *abstract_pynew(PyTypeObject *, PyObject *, PyObject *); extern PyObject *getbool(int); -extern PyObject *getu32(uint32); +#define DECL_GETU_(n) extern PyObject *getu##n(uint##n); +DOUINTSZ(DECL_GETU_) +extern PyObject * mkexc(PyObject *, PyObject *, const char *, PyMethodDef *); extern void *newtype(PyTypeObject *, const PyTypeObject *, const char *); extern PyTypeObject *inittype(PyTypeObject *); extern void addmethods(const PyMethodDef *); diff --git a/catacomb.c b/catacomb.c index 0e1c711..47a94dd 100644 --- a/catacomb.c +++ b/catacomb.c @@ -41,6 +41,16 @@ static void setconstants(PyObject *mod) C(PGEN_ABORT), C(MPW_MAX), C(PMODE_READ), C(PMODE_VERIFY), + C(KOPEN_READ), C(KOPEN_WRITE), C(KOPEN_NOFILE), + C(KEXP_FOREVER), C(KEXP_EXPIRE), + C(KF_ENCMASK), C(KENC_BINARY), C(KENC_MP), C(KENC_STRUCT), + C(KENC_ENCRYPT), C(KENC_STRING), C(KENC_EC), + C(KF_CATMASK), C(KCAT_SYMM), C(KCAT_PRIV), C(KCAT_PUB), C(KCAT_SHARE), + C(KF_NONSECRET), + C(KF_BURN), C(KF_OPT), +#define ENTRY(tag, val, str) C(KERR_##tag), + KEY_ERRORS(ENTRY) +#undef ENTRY #undef C { 0 } }; @@ -56,13 +66,15 @@ static void setconstants(PyObject *mod) } } -PyObject *getu32(uint32 w) -{ - if (w <= 0x7fffffff) - return (PyInt_FromLong(w)); - else - return (PyLong_FromUnsignedLong(w)); -} +#define GETU_(n) \ + PyObject *getu##n(uint##n w) \ + { \ + if (w <= MASK##n) \ + return (PyInt_FromLong(w)); \ + else \ + return (PyLong_FromUnsignedLong(w)); \ + } +DOUINTSZ(GETU_) PyObject *getbool(int b) { @@ -97,18 +109,20 @@ end: return (0); } -int convu32(PyObject *o, void *pp) -{ - unsigned long u; - uint32 *p = pp; - - if (!convulong(o, &u)) goto end; - if (u > 0xffffffff) TYERR("out of range"); - *p = u; - return (1); -end: - return (0); -} +#define CONVU_(n) \ + int convu##n(PyObject *o, void *pp) \ + { \ + unsigned long u; \ + uint##n *p = pp; \ + \ + if (!convulong(o, &u)) goto end; \ + if (u > MASK##n) TYERR("out of range"); \ + *p = u; \ + return (1); \ + end: \ + return (0); \ + } +DOUINTSZ(CONVU_) int convuint(PyObject *o, void *pp) { @@ -221,6 +235,48 @@ end: return (z); } +PyObject * mkexc(PyObject *mod, PyObject *base, + const char *name, PyMethodDef *mm) +{ + PyObject *nameobj = 0; + PyObject *dict = 0; + PyObject *exc = 0; + PyObject *func = 0; + PyObject *meth = 0; + + if ((nameobj = PyString_FromFormat("%s.%s", + PyModule_GetName(mod), + name)) == 0 || + (dict = PyDict_New()) == 0 || + (exc = PyErr_NewException(PyString_AS_STRING(nameobj), + base, dict)) == 0) + goto fail; + + if (mm) { + while (mm->ml_name) { + if ((func = PyCFunction_NewEx(mm, 0, mod)) == 0 || + (meth = PyMethod_New(func, 0, exc)) == 0 || + PyDict_SetItemString(dict, mm->ml_name, meth)) + goto fail; + Py_DECREF(func); func = 0; + Py_DECREF(meth); meth = 0; + mm++; + } + } + +done: + Py_XDECREF(nameobj); + Py_XDECREF(dict); + return (exc); + +fail: + Py_XDECREF(exc); + Py_XDECREF(func); + Py_XDECREF(meth); + exc = 0; + goto done; +} + DA_DECL(method_v, PyMethodDef); static method_v global_pymethods = DA_INIT; void addmethods(const PyMethodDef *m) @@ -287,9 +343,27 @@ PyTypeObject *inittype(PyTypeObject *tyskel) return (ty); } +static PyObject *meth__ego(PyObject *me, PyObject *arg) +{ + char *argv0; + if (!PyArg_ParseTuple(arg, "s:_ego", &argv0)) + return (0); + if (strcmp(QUIS, "") == 0) + ego(argv0); + RETURN_NONE; +} + +static PyMethodDef methods[] = { +#define METHNAME(func) meth_##func + METH (_ego, "_ego(ARGV0)") +#undef METHNAME + { 0 } +}; + void init_base(void) { static const PyMethodDef mzero = { 0 }; PyObject *mod; + addmethods(methods); INIT_MODULES; DA_PUSH(&global_pymethods, mzero); mod = Py_InitModule("catacomb._base", DA(&global_pymethods)); diff --git a/catacomb/__init__.py b/catacomb/__init__.py index 0b7f418..2b391eb 100644 --- a/catacomb/__init__.py +++ b/catacomb/__init__.py @@ -28,6 +28,9 @@ import _base import types as _types from binascii import hexlify as _hexify, unhexlify as _unhexify +from sys import argv as _argv + +_base._ego(_argv[0]) def _init(): d = globals() @@ -38,7 +41,8 @@ def _init(): for i in ['MP', 'GF', 'Field', 'ECPt', 'ECPtCurve', 'ECCurve', 'ECInfo', 'DHInfo', 'BinDHInfo', 'RSAPriv', 'PrimeFilter', 'RabinMiller', - 'Group', 'GE']: + 'Group', 'GE', + 'KeyData']: c = d[i] pre = '_' + i + '_' plen = len(pre) diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..73c4e19 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +catacomb-python (1.0.0) experimental; urgency=low + + * Debianization! + + -- Mark Wooding Mon, 26 Sep 2005 11:27:00 +0100 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..3b20640 --- /dev/null +++ b/debian/control @@ -0,0 +1,27 @@ +Source: catacomb-python +Section: libs +Priority: extra +Maintainer: Mark Wooding +Standards-Version: 3.1.1 + +Package: python-catacomb +Architecture: all +Depends: python, python2.3-catacomb +Description: Python bindings for the Catacomb cryptographic library. + This is a dummy package for making sure you have the right package + for the default Debian Python installation. + +Package: python2.3-catacomb +Architecture: any +Depends: ${shlibs:Depends}, python2.3 +Description: Python bindings for the Catacomb cryptographic library. + +Package: python2.4-catacomb +Architecture: any +Depends: ${shlibs:Depends}, python2.4 +Description: Python bindings for the Catacomb cryptographic library. + +Package: python-catacomb-bin +Architecture: all +Depends: python, python-catacomb +Description: Catacomb utilities in Python diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..050e1e1 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,16 @@ +Catacomb/Python is copyright (c) 2005 Straylight/Edgeware + +Catacomb/Python is free software; you can redistribute it and/or modify +it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +Catacomb/Python is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have a copy of the GNU Library General Public License in +/usr/share/common-licenses/LGPL-2; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, +USA. diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..94c8a31 --- /dev/null +++ b/debian/rules @@ -0,0 +1,67 @@ +#! /usr/bin/make -f + +export DH_COMPAT = 4 + +DEFVERSION = 2.3 +VERSIONS = $(DEFVERSION) 2.4 + +build: build-stamp + +build-stamp: + for v in $(VERSIONS); do python$$v setup.py build; done + touch build-stamp + +clean: + dh_clean + rm -rf build build-stamp + +install: build + dh_clean + for v in $(VERSIONS); do \ + python$$v setup.py build; \ + python$$v setup.py install --root=debian/python$$v-catacomb; \ + done + mkdir -p debian/python-catacomb + mkdir -p debian/python-catacomb-bin/usr/bin + mv debian/python$(DEFVERSION)-catacomb/usr/bin/* \ + debian/python-catacomb-bin/usr/bin + for v in $(VERSIONS); do \ + rm -rf debian/python$$v-catacomb/usr/bin; \ + done + +binary-indep: install + dh_testdir -i + dh_testroot -i + dh_compress -i + dh_installdocs -i + dh_gencontrol -i + dh_fixperms -i + dh_installdeb -i + dh_md5sums -i + dh_builddeb -i + +binary-arch: install + dh_testdir -a + dh_testroot -a + dh_compress -a + dh_installdocs -a + dh_strip -a + dh_shlibdeps -a + dh_gencontrol -a + dh_fixperms -a + dh_installdeb -a + dh_md5sums -a + dh_builddeb -a + +binary: binary-indep binary-arch + +source: + rm -rf dist/*.tar.gz dist/=deb= + python$(DEFVERSION) setup.py sdist + mkdir dist/=deb= + cd dist/=deb=; tar xvfz ../*.tar.gz + d=`pwd`; cd ..; dpkg-source -i -i'/\.svn/' -b $$d/dist/=deb=/* + rm -rf dist/=deb= + +.PHONY: binary binary-arch binary-indep clean install source build + diff --git a/ec.c b/ec.c index 985e94d..1666504 100644 --- a/ec.c +++ b/ec.c @@ -967,7 +967,7 @@ static PyObject *meth__ECCurve_parse(PyObject *me, PyObject *arg) ec_curve *c; PyObject *rc = 0; - if (!PyArg_ParseTuple(arg, "Os", &me, &p)) + if (!PyArg_ParseTuple(arg, "Os:parse", &me, &p)) goto end; qd.p = p; qd.e = 0; diff --git a/key.c b/key.c index a7d3621..9de143e 100644 --- a/key.c +++ b/key.c @@ -30,12 +30,2045 @@ #include "catacomb-python.h" +/*----- Exceptions --------------------------------------------------------*/ + +static PyObject *keyexc; +static PyObject *keyioexc; +static PyObject *keyfilebrokenexc; + +static PyObject *kxmeth___init__(PyObject *me, PyObject *arg) +{ + int err; + PyObject *x = 0; + + if (!PyArg_ParseTuple(arg, "Oi:__init__", &me, &err) || + (x = PyInt_FromLong(err)) == 0 || + PyObject_SetAttrString(me, "err", x)) + goto fail; + Py_DECREF(x); x = 0; + if ((x = PyString_FromString(key_strerror(err))) == 0 || + PyObject_SetAttrString(me, "errstring", x)) + goto fail; + Py_DECREF(x); x = 0; + if ((x = PyString_FromString(key_strerror(err))) == 0 || + PyObject_SetAttrString(me, "errstring", x)) + goto fail; + Py_DECREF(x); x = 0; + if ((x = PySequence_GetSlice(arg, 1, PySequence_Size(arg))) == 0 || + PyObject_SetAttrString(me, "args", x)) + goto fail; + Py_DECREF(x); x = 0; + RETURN_NONE; + +fail: + Py_XDECREF(x); + return (0); +} + +static PyObject *kxmeth___str__(PyObject *me, PyObject *arg) +{ + long err; + const char *errstr, *errtag; + PyObject *x = 0; + PyObject *rc = 0; + + static const char *const tab[] = { +#define ENTRY(tag, num, str) "KERR_" #tag, + KEY_ERRORS(ENTRY) +#undef ENTRY + }; + + if (!PyArg_ParseTuple(arg, "O:__str__", &me) || + (x = PyObject_GetAttrString(me, "err")) == 0 || + (err = PyInt_AsLong(x), PyErr_Occurred())) + goto done; + Py_DECREF(x); x = 0; + err = -err; + if (err >= 0 && err < N(tab)) errtag = tab[err]; + else errtag = ""; + if ((x = PyObject_GetAttrString(me, "errstring")) == 0 || + (errstr = PyString_AsString(x)) == 0) + goto done; + rc = PyString_FromFormat("%s (%ld): %s", errtag, -err, errstr); + +done: + Py_XDECREF(x); + return (rc); +} + +static PyMethodDef keyexc_pymethods[] = { +#define METHNAME(func) kxmeth_##func + METH (__init__, "KeyError(CODE)") + METH (__str__, "E.__str__() -> STRING") +#undef METHNAME + { 0 } +}; + +static void keyexc_raise(int err) +{ + PyObject *arg = Py_BuildValue("(i)", err); + if (arg) PyErr_SetObject(keyexc, arg); + Py_XDECREF(arg); +} +#define KEYERR(err) do { keyexc_raise(err); goto end; } while (0) +#define KEYIOERR(name) do { \ + PyErr_SetFromErrnoWithFilename(keyioexc, name); \ + goto end; \ +} while (0) +#define KEYFILEBROKEN(name) do { \ + PyErr_SetFromErrnoWithFilename(keyfilebrokenexc, name); \ + goto end; \ +} while (0) + +/*----- Data structures ---------------------------------------------------*/ + +typedef struct keydata_pyobj { + PyObject_HEAD + key_data *kd; +} keydata_pyobj; + +static PyTypeObject *keydata_pytype; +static PyTypeObject *keydatabin_pytype; +static PyTypeObject *keydataenc_pytype; +static PyTypeObject *keydatamp_pytype; +static PyTypeObject *keydatastruct_pytype; +static PyTypeObject *keydatastr_pytype; +static PyTypeObject *keydataec_pytype; +#define KEYDATA_PYCHECK(o) PyObject_TypeCheck(o, keydata_pytype) +#define KEYDATA_KD(o) (((keydata_pyobj *)(o))->kd) + +typedef struct subkeyiter_pyobj { + PyObject_HEAD + key_subkeyiter i; + PyObject *kdobj; +} subkeyiter_pyobj; + +static PyTypeObject *subkeyiter_pytype; +#define SUBKEYITER_PYCHECK(o) PyObject_TypeCheck(o, subkeyiter_pytype); +#define SUBKEYITER_I(o) (&((subkeyiter_pyobj *)(o))->i) +#define SUBKEYITER_KDOBJ(o) (((subkeyiter_pyobj *)(o))->kdobj) + +typedef struct keyfile_pyobj { + PyObject_HEAD + key_file kf; +} keyfile_pyobj; + +static PyTypeObject *keyfile_pytype; +#define KEYFILE_PYCHECK(o) PyObject_TypeCheck(o, keyfile_pytype) +#define KEYFILE_KF(o) (&((keyfile_pyobj *)(o))->kf) + +typedef struct key_pyobj { + PyObject_HEAD + key *k; + PyObject *kfobj; +} key_pyobj; + +static PyTypeObject *key_pytype; +#define KEY_PYCHECK(o) PyObject_TypeCheck(o, key_pytype) +#define KEY_K(o) (((key_pyobj *)(o))->k) +#define KEY_KFOBJ(o) (((key_pyobj *)(o))->kfobj) +#define KEY_KF(o) KEYFILE_KF(KEY_KFOBJ(o)) + +typedef struct keyiter_pyobj { + PyObject_HEAD + key_iter i; + PyObject *kfobj; +} keyiter_pyobj; + +static PyTypeObject *keyiter_pytype; +#define KEYITER_PYCHECK(o) PyObject_TypeCheck(o, keyiter_pytype) +#define KEYITER_I(o) (&((keyiter_pyobj *)(o))->i) +#define KEYITER_KFOBJ(o) (((keyiter_pyobj *)(o))->kfobj) +#define KEYITER_KF(o) KEYFILE_KF(KEYITER_KFOBJ(o)) + +typedef struct keyattrs_pyobj { + PyObject_HEAD + PyObject *kobj; +} keyattrs_pyobj; + +static PyTypeObject *keyattrs_pytype; +#define KEYATTRS_PYCHECK(o) PyObject_TypeCheck(o, keyattrs_pytype) +#define KEYATTRS_KOBJ(o) (((keyattrs_pyobj *)(o))->kobj) +#define KEYATTRS_KF(o) KEY_KF(KEYATTRS_KOBJ(o)) +#define KEYATTRS_K(o) KEY_K(KEYATTRS_KOBJ(o)) + +typedef struct keyattriter_pyobj { + PyObject_HEAD + key_attriter i; + PyObject *kobj; +} keyattriter_pyobj; + +static PyTypeObject *keyattriter_pytype; +#define KEYATTRITER_PYCHECK(o) PyObject_TypeCheck(o, keyattriter_pytype) +#define KEYATTRITER_I(o) (&((keyattriter_pyobj *)(o))->i) +#define KEYATTRITER_KOBJ(o) (((keyattriter_pyobj *)(o))->kobj) +#define KEYATTRITER_K(o) KEY_K(KEYATTRITER_KOBJ(o)) +#define KEYATTRITER_KFOBJ(o) KEY_KFOBJ(KEYATTRITER_KOBJ(o)) +#define KEYATTRITER_KF(o) KEY_KF(KEYATTRITER_KOBJ(o)) + +/*----- Filters -----------------------------------------------------------*/ + +static int convfilter(PyObject *x, void *p) +{ + key_filter *f = p; + const char *fs; + char *end; + int n; + PyObject *a = 0, *b = 0; + int err; + int rc = 0; + + if ((fs = PyString_AsString(x)) != 0) { + if ((err = key_readflags(fs, &end, &f->f, &f->m)) != 0) + KEYERR(err); + if (*end) + KEYERR(KERR_BADFLAGS); + } else { + PyErr_Clear(); + if (!PySequence_Check(x)) + goto tyerr; + else if ((n = PySequence_Size(x)) < 0) + goto end; + else if (n != 2) + goto tyerr; + else if ((a = PySequence_GetItem(x, 0)) == 0 || convuint(a, &f->f) || + (b = PySequence_GetItem(x, 1)) == 0 || convuint(b, &f->m)) + goto end; + } + rc = 1; + goto end; +tyerr: + TYERR("expected flag string or flag/mask pair"); +end: + Py_XDECREF(a); + Py_XDECREF(b); + return (rc); +} + +static int convflags(PyObject *x, void *p) +{ + unsigned *f = p; + const char *fs; + char *end; + int err; + int rc = 0; + + if (convuint(x, p)) + return (1); + else { + PyErr_Clear(); + if ((fs = PyString_AsString(x)) != 0) { + if ((err = key_readflags(fs, &end, f, 0)) != 0) + KEYERR(err); + if (*end) + KEYERR(KERR_BADFLAGS); + } else { + PyErr_Clear(); + goto tyerr; + } + } + rc = 1; + goto end; +tyerr: + TYERR("expected flag string or flag/mask pair"); +end: + return (rc); +} + +static PyObject *meth__KeyData_readflags(PyObject *me, PyObject *arg) +{ + const char *p; + char *end; + unsigned f, m; + PyObject *rc = 0; + int err; + + if (!PyArg_ParseTuple(arg, "Os:key_readflags", &me, &p)) + goto end; + if ((err = key_readflags(p, &end, &f, &m)) != 0) + KEYERR(err); + rc = Py_BuildValue("(NNs)", getu32(f), getu32(m), end); +end: + return (rc); +} + +static PyObject *meth__KeyData_writeflags(PyObject *me, PyObject *arg) +{ + dstr d = DSTR_INIT; + PyObject *rc; + unsigned f; + + if (!PyArg_ParseTuple(arg, "OO&:key_writeflags", &me, convuint, &f)) + return (0); + key_writeflags(f, &d); + rc = PyString_FromStringAndSize(d.buf, d.len); + dstr_destroy(&d); + return (rc); +} + +/*----- Key data ----------------------------------------------------------*/ + +static PyObject *keydata_pywrap(key_data *kd) +{ + PyTypeObject *ty; + keydata_pyobj *kdobj; + + switch (kd->e & KF_ENCMASK) { + case KENC_BINARY: ty = keydatabin_pytype; break; + case KENC_ENCRYPT: ty = keydataenc_pytype; break; + case KENC_MP: ty = keydatamp_pytype; break; + case KENC_STRUCT: ty = keydatastruct_pytype; break; + case KENC_STRING: ty = keydatastr_pytype; break; + case KENC_EC: ty = keydataec_pytype; break; + default: abort(); + } + kdobj = PyObject_NEW(keydata_pyobj, ty); + kdobj->kd = kd; + return ((PyObject *)kdobj); +} + +static void keydata_pydealloc(PyObject *me) +{ + key_drop(KEYDATA_KD(me)); + FREEOBJ(me); +} + +static PyObject *kdmeth_matchp(PyObject *me, PyObject *arg) +{ + key_filter f; + + if (!PyArg_ParseTuple(arg, "O&:matchp", convfilter, &f)) + return (0); + return (getbool(KEY_MATCH(KEYDATA_KD(me), &f))); +} + +static PyObject *kdmeth_split(PyObject *me, PyObject *arg) +{ + if (!PyArg_ParseTuple(arg, ":split")) + return (0); + key_split(&KEYDATA_KD(me)); + RETURN_ME; +} + +static PyObject *kdmeth_write(PyObject *me, PyObject *arg, PyObject *kw) +{ + key_filter f = { 0, 0 }; + dstr d = DSTR_INIT; + PyObject *rc = 0; + static char *kwlist[] = { "filter", 0 }; + + if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:write", kwlist, + convfilter, &f)) + return (0); + key_write(KEYDATA_KD(me), &d, &f); + rc = PyString_FromStringAndSize(d.buf, d.len); + dstr_destroy(&d); + return (rc); +} + +static PyObject *kdmeth_encode(PyObject *me, PyObject *arg, PyObject *kw) +{ + key_filter f = { 0, 0 }; + dstr d = DSTR_INIT; + PyObject *rc = 0; + static char *kwlist[] = { "filter", 0 }; + + if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:encode", kwlist, + convfilter, &f)) + return (0); + key_encode(KEYDATA_KD(me), &d, &f); + rc = bytestring_pywrap(d.buf, d.len); + dstr_destroy(&d); + return (rc); +} + +static PyObject *kdmeth_plock(PyObject *me, PyObject *arg) +{ + char *tag; + int err; + PyObject *rc = 0; + key_data *kd; + + if (!PyArg_ParseTuple(arg, "s:plock", &tag)) + goto end; + if ((err = key_plock(&kd, KEYDATA_KD(me), tag)) != 0) + KEYERR(err); + rc = keydata_pywrap(kd); +end: + return (rc); +} + +static PyObject *kdmeth_lock(PyObject *me, PyObject *arg) +{ + char *p; + int n; + PyObject *rc = 0; + key_data *kd; + + if (!PyArg_ParseTuple(arg, "s#:lock", &p, &n)) + goto end; + key_lock(&kd, KEYDATA_KD(me), p, n); + rc = keydata_pywrap(kd); +end: + return (rc); +} + +static PyObject *meth__KeyData_read(PyObject *me, PyObject *arg) +{ + const char *p; + char *end; + key_data *kd; + PyObject *rc = 0; + + if (!PyArg_ParseTuple(arg, "Os:read", &me, &p)) + goto end; + if ((kd = key_read(p, &end)) == 0) + KEYERR(KERR_MALFORMED); + rc = Py_BuildValue("(Ns)", keydata_pywrap(kd), end); +end: + return (rc); +} + +static PyObject *meth__KeyData_decode(PyObject *me, PyObject *arg) +{ + const char *p; + int n; + key_data *kd; + PyObject *rc = 0; + + if (!PyArg_ParseTuple(arg, "Os#:decode", &me, &p, &n)) + goto end; + if ((kd = key_decode(p, n)) == 0) + KEYERR(KERR_MALFORMED); + rc = keydata_pywrap(kd); +end: + return (rc); +} + +static PyObject *kdget_flags(PyObject *me, void *hunoz) + { return (getu32(KEYDATA_KD(me)->e)); } + +static PyMethodDef keydata_pymethods[] = { +#define METHNAME(func) kdmeth_##func + METH (matchp, "KD.matchp(FILTER) -> BOOL") + METH (split, "KD.split()") + KWMETH(write, "KD.write(filter = ) -> STRING") + KWMETH(encode, "KD.encode(filter = ) -> BYTES") + METH (plock, "KD.plock(TAG) -> ENCRYPTED-KD") + METH (lock, "KD.lock(KEY) -> ENCRYPTED-KD") +#undef METHNAME + { 0 } +}; + +static PyGetSetDef keydata_pygetset[] = { +#define GETSETNAME(op, name) kd##op##_##name + GET (flags, "KD.flags -> FLAGS") +#undef GETSETNAME + { 0 } +}; + +static PyTypeObject keydata_pytype_skel = { + PyObject_HEAD_INIT(0) 0, /* Header */ + "catacomb.KeyData", /* @tp_name@ */ + sizeof(keydata_pyobj), /* @tp_basicsize@ */ + 0, /* @tp_itemsize@ */ + + keydata_pydealloc, /* @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@ */ +"Key data base class.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + 0, /* @tp_iter@ */ + 0, /* @tp_iternexr@ */ + keydata_pymethods, /* @tp_methods@ */ + 0, /* @tp_members@ */ + keydata_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 PyObject *keydatabin_pynew(PyTypeObject *ty, + PyObject *arg, PyObject *kw) +{ + char *p; + int n; + unsigned f = 0; + keydata_pyobj *me = 0; + static char *kwlist[] = { "key", "flags", 0 }; + + if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#|O&:new", kwlist, + &p, &n, convflags, &f)) + goto end; + me = (keydata_pyobj *)ty->tp_alloc(ty, 0); + me->kd = key_newbinary(f & ~KF_ENCMASK, p, n); +end: + return ((PyObject *)me); +} + +static PyObject *kdbget_bin(PyObject *me, void *hunoz) + { return (bytestring_pywrap(KEYDATA_KD(me)->u.k.k, + KEYDATA_KD(me)->u.k.sz)); } + +static PyGetSetDef keydatabin_pygetset[] = { +#define GETSETNAME(op, name) kdb##op##_##name + GET (bin, "KD.bin -> BYTES") +#undef GETSETNAME + { 0 } +}; + +static PyTypeObject keydatabin_pytype_skel = { + PyObject_HEAD_INIT(0) 0, /* Header */ + "catacomb.KeyDataBinary", /* @tp_name@ */ + sizeof(keydata_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@ */ +"Key data for binary keys.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + 0, /* @tp_iter@ */ + 0, /* @tp_iternexr@ */ + 0, /* @tp_methods@ */ + 0, /* @tp_members@ */ + keydatabin_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@ */ + keydatabin_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + +static PyObject *keydataenc_pynew(PyTypeObject *ty, + PyObject *arg, PyObject *kw) +{ + char *p; + int n; + unsigned f = 0; + keydata_pyobj *me = 0; + static char *kwlist[] = { "key", "flags", 0 }; + + if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#|O&:new", kwlist, + &p, &n, convflags, &f)) + goto end; + me = (keydata_pyobj *)ty->tp_alloc(ty, 0); + me->kd = key_newencrypted(f & ~KF_ENCMASK, p, n); +end: + return ((PyObject *)me); +} + +static PyObject *kdemeth_plock(PyObject *me, PyObject *arg) +{ + char *hunoz; + if (!PyArg_ParseTuple(arg, "s:plock", &hunoz)) goto end; + KEYERR(KERR_WRONGTYPE); +end: + return (0); +} + +static PyObject *kdemeth_lock(PyObject *me, PyObject *arg) +{ + char *hunoz; + int hukairz; + if (!PyArg_ParseTuple(arg, "s#:lock", &hunoz, &hukairz)) goto end; + KEYERR(KERR_WRONGTYPE); +end: + return (0); +} + +static PyObject *kdemeth_punlock(PyObject *me, PyObject *arg) +{ + char *tag; + int err; + PyObject *rc = 0; + key_data *kd; + + if (!PyArg_ParseTuple(arg, "s:punlock", &tag)) + goto end; + if ((err = key_punlock(&kd, KEYDATA_KD(me), tag)) != 0) + KEYERR(err); + rc = keydata_pywrap(kd); +end: + return (rc); +} + +static PyObject *kdemeth_unlock(PyObject *me, PyObject *arg) +{ + char *p; + int n; + int err; + PyObject *rc = 0; + key_data *kd; + + if (!PyArg_ParseTuple(arg, "s#:unlock", &p, &n)) + goto end; + if ((err = key_unlock(&kd, KEYDATA_KD(me), p, n)) != 0) + KEYERR(err); + rc = keydata_pywrap(kd); +end: + return (rc); +} + +#define kdeget_ct kdbget_bin + +static PyMethodDef keydataenc_pymethods[] = { +#define METHNAME(func) kdemeth_##func + METH (plock, "KD.plock(TAG) -> ENCRYPTED-KD") + METH (lock, "KD.lock(KEY) -> ENCRYPTED-KD") + METH (punlock, "KD.punlock(TAG) -> KD") + METH (unlock, "KD.unlock(KEY) -> KD") +#undef METHNAME + { 0 } +}; + +static PyGetSetDef keydataenc_pygetset[] = { +#define GETSETNAME(op, name) kde##op##_##name + GET (ct, "KD.ct -> BYTES") +#undef GETSETNAME + { 0 } +}; + +static PyTypeObject keydataenc_pytype_skel = { + PyObject_HEAD_INIT(0) 0, /* Header */ + "catacomb.KeyDataEncrypted", /* @tp_name@ */ + sizeof(keydata_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@ */ +"Key data for encrypted keys.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + 0, /* @tp_iter@ */ + 0, /* @tp_iternexr@ */ + keydataenc_pymethods, /* @tp_methods@ */ + 0, /* @tp_members@ */ + keydataenc_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@ */ + keydataenc_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + +static PyObject *keydatamp_pynew(PyTypeObject *ty, + PyObject *arg, PyObject *kw) +{ + mp *x = 0; + unsigned f = 0; + keydata_pyobj *me = 0; + static char *kwlist[] = { "key", "flags", 0 }; + + if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:new", kwlist, + convmp, &x, convflags, &f)) + goto end; + me = (keydata_pyobj *)ty->tp_alloc(ty, 0); + me->kd = key_newmp(f & ~KF_ENCMASK, x); +end: + mp_drop(x); + return ((PyObject *)me); +} + +static PyObject *kdmget_mp(PyObject *me, void *hunoz) + { return (mp_pywrap(MP_COPY(KEYDATA_KD(me)->u.m))); } + +static PyGetSetDef keydatamp_pygetset[] = { +#define GETSETNAME(op, name) kdm##op##_##name + GET (mp, "KD.mp -> X") +#undef GETSETNAME + { 0 } +}; + +static PyTypeObject keydatamp_pytype_skel = { + PyObject_HEAD_INIT(0) 0, /* Header */ + "catacomb.KeyDataMP", /* @tp_name@ */ + sizeof(keydata_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@ */ +"Key data for large-integer keys.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + 0, /* @tp_iter@ */ + 0, /* @tp_iternexr@ */ + 0, /* @tp_methods@ */ + 0, /* @tp_members@ */ + keydatamp_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@ */ + keydatamp_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + +static PyObject *keydatastr_pynew(PyTypeObject *ty, + PyObject *arg, PyObject *kw) +{ + char *p; + unsigned f = 0; + keydata_pyobj *me = 0; + static char *kwlist[] = { "key", "flags", 0 }; + + if (!PyArg_ParseTupleAndKeywords(arg, kw, "s|O&:new", kwlist, + &p, convflags, &f)) + goto end; + me = (keydata_pyobj *)ty->tp_alloc(ty, 0); + me->kd = key_newstring(f & ~KF_ENCMASK, p); +end: + return ((PyObject *)me); +} + +static PyObject *kdsget_str(PyObject *me, void *hunoz) + { return (PyString_FromString(KEYDATA_KD(me)->u.p)); } + +static PyGetSetDef keydatastr_pygetset[] = { +#define GETSETNAME(op, name) kds##op##_##name + GET (str, "KD.str -> STRING") +#undef GETSETNAME + { 0 } +}; + +static PyTypeObject keydatastr_pytype_skel = { + PyObject_HEAD_INIT(0) 0, /* Header */ + "catacomb.KeyDataString", /* @tp_name@ */ + sizeof(keydata_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@ */ +"Key data for string keys.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + 0, /* @tp_iter@ */ + 0, /* @tp_iternexr@ */ + 0, /* @tp_methods@ */ + 0, /* @tp_members@ */ + keydatastr_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@ */ + keydatastr_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + +static PyObject *keydataec_pynew(PyTypeObject *ty, + PyObject *arg, PyObject *kw) +{ + ec x = EC_INIT; + unsigned f = 0; + keydata_pyobj *me = 0; + static char *kwlist[] = { "key", "flags", 0 }; + + if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:new", kwlist, + convecpt, &x, convflags, &f)) + goto end; + me = (keydata_pyobj *)ty->tp_alloc(ty, 0); + me->kd = key_newec(f & ~KF_ENCMASK, &x); +end: + EC_DESTROY(&x); + return ((PyObject *)me); +} + +static PyObject *kdeget_ecpt(PyObject *me, void *hunoz) +{ + ec pt = EC_INIT; + EC_COPY(&pt, &KEYDATA_KD(me)->u.e); + return (ecpt_pywrapout(ecpt_pytype, &pt)); +} + +static PyGetSetDef keydataec_pygetset[] = { +#define GETSETNAME(op, name) kde##op##_##name + GET (ecpt, "KD.ecpt -> ECPT") +#undef GETSETNAME + { 0 } +}; + +static PyTypeObject keydataec_pytype_skel = { + PyObject_HEAD_INIT(0) 0, /* Header */ + "catacomb.KeyDataECPt", /* @tp_name@ */ + sizeof(keydata_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@ */ +"Key data for elliptic-curve keys.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + 0, /* @tp_iter@ */ + 0, /* @tp_iternexr@ */ + 0, /* @tp_methods@ */ + 0, /* @tp_members@ */ + keydataec_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@ */ + keydataec_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + +static PyObject *subkeyiter_make(PyObject *kdobj) +{ + subkeyiter_pyobj *me = PyObject_NEW(subkeyiter_pyobj, subkeyiter_pytype); + me->kdobj = kdobj; + Py_INCREF(kdobj); + key_mksubkeyiter(&me->i, KEYDATA_KD(kdobj)); + return ((PyObject *)me); +} + +static PyObject *subkeyiter_next(PyObject *me) +{ + const char *tag; + if (!key_nextsubkey(SUBKEYITER_I(me), &tag, 0)) + return (0); + return (PyString_FromString(tag)); +} + +static void subkeyiter_pydealloc(PyObject *me) +{ + Py_DECREF(SUBKEYITER_KDOBJ(me)); + FREEOBJ(me); +} + +static PyTypeObject subkeyiter_pytype_skel = { + PyObject_HEAD_INIT(0) 0, /* Header */ + "catacomb.SubKeyIter", /* @tp_name@ */ + sizeof(subkeyiter_pyobj), /* @tp_basicsize@ */ + 0, /* @tp_itemsize@ */ + + subkeyiter_pydealloc, /* @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@ */ +"Iterator for structured keys.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + PyObject_SelfIter, /* @tp_iter@ */ + subkeyiter_next, /* @tp_iternexr@ */ + 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@ */ + abstract_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + +static PyObject *keydatastruct_pynew(PyTypeObject *ty, + PyObject *arg, PyObject *kw) +{ + PyObject *sub = 0; + PyObject *it = 0, *name = 0, *val = 0; + char *p; + keydata_pyobj *me = 0; + key_data *kd = 0; + static char *kwlist[] = { "subkeys", 0 }; + + Py_INCREF(arg); Py_INCREF(kw); + if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O:new", kwlist, &sub)) + goto end; + kd = key_newstruct(); + if (sub) { + if (!PyMapping_Check(sub)) + TYERR("subkeys must be an iterable mapping"); + if ((it = PyObject_GetIter(sub)) == 0) + goto end; + while ((name = PyIter_Next(it)) != 0) { + if ((p = PyString_AsString(name)) == 0 || + (val = PyObject_GetItem(sub, name)) == 0) + goto end; + if (!KEYDATA_PYCHECK(val)) + TYERR("subkey objects must be subclasses of KeyData"); + key_structset(kd, p, KEYDATA_KD(val)); + Py_DECREF(name); name = 0; + Py_DECREF(val); val = 0; + } + if (PyErr_Occurred()) + goto end; + Py_DECREF(it); it = 0; + } + me = (keydata_pyobj *)ty->tp_alloc(ty, 0); + me->kd = kd; +end: + if (kd && !me) key_drop(kd); + Py_XDECREF(name); Py_XDECREF(val); Py_XDECREF(it); + Py_XDECREF(arg); Py_XDECREF(kw); + return ((PyObject *)me); +} + +static PyObject *keydatastruct_pylookup(PyObject *me, PyObject *key) +{ + const char *tag; + key_data *kd; + PyObject *rc = 0; + + if ((tag = PyString_AsString(key)) == 0) + goto end; + if ((kd = key_structfind(KEYDATA_KD(me), tag)) == 0) + INDEXERR(key); + key_incref(kd); + rc = keydata_pywrap(kd); +end: + return (rc); +} + +static int keydatastruct_pystore(PyObject *me, + PyObject *key, PyObject *value) +{ + const char *tag; + int rc = -1; + + if ((tag = PyString_AsString(key)) == 0) + goto end; + if (value) { + if (!KEYDATA_PYCHECK(value)) + TYERR("expected KeyData value"); + key_structset(KEYDATA_KD(me), tag, KEYDATA_KD(value)); + } else { + if (!key_structfind(KEYDATA_KD(me), tag)) + INDEXERR(key); + key_structset(KEYDATA_KD(me), tag, 0); + } + rc = 0; +end: + return (rc); +} + +static PyMappingMethods keydatastruct_pymapping = { + 0, /* @mp_length@ */ + keydatastruct_pylookup, /* @mp_subscript@ */ + keydatastruct_pystore, /* @mp_ass_subscript@ */ +}; + +static PyTypeObject keydatastruct_pytype_skel = { + PyObject_HEAD_INIT(0) 0, /* Header */ + "catacomb.KeyDataStructured", /* @tp_name@ */ + sizeof(keydata_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@ */ + &keydatastruct_pymapping, /* @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@ */ +"Key data for structured keys.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + subkeyiter_make, /* @tp_iter@ */ + 0, /* @tp_iternexr@ */ + 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@ */ + keydatastruct_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + +/*----- Key attributes ----------------------------------------------------*/ + +static PyObject *keyattriter_make(PyObject *kaobj) +{ + PyObject *kobj = KEYATTRS_KOBJ(kaobj); + keyattriter_pyobj *me = PyObject_NEW(keyattriter_pyobj, + keyattriter_pytype); + me->kobj = kobj; + Py_INCREF(kobj); + key_mkattriter(&me->i, KEY_K(kobj)); + return ((PyObject *)me); +} + +static PyObject *keyattriter_next(PyObject *me) +{ + const char *name; + + if (!key_nextattr(KEYATTRITER_I(me), &name, 0)) + return (0); + return (PyString_FromString(name)); +} + +static void keyattriter_pydealloc(PyObject *me) +{ + Py_DECREF(KEYATTRITER_KOBJ(me)); + FREEOBJ(me); +} + +static PyTypeObject keyattriter_pytype_skel = { + PyObject_HEAD_INIT(0) 0, /* Header */ + "catacomb.KeyAttributeIter", /* @tp_name@ */ + sizeof(keyattriter_pyobj), /* @tp_basicsize@ */ + 0, /* @tp_itemsize@ */ + + keyattriter_pydealloc, /* @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@ */ +"Iterator for key attributes.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + PyObject_SelfIter, /* @tp_iter@ */ + keyattriter_next, /* @tp_iternexr@ */ + 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@ */ + abstract_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + +static PyObject *keyattrs_pylookup(PyObject *me, PyObject *key) +{ + const char *attr; + const char *value; + PyObject *rc = 0; + + if ((attr = PyString_AsString(key)) == 0) + goto end; + if ((value = key_getattr(KEYATTRS_KF(me), KEYATTRS_K(me), attr)) == 0) + INDEXERR(key); + rc = PyString_FromString(value); +end: + return (rc); +} + +static int keyattrs_pystore(PyObject *me, + PyObject *key, PyObject *value) +{ + const char *attr; + const char *val; + int err; + int rc = -1; + + if ((attr = PyString_AsString(key)) == 0) + goto end; + if (value) { + if ((val = PyString_AsString(value)) == 0) + goto end; + if ((err = key_putattr(KEYATTRS_KF(me), KEYATTRS_K(me), + attr, val)) != 0) + KEYERR(err); + } else { + if (!key_getattr(KEYATTRS_KF(me), KEYATTRS_K(me), attr)) + INDEXERR(key); + if ((err = key_putattr(KEYATTRS_KF(me), KEYATTRS_K(me), attr, 0)) != 0) + KEYERR(err); + } + rc = 0; +end: + return (rc); +} + +static PyObject *keyattrs_make(PyObject *kobj) +{ + keyattrs_pyobj *me = PyObject_NEW(keyattrs_pyobj, keyattrs_pytype); + me->kobj = kobj; + Py_INCREF(kobj); + return ((PyObject *)me); +} + +static void keyattrs_pydealloc(PyObject *me) +{ + Py_DECREF(KEYATTRS_KOBJ(me)); + FREEOBJ(me); +} + +static PyMappingMethods keyattrs_pymapping = { + 0, + keyattrs_pylookup, + keyattrs_pystore +}; + +static PyTypeObject keyattrs_pytype_skel = { + PyObject_HEAD_INIT(0) 0, /* Header */ + "catacomb.KeyAttributes", /* @tp_name@ */ + sizeof(keyattrs_pyobj), /* @tp_basicsize@ */ + 0, /* @tp_itemsize@ */ + + keyattrs_pydealloc, /* @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@ */ + &keyattrs_pymapping, /* @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@ */ +"Proxy thing for talking about key attributes.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + keyattriter_make, /* @tp_iter@ */ + 0, /* @tp_iternexr@ */ + 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@ */ + abstract_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + +/*----- Key objects -------------------------------------------------------*/ + +static PyObject *key_dowrap(PyTypeObject *ty, PyObject *kfobj, key *k) +{ + key_pyobj *kobj = (key_pyobj *)ty->tp_alloc(ty, 0); + kobj->kfobj = kfobj; + Py_INCREF(kfobj); + kobj->k = k; + return ((PyObject *)kobj); +} + +static PyObject *key_pywrap(PyObject *kfobj, key *k) + { return (key_dowrap(key_pytype, kfobj, k)); } + +static PyObject *key_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) +{ + PyObject *kfobj; + uint32 id; + char *type; + long exptime = KEXP_FOREVER; + static char *kwlist[] = { "keyfile", "id", "type", "exptime", 0 }; + key *k; + int err; + + if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O&sl:new", kwlist, + keyfile_pytype, &kfobj, convu32, &id, + &type, &exptime)) + goto end; + if ((err = key_new(KEYFILE_KF(kfobj), id, type, exptime, &k)) == 0) + KEYERR(err); + return (key_dowrap(ty, kfobj, k)); +end: + return (0); +} + +static void key_pydealloc(PyObject *me) +{ + Py_DECREF(KEY_KFOBJ(me)); + FREEOBJ(me); +} + +static PyObject *kmeth_delete(PyObject *me, PyObject *arg) +{ + int err; + + if (!PyArg_ParseTuple(arg, ":delete")) goto end; + if ((err = key_delete(KEY_KF(me), KEY_K(me))) != 0) KEYERR(err); + RETURN_ME; +end: + return (0); +} + +static PyObject *kmeth_expire(PyObject *me, PyObject *arg) +{ + int err; + + if (!PyArg_ParseTuple(arg, ":expire")) goto end; + if ((err = key_expire(KEY_KF(me), KEY_K(me))) != 0) KEYERR(err); + RETURN_ME; +end: + return (0); +} + +static PyObject *kmeth_used(PyObject *me, PyObject *arg) +{ + long t; + int err; + + if (!PyArg_ParseTuple(arg, "l:used", &t)) goto end; + if ((err = key_used(KEY_KF(me), KEY_K(me), t)) != 0) KEYERR(err); + RETURN_ME; +end: + return (0); +} + +static PyObject *kmeth_extract(PyObject *me, PyObject *arg, PyObject *kw) +{ + key_filter f = { 0, 0 }; + PyObject *file; + PyObject *nameobj; + char *name; + FILE *fp; + static char *kwlist[] = { "file", "filter", 0 }; + + if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!|O&:extract", kwlist, + &PyFile_Type, &file, + convfilter, &f) || + (fp = PyFile_AsFile(file)) == 0 || + (nameobj = PyFile_Name(file)) == 0 || + (name = PyString_AsString(nameobj)) == 0) + goto end; + if (key_extract(KEY_KF(me), KEY_K(me), fp, &f)) + OSERR(name); + RETURN_ME; +end: + return (0); +} + +static PyObject *kmeth_fingerprint(PyObject *me, + PyObject *arg, PyObject *kw) +{ + ghash *h; + key_filter f = { KF_NONSECRET, KF_NONSECRET }; + static char *kwlist[] = { "hash", "filter", 0 }; + + if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:fingerprint", kwlist, + convghash, &h, convfilter, &f)) + return (0); + return (getbool(key_fingerprint(KEY_K(me), h, &f))); +} + +static PyObject *kget_id(PyObject *me, void *hunoz) + { return (getu32(KEY_K(me)->id)); } +static PyObject *kget_type(PyObject *me, void *hunoz) + { return (PyString_FromString(KEY_K(me)->type)); } +static PyObject *kget_exptime(PyObject *me, void *hunoz) + { return (PyInt_FromLong(KEY_K(me)->exp)); } +static PyObject *kget_deltime(PyObject *me, void *hunoz) + { return (PyInt_FromLong(KEY_K(me)->del)); } +static PyObject *kget_expiredp(PyObject *me, void *hunoz) + { return (getbool(key_expired(KEY_K(me)))); } +static PyObject *kget_attr(PyObject *me, void *hunoz) + { return (keyattrs_make(me)); } + +static PyObject *kget_data(PyObject *me, void *hunoz) +{ + key_data *kd = KEY_K(me)->k; + key_incref(kd); + return (keydata_pywrap(kd)); +} +static int kset_data(PyObject *me, PyObject *x, void *hunoz) +{ + int err; + if (!KEYDATA_PYCHECK(x)) TYERR("expected KeyData object"); + if ((err = key_setkeydata(KEY_KF(me), KEY_K(me), KEYDATA_KD(x))) != 0) + KEYERR(err); + return (0); +end: + return (-1); +} + +static PyObject *kget_fulltag(PyObject *me, void *hunoz) +{ + dstr d = DSTR_INIT; + PyObject *rc; + + key_fulltag(KEY_K(me), &d); + rc = PyString_FromStringAndSize(d.buf, d.len); + dstr_destroy(&d); + return (rc); +} + +static PyObject *kget_tag(PyObject *me, void *hunoz) +{ + if (!KEY_K(me)->tag) RETURN_NONE; + return (PyString_FromString(KEY_K(me)->tag)); +} +static int kset_tag(PyObject *me, PyObject *x, void *hunoz) +{ + int err; + char *tag; + + if (x == Py_None) tag = 0; + else if ((tag = PyString_AsString(x)) == 0) goto end; + if ((err = key_settag(KEY_KF(me), KEY_K(me), tag)) != 0) KEYERR(err); + return (0); +end: + return (-1); +} + +static PyObject *kget_comment(PyObject *me, void *hunoz) +{ + if (!KEY_K(me)->c) RETURN_NONE; + return (PyString_FromString(KEY_K(me)->c)); +} +static int kset_comment(PyObject *me, PyObject *x, void *hunoz) +{ + int err; + char *c; + + if (x == Py_None) c = 0; + else if ((c = PyString_AsString(x)) == 0) goto end; + if ((err = key_setcomment(KEY_KF(me), KEY_K(me), c)) != 0) KEYERR(err); + return (0); +end: + return (-1); +} + +static PyMethodDef key_pymethods[] = { +#define METHNAME(func) kmeth_##func + METH (delete, "KEY.delete()") + METH (expire, "KEY.expire()") + METH (used, "KEY.used(TIME)") + KWMETH(extract, "KEY.extract(FILE, filter = '')") + KWMETH(fingerprint, "KEY.fingerprint(HASH, filtr = '-secret')") +#undef METHNAME + { 0 } +}; + +static PyGetSetDef key_pygetset[] = { +#define GETSETNAME(op, name) k##op##_##name + GET (id, "KEY.id -> ID") + GETSET(tag, "KEY.tag -> TAG") + GET (type, "KEY.type -> TYPE") + GET (exptime, "KEY.exptime -> TIME") + GET (deltime, "KEY.deltime -> TIME") + GET (expiredp, "KEY.expiredp -> BOOL") + GET (attr, "KEY.attr -> ATTRIBUTES") + GETSET(data, "KEY.data -> KD") + GETSET(comment, "KEY.comment -> COMMENT") + GET (fulltag, "KEY.fulltag -> FULLTAG") +#undef GETSETNAME + { 0 } +}; + +static PyTypeObject key_pytype_skel = { + PyObject_HEAD_INIT(0) 0, /* Header */ + "catacomb.Key", /* @tp_name@ */ + sizeof(key_pyobj), /* @tp_basicsize@ */ + 0, /* @tp_itemsize@ */ + + key_pydealloc, /* @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@ */ +"Key object.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + 0, /* @tp_iter@ */ + 0, /* @tp_iternexr@ */ + key_pymethods, /* @tp_methods@ */ + 0, /* @tp_members@ */ + key_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@ */ + key_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + +/*----- Key iteration -----------------------------------------------------*/ + +static PyObject *keyiter_new(PyObject *kfobj) +{ + keyiter_pyobj *me = PyObject_NEW(keyiter_pyobj, keyiter_pytype); + key_mkiter(&me->i, KEYFILE_KF(kfobj)); + me->kfobj = kfobj; + Py_INCREF(kfobj); + return ((PyObject *)me); +} + +static PyObject *keyiter_next(PyObject *me) +{ + key *k; + + if ((k = key_next(KEYITER_I(me))) == 0) + return (0); + return (key_pywrap(KEYITER_KFOBJ(me), k)); +} + +static void keyiter_pydealloc(PyObject *me) +{ + Py_DECREF(KEYITER_KFOBJ(me)); + FREEOBJ(me); +} + +static PyTypeObject keyiter_pytype_skel = { + PyObject_HEAD_INIT(0) 0, /* Header */ + "catacomb.KeyFileIter", /* @tp_name@ */ + sizeof(keyiter_pyobj), /* @tp_basicsize@ */ + 0, /* @tp_itemsize@ */ + + keyiter_pydealloc, /* @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@ */ +"Keyring iterator.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + PyObject_SelfIter, /* @tp_iter@ */ + keyiter_next, /* @tp_iternexr@ */ + 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@ */ + abstract_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + /*----- Key files ---------------------------------------------------------*/ +struct reportinfo { + PyObject *func; + int stop; +}; + +static void pythonreporter(const char *file, int line, + const char *msg, void *p) +{ + struct reportinfo *ri = p; + PyObject *res = 0; + + if (ri->stop) + return; + if (!ri->func) + key_moan(file, line, msg, 0); + else if ((res = PyObject_CallFunction(ri->func, "sis", + file, line, msg)) == 0) + ri->stop = 1; + else + Py_DECREF(res); +} + static PyObject *keyfile_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) { - + struct reportinfo ri = { 0, 0 }; + char *file = 0; + unsigned how = KOPEN_READ; + keyfile_pyobj *rc = 0; + static char *kwlist[] = { "file", "how", "report", 0 }; + + Py_XINCREF(arg); Py_XINCREF(kw); + if (!PyArg_ParseTupleAndKeywords(arg, kw, "s|iO:new", kwlist, + &file, &how, &ri.func)) + goto end; + if (ri.func && !PyCallable_Check(ri.func)) + TYERR("reporter function not callable"); + if ((rc = (keyfile_pyobj *)ty->tp_alloc(ty, 0)) == 0) + goto end; + if (key_open(&rc->kf, file, how, pythonreporter, &ri)) + OSERR(file); + if (ri.stop) { + key_discard(&rc->kf); + goto end; + } + goto done; + +end: + if (rc) { + FREEOBJ(rc); + rc = 0; + } +done: + Py_XDECREF(arg); Py_XDECREF(kw); + return ((PyObject *)rc); +} + +static void keyfile_pydealloc(PyObject *me) +{ + key_discard(KEYFILE_KF(me)); + FREEOBJ(me); +} + +static PyObject *kfmeth_save(PyObject *me, PyObject *arg) +{ + if (!PyArg_ParseTuple(arg, ":save")) + goto end; + switch (key_save(KEYFILE_KF(me))) { + case KWRITE_OK: + RETURN_ME; + case KWRITE_FAIL: + KEYIOERR(KEYFILE_KF(me)->name); + case KWRITE_BROKEN: + KEYFILEBROKEN(KEYFILE_KF(me)->name); + default: + abort(); + } +end: + return (0); +} + +static PyObject *kfmeth_merge(PyObject *me, PyObject *arg, PyObject *kw) +{ + struct reportinfo ri = { 0, 0 }; + char *name; + PyObject *x = 0; + FILE *fp = 0; + int rc; + static char *kwlist[] = { "file", "report", 0 }; + + Py_XINCREF(arg); Py_XINCREF(kw); + if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!|O:merge", kwlist, + &PyFile_Type, &x, &ri.func)) + goto end; + if (ri.func && !PyCallable_Check(ri.func)) + TYERR("reporter function not callable"); + if ((fp = PyFile_AsFile(x)) == 0) + goto end; + x = PyFile_Name(x); + if ((name = PyString_AsString(x)) == 0) + goto end; + rc = key_merge(KEYFILE_KF(me), name, fp, pythonreporter, &ri); + if (ri.stop) + goto end; + if (rc != 0) + KEYERR(rc); + Py_XDECREF(arg); Py_XDECREF(kw); + RETURN_ME; + +end: + Py_XDECREF(arg); Py_XDECREF(kw); + return (0); +} + +static PyObject *kfmeth_byid(PyObject *me, PyObject *arg) +{ + uint32 id; + key *k; + PyObject *rc = 0; + + if (!PyArg_ParseTuple(arg, "O&:byid", convu32, &id)) goto end; + if ((k = key_byid(KEYFILE_KF(me), id)) == 0) KEYERR(KERR_NOTFOUND); + rc = key_pywrap(me, k); +end: + return (rc); +} + +static PyObject *kfmeth_bytype(PyObject *me, PyObject *arg) +{ + char *type; + key *k; + PyObject *rc = 0; + + if (!PyArg_ParseTuple(arg, "s:bytype", &type)) goto end; + if ((k = key_bytype(KEYFILE_KF(me), type)) == 0) RETURN_NONE; + rc = key_pywrap(me, k); +end: + return (rc); +} + +static PyObject *bytag(PyObject *me, PyObject *tagobj) +{ + uint32 id; + char *tag; + key *k; + PyObject *rc = 0; + + if (convu32(tagobj, &id)) + k = key_byid(KEYFILE_KF(me), id); + else { + PyErr_Clear(); + if ((tag = PyString_AsString(tagobj)) == 0) + goto end; + k = key_bytag(KEYFILE_KF(me), tag); + } + if (!k) RETURN_NONE; + rc = key_pywrap(me, k); +end: + return (rc); +} + +static PyObject *kfmeth_bytag(PyObject *me, PyObject *arg) +{ + PyObject *tagobj; + + if (!PyArg_ParseTuple(arg, "O:bytag", &tagobj)) return (0); + return (bytag(me, tagobj)); +} + +static PyObject *keyfile_pylookup(PyObject *me, PyObject *key) +{ + PyObject *rc = bytag(me, key); + if (!rc) goto end; + if (rc == Py_None) { + Py_DECREF(rc); + rc = 0; + INDEXERR(key); + } +end: + return (rc); +} + +static PyObject *kfmeth_newkey(PyObject *me, PyObject *arg, PyObject *kw) +{ + uint32 id; + char *type; + long exptime = KEXP_FOREVER; + static char *kwlist[] = { "id", "type", "exptime", 0 }; + key *k; + int err; + + if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&sl:new", kwlist, + convu32, &id, &type, &exptime)) + goto end; + if ((err = key_new(KEYFILE_KF(me), id, type, exptime, &k)) == 0) + KEYERR(err); + return (key_pywrap(me, k)); +end: + return (0); +} + +static PyObject *kfmeth_qtag(PyObject *me, PyObject *arg, PyObject *kw) +{ + key *k; + key_data **kd; + PyObject *newkdobj = 0; + char *tag; + PyObject *kdobj; + dstr d = DSTR_INIT; + PyObject *rc = 0; + static char *kwlist[] = { "tag", "new", 0 }; + + if (!PyArg_ParseTupleAndKeywords(arg, kw, "s|O!:qtag", kwlist, + &tag, keydata_pytype, &newkdobj)) + goto end; + if (key_qtag(KEYFILE_KF(me), tag, &d, &k, &kd)) + KEYERR(KERR_NOTFOUND); + key_incref(*kd); + kdobj = keydata_pywrap(*kd); + if (newkdobj) { + if (!(KEYFILE_KF(me)->f & KF_WRITE)) + KEYERR(KERR_READONLY); + key_drop(*kd); + *kd = KEYDATA_KD(newkdobj); + key_incref(*kd); + } + rc = Py_BuildValue("(s#NN)", d.buf, d.len, key_pywrap(me, k), kdobj); +end: + return (rc); +} + +static PyObject *kfget_name(PyObject *me, void *hunoz) + { return (PyString_FromString(KEYFILE_KF(me)->name)); } +static PyObject *kfget_modifiedp(PyObject *me, void *hunoz) + { return (getbool(KEYFILE_KF(me)->f & KF_MODIFIED)); } +static PyObject *kfget_writep(PyObject *me, void *hunoz) + { return (getbool(KEYFILE_KF(me)->f & KF_WRITE)); } +static PyObject *kfget_filep(PyObject *me, void *hunoz) + { return (getbool(!!KEYFILE_KF(me)->fp)); } + +static PyMethodDef keyfile_pymethods[] = { +#define METHNAME(func) kfmeth_##func + METH (save, "KF.save()") + KWMETH(merge, "KF.merge(FILE, report = )") + KWMETH(newkey, "KF.newkey(ID, TYPE, exptime = KEXP_FOREVER) -> KEY") + METH (byid, "KF.byid(KEYID) -> KEY|None") + METH (bytype, "KF.bytype(TYPE) -> KEY|None") + METH (bytag, "KF.bytag(TAG) -> KEY|None") + KWMETH(qtag, "KF.qtag(TAG, new = KD) -> FULLTAG, KEY, OLDKD") +#undef METHNAME + { 0 } +}; + +static PyGetSetDef keyfile_pygetset[] = { +#define GETSETNAME(op, name) kf##op##_##name + GET (name, "KF.name -> file name") + GET (modifiedp, "KF.modifiedp -> has keyring been modified?") + GET (writep, "KF.writep -> is keyring modifiable?") + GET (filep, "KF.filep -> does keyring have a backing file?") +#undef GETSETNAME + { 0 } +}; + +static PyMappingMethods keyfile_pymapping = { + 0, + keyfile_pylookup, + 0 +}; + +static PyTypeObject keyfile_pytype_skel = { + PyObject_HEAD_INIT(0) 0, /* Header */ + "catacomb.KeyFile", /* @tp_name@ */ + sizeof(keyfile_pyobj), /* @tp_basicsize@ */ + 0, /* @tp_itemsize@ */ + + keyfile_pydealloc, /* @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@ */ + &keyfile_pymapping, /* @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@ */ +"Keyring file.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + keyiter_new, /* @tp_iter@ */ + 0, /* @tp_iternexr@ */ + keyfile_pymethods, /* @tp_methods@ */ + 0, /* @tp_members@ */ + keyfile_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@ */ + keyfile_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + +/*----- Global stuff ------------------------------------------------------*/ + +static PyObject *meth_barf(PyObject *me, PyObject *arg) +{ + int err; + + if (PyArg_ParseTuple(arg, "i:barf", &err)) + KEYERR(err); +end: + return (0); +} + +static PyMethodDef methods[] = { +#define METHNAME(func) meth_##func + METH (_KeyData_readflags, + "KeyData.readflags(STRING) -> (FLAGS, MASK, REST)") + METH (_KeyData_writeflags, "KeyData.writeflags(FLAGS) -> STRING") + METH (_KeyData_read, "KeyData.read(STRING) -> (KD, REST)") + METH (_KeyData_decode, "KeyData.read(BYTES) -> KD") + METH (barf, "barf(ERR)") +#undef METHNAME + { 0 } +}; + +/*----- Initialization ----------------------------------------------------*/ + +void key_pyinit(void) +{ + INITTYPE(keyfile, root); + INITTYPE(key, root); + INITTYPE(keyiter, root); + INITTYPE(keydata, root); + INITTYPE(keydatabin, keydata); + INITTYPE(keydataenc, keydata); + INITTYPE(keydatastr, keydata); + INITTYPE(keydatamp, keydata); + INITTYPE(keydataec, keydata); + INITTYPE(keydatastruct, keydata); + INITTYPE(subkeyiter, root); + INITTYPE(keyattrs, root); + INITTYPE(keyattriter, root); + addmethods(methods); +} + +void key_pyinsert(PyObject *mod) +{ + INSEXC("KeyError", keyexc, PyExc_Exception, keyexc_pymethods); + INSEXC("KeyFileIOError", keyioexc, PyExc_OSError, 0); + INSEXC("KeyFileBroken", keyfilebrokenexc, keyioexc, 0); + INSERT("KeyFile", keyfile_pytype); + INSERT("KeyFileIter", keyiter_pytype); + INSERT("Key", key_pytype); + INSERT("KeyAttributes", keyattrs_pytype); + INSERT("KeyAttributeIter", keyattriter_pytype); + INSERT("KeyData", keydata_pytype); + INSERT("KeyDataBinary", keydatabin_pytype); + INSERT("KeyDataEncrypted", keydataenc_pytype); + INSERT("KeyDataMP", keydatamp_pytype); + INSERT("KeyDataECPt", keydataec_pytype); + INSERT("KeyDataString", keydatastr_pytype); + INSERT("KeyDataStructured", keydatastruct_pytype); + INSERT("SubKeyIter", subkeyiter_pytype); } /*----- That's all, folks -------------------------------------------------*/ diff --git a/pubkey.c b/pubkey.c index 862fe51..52d0ca5 100644 --- a/pubkey.c +++ b/pubkey.c @@ -378,7 +378,7 @@ static PyObject *kcdsameth_sign(PyObject *me, PyObject *arg, PyObject *kw) if (n != DSA_D(me)->h->hashsz) VALERR("bad message length (doesn't match hash size)"); r = bytestring_pywrap(0, DSA_D(me)->h->hashsz); - s.r = PyString_AS_STRING(r); + s.r = (octet *)PyString_AS_STRING(r); gkcdsa_sign(DSA_D(me), &s, p, k); rc = Py_BuildValue("(NN)", r, mp_pywrap(s.s)); end: diff --git a/setup.py b/setup.py index 0fa8848..adf9474 100644 --- a/setup.py +++ b/setup.py @@ -40,8 +40,6 @@ def uniquify(l): u[i] = 1 return o -cflags = [] -libs = [] libconfig('catacomb', '2.1.0') libconfig('mLib', '2.0.3') @@ -94,20 +92,21 @@ for g in ['algorithms.h']: rename(fnew, fout) cat = Extension('catacomb._base', - ['catacomb.c', 'bytestring.c', + ['catacomb.c', 'bytestring.c', 'buffer.c', 'rand.c', 'algorithms.c', 'pubkey.c', 'pgen.c', - 'mp.c', 'field.c', 'ec.c', 'group.c', 'passphrase.c'], + 'mp.c', 'field.c', 'ec.c', 'group.c', 'passphrase.c', + 'share.c', 'key.c'], ##extra_compile_args = ['-O0'], include_dirs = uniquify(incdirs), library_dirs = uniquify(libdirs), libraries = uniquify(libs)) -setup(name = 'Catacomb', - version = '2.1.0', +setup(name = 'catacomb-python', + version = '1.0.0', description = 'Interface to Catacomb cryptographic library', - url = 'http://tux.nsict.org/~mdw/Catacomb-2.1.0', + url = 'http://www.distorted.org.uk/~mdw/Catacomb-2.1.0', author = 'Straylight/Edgeware', - author_email = 'mdw@nsict.org', + author_email = 'mdw@distorted.org.uk', license = 'GNU General Public License', packages = ['catacomb'], scripts = ['pwsafe'], diff --git a/share.c b/share.c new file mode 100644 index 0000000..38d966e --- /dev/null +++ b/share.c @@ -0,0 +1,640 @@ +/* -*-c-*- + * + * $Id$ + * + * Secret sharing + * + * (c) 2005 Straylight/Edgeware + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of the Python interface to Catacomb. + * + * Catacomb/Python is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * Catacomb/Python is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Catacomb/Python; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/*----- Header files ------------------------------------------------------*/ + +#include "catacomb-python.h" + +/*----- GF(2^8)-based secret-sharing --------------------------------------*/ + +typedef struct gfshare_pyobj { + PyObject_HEAD + gfshare s; +} gfshare_pyobj; + +static PyTypeObject + *gfshare_pytype, *gfsharesplit_pytype, *gfsharejoin_pytype; +#define GFSHARE_PYCHECK(o) PyObject_TypeCheck((o), gfshare_pytype) +#define GFSHARESPLIT_PYCHECK(o) PyObject_TypeCheck((o), gfsharesplit_pytype) +#define GFSHAREJOIN_PYCHECK(o) PyObject_TypeCheck((o), gfsharejoin_pytype) +#define GFSHARE_S(o) (&((gfshare_pyobj *)(o))->s) + +static void gfshare_pydealloc(PyObject *me) +{ + gfshare_destroy(GFSHARE_S(me)); + FREEOBJ(me); +} + +static PyObject *gfsget_threshold(PyObject *me, void *hunoz) + { return (PyInt_FromLong(GFSHARE_S(me)->t)); } +static PyObject *gfsget_size(PyObject *me, void *hunoz) + { return (PyInt_FromLong(GFSHARE_S(me)->sz)); } + +static PyGetSetDef gfshare_pygetset[]= { +#define GETSETNAME(op, name) gfs##op##_##name + GET (threshold, "S.threshold -> THRESHOLD") + GET (size, "S.size -> SECRETSZ") +#undef GETSETNAME + { 0 } +}; + +static PyTypeObject gfshare_pytype_skel = { + PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */ + "catacomb.GFShare", /* @tp_name@ */ + sizeof(gfshare_pyobj), /* @tp_basicsize@ */ + 0, /* @tp_itemsize@ */ + + gfshare_pydealloc, /* @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@ */ +"Binary-field secret sharing base class.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + 0, /* @tp_iter@ */ + 0, /* @tp_iternexr@ */ + 0, /* @tp_methods@ */ + 0, /* @tp_members@ */ + gfshare_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 PyObject *gfsharesplit_pynew(PyTypeObject *ty, + PyObject *arg, PyObject *kw) +{ + char *p; + int n; + unsigned t; + grand *r = &rand_global; + gfshare_pyobj *s; + char *kwlist[] = { "threshold", "secret", "rng", 0 }; + if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&s#|O&:new", kwlist, + convuint, &t, &p, &n, convgrand, &r)) + goto end; + if (!t || t > 255) VALERR("threshold must be nonzero and < 256"); + s = (gfshare_pyobj *)ty->tp_alloc(ty, 0); + gfshare_create(&s->s, t, n); + gfshare_mkshares(&s->s, r, p); + return ((PyObject *)s); +end: + return (0); +} + +static PyObject *gfsmeth_get(PyObject *me, PyObject *arg) +{ + unsigned i; + PyObject *rc = 0; + if (!PyArg_ParseTuple(arg, "O&:get", convuint, &i)) goto end; + if (i >= 255) VALERR("index must be < 255"); + rc = bytestring_pywrap(0, GFSHARE_S(me)->sz); + gfshare_get(GFSHARE_S(me), i, PyString_AS_STRING(rc)); +end: + return (rc); +} + +static PyMethodDef gfsharesplit_pymethods[] = { +#define METHNAME(name) gfsmeth_##name + METH (get, "S.get(I) -> SHARE") +#undef METHNAME + { 0 } +}; + +static PyTypeObject gfsharesplit_pytype_skel = { + PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */ + "catacomb.GFShareSplit", /* @tp_name@ */ + sizeof(gfshare_pyobj), /* @tp_basicsize@ */ + 0, /* @tp_itemsize@ */ + + gfshare_pydealloc, /* @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@ */ +"Binary field secret sharing: split secret into shares.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + 0, /* @tp_iter@ */ + 0, /* @tp_iternexr@ */ + gfsharesplit_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@ */ + gfsharesplit_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + +static PyObject *gfsharejoin_pynew(PyTypeObject *ty, + PyObject *arg, PyObject *kw) +{ + unsigned t, sz; + gfshare_pyobj *s; + char *kwlist[] = { "threshold", "size", 0 }; + if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&:new", kwlist, + convuint, &t, convuint, &sz)) + goto end; + if (!t || t > 255) VALERR("threshold must be nonzero and < 256"); + s = (gfshare_pyobj *)ty->tp_alloc(ty, 0); + gfshare_create(&s->s, t, sz); + return ((PyObject *)s); +end: + return (0); +} + +static PyObject *gfsmeth_addedp(PyObject *me, PyObject *arg) +{ + unsigned i; + if (!PyArg_ParseTuple(arg, "O&:addedp", convuint, &i)) goto end; + if (i > 254) VALERR("index must be < 255"); + return (getbool(gfshare_addedp(GFSHARE_S(me), i))); +end: + return (0); +} + +static PyObject *gfsmeth_add(PyObject *me, PyObject *arg) +{ + unsigned i; + char *p; + int n; + if (!PyArg_ParseTuple(arg, "O&s#:add", convuint, &i, &p, &n)) goto end; + if (i > 254) VALERR("index must be < 255"); + if (n != GFSHARE_S(me)->sz) VALERR("bad share size"); + if (gfshare_addedp(GFSHARE_S(me), i)) VALERR("this share already added"); + if (GFSHARE_S(me)->i >= GFSHARE_S(me)->t) VALERR("enough shares already"); + gfshare_add(GFSHARE_S(me), i, p); + return (PyInt_FromLong(GFSHARE_S(me)->t - GFSHARE_S(me)->i)); +end: + return (0); +} + +static PyObject *gfsmeth_combine(PyObject *me, PyObject *arg) +{ + PyObject *rc = 0; + if (!PyArg_ParseTuple(arg, ":combine")) goto end; + if (GFSHARE_S(me)->i < GFSHARE_S(me)->t) VALERR("not enough shares yet"); + rc = bytestring_pywrap(0, GFSHARE_S(me)->sz); + gfshare_combine(GFSHARE_S(me), PyString_AS_STRING(rc)); +end: + return (rc); +} + +static PyMethodDef gfsharejoin_pymethods[] = { +#define METHNAME(name) gfsmeth_##name + METH (addedp, "S.addedp(I) -> BOOL") + METH (add, "S.add(I, SHARE) -> REMAIN") + METH (combine, "S.combine() -> SECRET") +#undef METHNAME + { 0 } +}; + +static PyObject *gfsget_remain(PyObject *me, void *hunoz) + { return (PyInt_FromLong(GFSHARE_S(me)->t - GFSHARE_S(me)->i)); } + +static PyGetSetDef gfsharejoin_pygetset[]= { +#define GETSETNAME(op, name) gfs##op##_##name + GET (remain, "S.remain -> REMAIN") +#undef GETSETNAME + { 0 } +}; + +static PyTypeObject gfsharejoin_pytype_skel = { + PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */ + "catacomb.GFShareJoin", /* @tp_name@ */ + sizeof(gfshare_pyobj), /* @tp_basicsize@ */ + 0, /* @tp_itemsize@ */ + + gfshare_pydealloc, /* @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@ */ +"Binary field secret sharing: join shares to recover secret.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + 0, /* @tp_iter@ */ + 0, /* @tp_iternexr@ */ + gfsharejoin_pymethods, /* @tp_methods@ */ + 0, /* @tp_members@ */ + gfsharejoin_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@ */ + gfsharejoin_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + +/*----- Prime-field secret-sharing ----------------------------------------*/ + +typedef struct share_pyobj { + PyObject_HEAD + share s; +} share_pyobj; + +static PyTypeObject + *share_pytype, *sharesplit_pytype, *sharejoin_pytype; +#define SHARE_PYCHECK(o) PyObject_TypeCheck((o), share_pytype) +#define SHARESPLIT_PYCHECK(o) PyObject_TypeCheck((o), sharesplit_pytype) +#define SHAREJOIN_PYCHECK(o) PyObject_TypeCheck((o), sharejoin_pytype) +#define SHARE_S(o) (&((share_pyobj *)(o))->s) + +static void share_pydealloc(PyObject *me) +{ + share_destroy(SHARE_S(me)); + FREEOBJ(me); +} + +static PyObject *sget_threshold(PyObject *me, void *hunoz) + { return (PyInt_FromLong(SHARE_S(me)->t)); } +static PyObject *sget_modulus(PyObject *me, void *hunoz) + { return (mp_pywrap(SHARE_S(me)->p)); } + +static PyGetSetDef share_pygetset[]= { +#define GETSETNAME(op, name) s##op##_##name + GET (threshold, "S.threshold -> THRESHOLD") + GET (modulus, "S.modulus -> MODULUS") +#undef GETSETNAME + { 0 } +}; + +static PyTypeObject share_pytype_skel = { + PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */ + "catacomb.Share", /* @tp_name@ */ + sizeof(share_pyobj), /* @tp_basicsize@ */ + 0, /* @tp_itemsize@ */ + + share_pydealloc, /* @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@ */ +"Prime-field secret sharing base class.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + 0, /* @tp_iter@ */ + 0, /* @tp_iternexr@ */ + 0, /* @tp_methods@ */ + 0, /* @tp_members@ */ + share_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 PyObject *sharesplit_pynew(PyTypeObject *ty, + PyObject *arg, PyObject *kw) +{ + mp *sec = 0; + unsigned t; + grand *r = &rand_global; + mp *m = 0; + share_pyobj *s; + char *kwlist[] = { "threshold", "secret", "modulus", "rng", 0 }; + if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&)&|O&O&:new", kwlist, + convuint, &t, convmp, &sec, + convmp, &m, convgrand, &r)) + goto end; + if (!t) VALERR("threshold must be nonzero"); + s = (share_pyobj *)ty->tp_alloc(ty, 0); + share_create(&s->s, t); + s->s.p = m; + share_mkshares(&s->s, r, sec); + mp_drop(sec); + return ((PyObject *)s); +end: + mp_drop(m); + mp_drop(sec); + return (0); +} + +static PyObject *smeth_get(PyObject *me, PyObject *arg) +{ + unsigned i; + PyObject *rc = 0; + if (!PyArg_ParseTuple(arg, "O&:get", convuint, &i)) goto end; + rc = mp_pywrap(share_get(SHARE_S(me), MP_NEW, i)); +end: + return (rc); +} + +static PyMethodDef sharesplit_pymethods[] = { +#define METHNAME(name) smeth_##name + METH (get, "S.get(I) -> SHARE") +#undef METHNAME + { 0 } +}; + +static PyTypeObject sharesplit_pytype_skel = { + PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */ + "catacomb.ShareSplit", /* @tp_name@ */ + sizeof(share_pyobj), /* @tp_basicsize@ */ + 0, /* @tp_itemsize@ */ + + share_pydealloc, /* @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@ */ +"Prime field secret sharing: split secret into shares.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + 0, /* @tp_iter@ */ + 0, /* @tp_iternexr@ */ + sharesplit_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@ */ + sharesplit_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + +static PyObject *sharejoin_pynew(PyTypeObject *ty, + PyObject *arg, PyObject *kw) +{ + unsigned t; + mp *m = 0; + share_pyobj *s; + char *kwlist[] = { "threshold", "modulus", 0 }; + if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&:new", kwlist, + convuint, &t, convmp, &m)) + goto end; + if (!t) VALERR("threshold must be nonzero"); + s = (share_pyobj *)ty->tp_alloc(ty, 0); + share_create(&s->s, t); + s->s.p = m; + return ((PyObject *)s); +end: + mp_drop(m); + return (0); +} + +static PyObject *smeth_addedp(PyObject *me, PyObject *arg) +{ + unsigned i; + if (!PyArg_ParseTuple(arg, "O&:addedp", convuint, &i)) goto end; + return (getbool(share_addedp(SHARE_S(me), i))); +end: + return (0); +} + +static PyObject *smeth_add(PyObject *me, PyObject *arg) +{ + unsigned i; + mp *s = 0; + PyObject *rc = 0; + if (!PyArg_ParseTuple(arg, "O&O&:add", convuint, &i, convmp, &s)) goto end; + if (MP_NEGP(s) || MP_CMP(s, >=, SHARE_S(me)->p)) + VALERR("share out of range"); + if (share_addedp(SHARE_S(me), i)) VALERR("this share already added"); + if (SHARE_S(me)->i >= SHARE_S(me)->t) VALERR("enough shares already"); + share_add(SHARE_S(me), i, s); + rc = PyInt_FromLong(SHARE_S(me)->t - SHARE_S(me)->i); +end: + mp_drop(s); + return (rc); +} + +static PyObject *smeth_combine(PyObject *me, PyObject *arg) +{ + PyObject *rc = 0; + if (!PyArg_ParseTuple(arg, ":combine")) goto end; + if (SHARE_S(me)->i < SHARE_S(me)->t) VALERR("not enough shares yet"); + rc = mp_pywrap(share_combine(SHARE_S(me))); +end: + return (rc); +} + +static PyMethodDef sharejoin_pymethods[] = { +#define METHNAME(name) smeth_##name + METH (addedp, "S.addedp(I) -> BOOL") + METH (add, "S.add(I, SHARE) -> REMAIN") + METH (combine, "S.combine() -> SECRET") +#undef METHNAME + { 0 } +}; + +static PyObject *sget_remain(PyObject *me, void *hunoz) + { return (PyInt_FromLong(SHARE_S(me)->t - SHARE_S(me)->i)); } + +static PyGetSetDef sharejoin_pygetset[]= { +#define GETSETNAME(op, name) s##op##_##name + GET (remain, "S.remain -> REMAIN") +#undef GETSETNAME + { 0 } +}; + +static PyTypeObject sharejoin_pytype_skel = { + PyObject_HEAD_INIT(&PyType_Type) 0, /* Header */ + "catacomb.ShareJoin", /* @tp_name@ */ + sizeof(share_pyobj), /* @tp_basicsize@ */ + 0, /* @tp_itemsize@ */ + + share_pydealloc, /* @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@ */ +"Prime field secret sharing: join shares to recover secret.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + 0, /* @tp_iter@ */ + 0, /* @tp_iternexr@ */ + sharejoin_pymethods, /* @tp_methods@ */ + 0, /* @tp_members@ */ + sharejoin_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@ */ + sharejoin_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + +/*----- Global stuff ------------------------------------------------------*/ + +void share_pyinit(void) +{ + INITTYPE(gfshare, root); + INITTYPE(gfsharesplit, gfshare); + INITTYPE(gfsharejoin, gfshare); + INITTYPE(share, root); + INITTYPE(sharesplit, share); + INITTYPE(sharejoin, share); +} + +void share_pyinsert(PyObject *mod) +{ + INSERT("GFShare", gfshare_pytype); + INSERT("GFShareSplit", gfsharesplit_pytype); + INSERT("GFShareJoin", gfsharejoin_pytype); + INSERT("Share", share_pytype); + INSERT("ShareSplit", sharesplit_pytype); + INSERT("ShareJoin", sharejoin_pytype); +} + +/*----- That's all, folks -------------------------------------------------*/ -- [mdw]