From: Mark Wooding Date: Sun, 14 May 2017 03:28:02 +0000 (+0100) Subject: Merge branch '1.1.x' X-Git-Tag: 1.2.0~21 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/catacomb-python/commitdiff_plain/457b4e971a2795898c83a53ae4c27d6a893690d1?hp=a1e3dbc594b83e7e391c4b9453956c7cdf37915e Merge branch '1.1.x' * 1.1.x: Release 1.1.2. catacomb/__init__.py: Fix up cipher etc. names better. algorithms.c: Support the new 16-bit key-size descriptors. group.c: Track Catacomb group internals change. utils.c: Raise exceptions from `convTHING' with null arguments. Return `long' objects when `int' is requested but the value won't fit. bytestring.c: Check for cached hash more carefully. rand.c: Careful range checking on `block' and `mp'. *.c: Fix docstrings for methods. Further fixing to use `Py_ssize_t' in place of int. Conflicts: debian/control (already wanted later catacomb-dev) group.c (no need for compatibility with older Catacombs) --- diff --git a/algorithms.c b/algorithms.c index 3a618d0..5703901 100644 --- a/algorithms.c +++ b/algorithms.c @@ -473,7 +473,7 @@ static PyObject *gcipher_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) { char *kwlist[] = { "k", 0 }; char *k; - int sz; + Py_ssize_t sz; if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &k, &sz)) goto end; @@ -522,7 +522,7 @@ static PyObject *gccget_blksz(PyObject *me, void *hunoz) static PyObject *gcmeth_encrypt(PyObject *me, PyObject *arg) { char *p; - int sz; + Py_ssize_t sz; PyObject *rc = 0; if (!PyArg_ParseTuple(arg, "s#:encrypt", &p, &sz)) return (0); @@ -548,7 +548,7 @@ static PyObject *gcmeth_enczero(PyObject *me, PyObject *arg) static PyObject *gcmeth_decrypt(PyObject *me, PyObject *arg) { char *p; - int sz; + Py_ssize_t sz; PyObject *rc = 0; if (!PyArg_ParseTuple(arg, "s#:decrypt", &p, &sz)) return (0); @@ -574,9 +574,10 @@ static PyObject *gcmeth_deczero(PyObject *me, PyObject *arg) static PyObject *gcmeth_setiv(PyObject *me, PyObject *arg) { char *p; - int sz; + Py_ssize_t sz; if (!PyArg_ParseTuple(arg, "s#:setiv", &p, &sz)) goto end; + if (!GCIPHER_C(me)->ops->setiv) VALERR("`setiv' not supported"); if (!GC_CLASS(GCIPHER_C(me))->blksz) VALERR("not a block cipher mode"); if (sz != GC_CLASS(GCIPHER_C(me))->blksz) VALERR("bad IV length"); GC_SETIV(GCIPHER_C(me), p); @@ -588,6 +589,7 @@ end: static PyObject *gcmeth_bdry(PyObject *me, PyObject *arg) { if (!PyArg_ParseTuple(arg, ":bdry")) goto end; + if (!GCIPHER_C(me)->ops->bdry) VALERR("`bdry' not supported"); if (!GC_CLASS(GCIPHER_C(me))->blksz) VALERR("not a block cipher mode"); GC_BDRY(GCIPHER_C(me)); RETURN_ME; @@ -777,33 +779,12 @@ static PyObject *gchget_bufsz(PyObject *me, void *hunoz) static PyObject *ghmeth_hash(PyObject *me, PyObject *arg) { char *p; - int sz; + Py_ssize_t sz; if (!PyArg_ParseTuple(arg, "s#:hash", &p, &sz)) return (0); GH_HASH(GHASH_H(me), p, sz); RETURN_ME; } -static PyObject *ghmeth_done(PyObject *me, PyObject *arg) -{ - ghash *g; - PyObject *rc; - if (!PyArg_ParseTuple(arg, ":done")) return (0); - g = GH_COPY(GHASH_H(me)); - rc = bytestring_pywrap(0, g->ops->c->hashsz); - GH_DONE(g, PyString_AS_STRING(rc)); - GH_DESTROY(g); - return (rc); -} - -static PyGetSetDef gchash_pygetset[] = { -#define GETSETNAME(op, name) gch##op##_##name - GET (bufsz, "CH.bufsz -> hash buffer size, or zero") - GET (hashsz, "CH.blksz -> hash output size") - GET (name, "CH.name -> name of this kind of hash") -#undef GETSETNAME - { 0 } -}; - #define GHMETH_HASHU_(n, W, w) \ static PyObject *ghmeth_hashu##w(PyObject *me, PyObject *arg) \ { \ @@ -820,7 +801,7 @@ DOUINTCONV(GHMETH_HASHU_) static PyObject *ghmeth_hashbuf##w(PyObject *me, PyObject *arg) \ { \ char *p; \ - int sz; \ + Py_ssize_t 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); \ @@ -838,13 +819,36 @@ static PyObject *ghmeth_hashstrz(PyObject *me, PyObject *arg) RETURN_ME; } +static PyObject *ghmeth_done(PyObject *me, PyObject *arg) +{ + ghash *g; + PyObject *rc; + if (!PyArg_ParseTuple(arg, ":done")) return (0); + g = GH_COPY(GHASH_H(me)); + rc = bytestring_pywrap(0, g->ops->c->hashsz); + GH_DONE(g, PyString_AS_STRING(rc)); + GH_DESTROY(g); + return (rc); +} + +static PyGetSetDef gchash_pygetset[] = { +#define GETSETNAME(op, name) gch##op##_##name + GET (bufsz, "CH.bufsz -> hash buffer size, or zero") + GET (hashsz, "CH.hashsz -> hash output size") + GET (name, "CH.name -> name of this kind of hash") +#undef GETSETNAME + { 0 } +}; + 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_) +#undef METHU_ #define METHBUF_(n, W, w) METH(hashbuf##w, "H.hashbuf" #w "(BYTES)") DOUINTCONV(METHBUF_) +#undef METHBUF_ METH (hashstrz, "H.hashstrz(STRING)") METH (done, "H.done() -> HASH") #undef METHNAME @@ -959,7 +963,7 @@ static PyObject *gmac_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) { char *kwlist[] = { "k", 0 }; char *k; - int sz; + Py_ssize_t sz; if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &k, &sz)) goto end; @@ -1007,6 +1011,7 @@ PyObject *gmac_pywrap(PyObject *cobj, gmac *m, unsigned f) if (!cobj) cobj = gcmac_pywrap((/*unconst*/ gcmac *)GM_CLASS(m)); else Py_INCREF(cobj); g = newtype((PyTypeObject *)cobj, 0, 0); + g->ty.ht_type.tp_basicsize = sizeof(ghash_pyobj); g->ty.ht_name = PyString_FromFormat("%s(keyed)", m->ops->c->name); g->ty.ht_type.tp_name = PyString_AS_STRING(g->ty.ht_name); g->ty.ht_type.tp_base = gmhash_pytype; @@ -1193,6 +1198,394 @@ static PyTypeObject gmhash_pytype_skel = { 0 /* @tp_is_gc@ */ }; +/*----- Special snowflake for Poly1305 ------------------------------------*/ + +PyTypeObject *poly1305cls_pytype, *poly1305key_pytype, *poly1305hash_pytype; + +typedef struct poly1305key_pyobj { + PyHeapTypeObject ty; + poly1305_key k; +} poly1305key_pyobj; + +typedef struct poly1305hash_pyobj { + PyObject_HEAD + unsigned f; +#define f_mask 1u + poly1305_ctx ctx; +} poly1305hash_pyobj; + +#define P1305_F(o) (((poly1305hash_pyobj *)(o))->f) +#define P1305_CTX(o) (&((poly1305hash_pyobj *)(o))->ctx) +CONVFUNC(poly1305hash, poly1305_ctx *, P1305_CTX) + +static PyObject *poly1305hash_pynew(PyTypeObject *ty, + PyObject *arg, PyObject *kw) +{ + char *kwlist[] = { "mask", 0 }; + poly1305key_pyobj *pk = (poly1305key_pyobj *)ty; + poly1305hash_pyobj *ph; + char *m = 0; + Py_ssize_t sz; + + if (!PyArg_ParseTupleAndKeywords(arg, kw, "|s#:new", kwlist, &m, &sz)) + return (0); + if (m && sz != POLY1305_MASKSZ) VALERR("bad mask length"); + ph = PyObject_NEW(poly1305hash_pyobj, ty); + ph->f = 0; + if (m) ph->f |= f_mask; + poly1305_macinit(&ph->ctx, &pk->k, m); + Py_INCREF(ty); + return ((PyObject *)ph); +end: + return (0); +} + +static PyObject *poly1305key_pynew(PyTypeObject *ty, + PyObject *arg, PyObject *kw) +{ + char *kwlist[] = { "k", 0 }; + poly1305key_pyobj *pk; + char *k; + Py_ssize_t sz; + + if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &k, &sz)) + goto end; + if (keysz(sz, poly1305_keysz) != sz) VALERR("bad key length"); + + pk = newtype(ty, 0, 0); + pk->ty.ht_name = PyString_FromString("poly1305(keyed)"); + pk->ty.ht_type.tp_basicsize = sizeof(poly1305hash_pyobj); + pk->ty.ht_type.tp_name = PyString_AS_STRING(pk->ty.ht_name); + pk->ty.ht_type.tp_base = poly1305hash_pytype; + Py_INCREF(poly1305key_pytype); + pk->ty.ht_type.tp_flags = (Py_TPFLAGS_DEFAULT | + Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_HEAPTYPE); + pk->ty.ht_type.tp_alloc = PyType_GenericAlloc; + pk->ty.ht_type.tp_free = 0; + pk->ty.ht_type.tp_new = poly1305hash_pynew; + typeready(&pk->ty.ht_type); + + poly1305_keyinit(&pk->k, k, sz); + return ((PyObject *)pk); + +end: + return (0); +} + +static PyObject *poly1305clsget_name(PyObject *me, void *hunoz) + { return (PyString_FromString("poly1305")); } + +static PyObject *poly1305clsget_keysz(PyObject *me, void *hunoz) + { return (keysz_pywrap(poly1305_keysz)); } + +static PyObject *poly1305clsget_masksz(PyObject *me, void *hunoz) + { return (PyInt_FromLong(POLY1305_MASKSZ)); } + +static PyObject *poly1305clsget_tagsz(PyObject *me, void *hunoz) + { return (PyInt_FromLong(POLY1305_TAGSZ)); } + +static PyObject *polymeth_copy(PyObject *me, PyObject *arg) +{ + poly1305hash_pyobj *ph; + if (!PyArg_ParseTuple(arg, ":copy")) return (0); + ph = PyObject_NEW(poly1305hash_pyobj, me->ob_type); + poly1305_copy(&ph->ctx, P1305_CTX(me)); + Py_INCREF(me->ob_type); + return ((PyObject *)ph); +} + +static PyObject *polymeth_hash(PyObject *me, PyObject *arg) +{ + char *p; + Py_ssize_t sz; + if (!PyArg_ParseTuple(arg, "s#:hash", &p, &sz)) return (0); + poly1305_hash(P1305_CTX(me), p, sz); + RETURN_ME; +} + +#define POLYMETH_HASHU_(n, W, w) \ + static PyObject *polymeth_hashu##w(PyObject *me, PyObject *arg) \ + { \ + uint##n x; \ + octet b[SZ_##W]; \ + if (!PyArg_ParseTuple(arg, "O&:hashu" #w, convu##n, &x)) goto end; \ + STORE##W(b, x); poly1305_hash(P1305_CTX(me), b, sizeof(b)); \ + RETURN_ME; \ + end: \ + return (0); \ + } +DOUINTCONV(POLYMETH_HASHU_) + +#define POLYMETH_HASHBUF_(n, W, w) \ + static PyObject *polymeth_hashbuf##w(PyObject *me, PyObject *arg) \ + { \ + char *p; \ + Py_ssize_t sz; \ + octet b[SZ_##W]; \ + if (!PyArg_ParseTuple(arg, "s#:hashbuf" #w, &p, &sz)) goto end; \ + if (sz > MASK##n) TYERR("string too long"); \ + STORE##W(b, sz); poly1305_hash(P1305_CTX(me), b, sizeof(b)); \ + poly1305_hash(P1305_CTX(me), p, sz); \ + RETURN_ME; \ + end: \ + return (0); \ + } +DOUINTCONV(POLYMETH_HASHBUF_) + +static PyObject *polymeth_hashstrz(PyObject *me, PyObject *arg) +{ + char *p; + if (!PyArg_ParseTuple(arg, "s:hashstrz", &p)) return (0); + poly1305_hash(P1305_CTX(me), p, strlen(p) + 1); + RETURN_ME; +} + +static PyObject *polymeth_flush(PyObject *me, PyObject *arg) +{ + if (!PyArg_ParseTuple(arg, ":flush")) return (0); + poly1305_flush(P1305_CTX(me)); + RETURN_ME; +} + +static PyObject *polymeth_flushzero(PyObject *me, PyObject *arg) +{ + if (!PyArg_ParseTuple(arg, ":flushzero")) return (0); + poly1305_flushzero(P1305_CTX(me)); + RETURN_ME; +} + +static PyObject *polymeth_concat(PyObject *me, PyObject *arg) +{ + PyObject *pre, *suff; + if (!PyArg_ParseTuple(arg, "OO:concat", &pre, &suff)) return (0); + if (!PyObject_TypeCheck(pre, poly1305hash_pytype) || + !PyObject_TypeCheck(suff, poly1305hash_pytype)) + TYERR("wanted a poly1305hash"); + if (me->ob_type != pre->ob_type || me->ob_type != suff->ob_type) + TYERR("key mismatch"); + if (P1305_CTX(pre)->nbuf) VALERR("prefix is not block-aligned"); + poly1305_concat(P1305_CTX(me), P1305_CTX(pre), P1305_CTX(suff)); + RETURN_ME; +end: + return (0); +} + +static PyObject *polymeth_done(PyObject *me, PyObject *arg) +{ + PyObject *rc; + if (!PyArg_ParseTuple(arg, ":done")) return (0); + if (!(P1305_F(me) & f_mask)) VALERR("no mask"); + rc = bytestring_pywrap(0, POLY1305_TAGSZ); + poly1305_done(P1305_CTX(me), PyString_AS_STRING(rc)); + return (rc); +end: + return (0); +} + +static PyGetSetDef poly1305cls_pygetset[] = { +#define GETSETNAME(op, name) poly1305cls##op##_##name + GET (keysz, "PC.keysz -> acceptable key sizes") + GET (masksz, "PC.masksz -> mask size") + GET (tagsz, "PC.tagsz -> MAC output size") + GET (name, "PC.name -> name of this kind of MAC") +#undef GETSETNAME + { 0 } +}; + +static PyMethodDef poly1305hash_pymethods[] = { +#define METHNAME(name) polymeth_##name + METH (copy, "P.copy() -> PP") + METH (hash, "P.hash(M)") +#define METHU_(n, W, w) METH(hashu##w, "P.hashu" #w "(WORD)") + DOUINTCONV(METHU_) +#undef METHU_ +#define METHBUF_(n, W, w) METH(hashbuf##w, "P.hashbuf" #w "(BYTES)") + DOUINTCONV(METHBUF_) +#undef METHBUF_ + METH (hashstrz, "P.hashstrz(STRING)") + METH (flush, "P.flush()") + METH (flushzero, "P.flushzero()") + METH (concat, "P.concat(PREFIX, SUFFIX)") + METH (done, "P.done() -> TAG") +#undef METHNAME + { 0 } +}; + +static PyTypeObject poly1305cls_pytype_skel = { + PyObject_HEAD_INIT(0) 0, /* Header */ + "Poly1305Class", /* @tp_name@ */ + sizeof(PyHeapTypeObject), /* @tp_basicsize@ */ + 0, /* @tp_itemsize@ */ + + 0, /* @tp_dealloc@ */ + 0, /* @tp_print@ */ + 0, /* @tp_getattr@ */ + 0, /* @tp_setattr@ */ + 0, /* @tp_compare@ */ + 0, /* @tp_repr@ */ + 0, /* @tp_as_number@ */ + 0, /* @tp_as_sequence@ */ + 0, /* @tp_as_mapping@ */ + 0, /* @tp_hash@ */ + 0, /* @tp_call@ */ + 0, /* @tp_str@ */ + 0, /* @tp_getattro@ */ + 0, /* @tp_setattro@ */ + 0, /* @tp_as_buffer@ */ + Py_TPFLAGS_DEFAULT | /* @tp_flags@ */ + Py_TPFLAGS_BASETYPE, + + /* @tp_doc@ */ +"Poly1305 metametaclass. Best not to ask.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + 0, /* @tp_iter@ */ + 0, /* @tp_iternext@ */ + 0, /* @tp_methods@ */ + 0, /* @tp_members@ */ + poly1305cls_pygetset, /* @tp_getset@ */ + 0, /* @tp_base@ */ + 0, /* @tp_dict@ */ + 0, /* @tp_descr_get@ */ + 0, /* @tp_descr_set@ */ + 0, /* @tp_dictoffset@ */ + 0, /* @tp_init@ */ + PyType_GenericAlloc, /* @tp_alloc@ */ + abstract_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + +static PyTypeObject poly1305key_pytype_skel = { + PyObject_HEAD_INIT(0) 0, /* Header */ + "poly1305", /* @tp_name@ */ + sizeof(poly1305key_pyobj), /* @tp_basicsize@ */ + 0, /* @tp_itemsize@ */ + + 0, /* @tp_dealloc@ */ + 0, /* @tp_print@ */ + 0, /* @tp_getattr@ */ + 0, /* @tp_setattr@ */ + 0, /* @tp_compare@ */ + 0, /* @tp_repr@ */ + 0, /* @tp_as_number@ */ + 0, /* @tp_as_sequence@ */ + 0, /* @tp_as_mapping@ */ + 0, /* @tp_hash@ */ + 0, /* @tp_call@ */ + 0, /* @tp_str@ */ + 0, /* @tp_getattro@ */ + 0, /* @tp_setattro@ */ + 0, /* @tp_as_buffer@ */ + Py_TPFLAGS_DEFAULT | /* @tp_flags@ */ + Py_TPFLAGS_BASETYPE, + + /* @tp_doc@ */ +"Poly1305 key.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + 0, /* @tp_iter@ */ + 0, /* @tp_iternext@ */ + 0, /* @tp_methods@ */ + 0, /* @tp_members@ */ + 0, /* @tp_getset@ */ + 0, /* @tp_base@ */ + 0, /* @tp_dict@ */ + 0, /* @tp_descr_get@ */ + 0, /* @tp_descr_set@ */ + 0, /* @tp_dictoffset@ */ + 0, /* @tp_init@ */ + PyType_GenericAlloc, /* @tp_alloc@ */ + poly1305key_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + +static PyTypeObject poly1305hash_pytype_skel = { + PyObject_HEAD_INIT(0) 0, /* Header */ + "Poly1305Hash", /* @tp_name@ */ + sizeof(poly1305hash_pyobj), /* @tp_basicsize@ */ + 0, /* @tp_itemsize@ */ + + 0, /* @tp_dealloc@ */ + 0, /* @tp_print@ */ + 0, /* @tp_getattr@ */ + 0, /* @tp_setattr@ */ + 0, /* @tp_compare@ */ + 0, /* @tp_repr@ */ + 0, /* @tp_as_number@ */ + 0, /* @tp_as_sequence@ */ + 0, /* @tp_as_mapping@ */ + 0, /* @tp_hash@ */ + 0, /* @tp_call@ */ + 0, /* @tp_str@ */ + 0, /* @tp_getattro@ */ + 0, /* @tp_setattro@ */ + 0, /* @tp_as_buffer@ */ + Py_TPFLAGS_DEFAULT | /* @tp_flags@ */ + Py_TPFLAGS_BASETYPE, + + /* @tp_doc@ */ +"Poly1305 MAC context base class.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + 0, /* @tp_iter@ */ + 0, /* @tp_iternext@ */ + poly1305hash_pymethods, /* @tp_methods@ */ + 0, /* @tp_members@ */ + 0, /* @tp_getset@ */ + 0, /* @tp_base@ */ + 0, /* @tp_dict@ */ + 0, /* @tp_descr_get@ */ + 0, /* @tp_descr_set@ */ + 0, /* @tp_dictoffset@ */ + 0, /* @tp_init@ */ + PyType_GenericAlloc, /* @tp_alloc@ */ + abstract_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + +/*----- Special snowflake for HSalsa and HChaCha --------------------------*/ + +#define DEF_HDANCE(DANCE, HDANCE, dance, hdance) \ + static PyObject *meth_##hdance##_prf(PyObject *me, PyObject *arg) \ + { \ + dance##_ctx dance; \ + char *k, *n; \ + Py_ssize_t ksz, nsz; \ + PyObject *rc; \ + if (!PyArg_ParseTuple(arg, "s#s#:" #hdance "_prf", \ + &k, &ksz, &n, &nsz)) \ + goto end; \ + if (ksz != DANCE##_KEYSZ) VALERR("bad key length"); \ + if (nsz != HDANCE##_INSZ) VALERR("bad input length"); \ + rc = bytestring_pywrap(0, HSALSA20_OUTSZ); \ + dance##_init(&dance, k, ksz, 0); \ + hdance##_prf(&dance, n, PyString_AS_STRING(rc)); \ + return (rc); \ + end: \ + return (0); \ + } + +DEF_HDANCE(SALSA20, HSALSA20, salsa20, hsalsa20) +DEF_HDANCE(SALSA20, HSALSA20, salsa20, hsalsa2012) +DEF_HDANCE(SALSA20, HSALSA20, salsa20, hsalsa208) + +DEF_HDANCE(CHACHA, HCHACHA, chacha, hchacha20) +DEF_HDANCE(CHACHA, HCHACHA, chacha, hchacha12) +DEF_HDANCE(CHACHA, HCHACHA, chacha, hchacha8) + /*----- Pseudorandom permutations -----------------------------------------*/ static PyTypeObject *gcprp_pytype, *gprp_pytype; @@ -1254,7 +1647,7 @@ static PyObject *gprp_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) { char *kwlist[] = { "key", 0 }; char *k; - int sz; + Py_ssize_t sz; const prpinfo *prp = GCPRP_PRP(ty); PyObject *me; @@ -1300,7 +1693,7 @@ static PyObject *gcpget_blksz(PyObject *me, void *hunoz) static PyObject *gpmeth_encrypt(PyObject *me, PyObject *arg) { char *p; - int n; + Py_ssize_t n; PyObject *rc = 0; if (!PyArg_ParseTuple(arg, "s#:encrypt", &p, &n)) goto end; @@ -1314,7 +1707,7 @@ end: static PyObject *gpmeth_decrypt(PyObject *me, PyObject *arg) { char *p; - int n; + Py_ssize_t n; PyObject *rc = 0; if (!PyArg_ParseTuple(arg, "s#:decrypt", &p, &n)) goto end; @@ -1458,6 +1851,17 @@ toschnorr(N) -> M: convert work factor to Schnorr group order") toif(N) -> M: convert work factor to integer factorization problem size") METH (_KeySZ_toec, "\ toec(N) -> M: convert work factor to elliptic curve group order") + METH (_KeySZ_toec, "\ +toec(N) -> M: convert work factor to elliptic curve group order") +#define METH_HDANCE(hdance, HDance) METH(hdance##_prf, "\ +" #hdance "_prf(K, N) -> H: calculate " HDance " hash of N with K") + METH_HDANCE(hsalsa20, "HSalsa20") + METH_HDANCE(hsalsa2012, "HSalsa20/12") + METH_HDANCE(hsalsa208, "HSalsa20/8") + METH_HDANCE(hchacha20, "HChaCha20") + METH_HDANCE(hchacha12, "HChaCha12") + METH_HDANCE(hchacha8, "HChaCha8") +#undef METH_DANCE #undef METHNAME { 0 } }; @@ -1475,6 +1879,9 @@ void algorithms_pyinit(void) INITTYPE(gcmac, type); INITTYPE(gmac, type); INITTYPE(gmhash, ghash); + INITTYPE(poly1305cls, type); + INITTYPE_META(poly1305key, type, poly1305cls); + INITTYPE(poly1305hash, root); INITTYPE(gcprp, type); INITTYPE(gprp, root); addmethods(methods); @@ -1505,6 +1912,9 @@ void algorithms_pyinsert(PyObject *mod) INSERT("GMAC", gmac_pytype); INSERT("GMACHash", gmhash_pytype); INSERT("gcmacs", gcmacs()); + INSERT("Poly1305Class", poly1305cls_pytype); + INSERT("poly1305", poly1305key_pytype); + INSERT("Poly1305Hash", poly1305hash_pytype); INSERT("GCPRP", gcprp_pytype); INSERT("GPRP", gprp_pytype); INSERT("gcprps", gcprps()); diff --git a/algorithms.py b/algorithms.py index 3ceb207..a2a468f 100644 --- a/algorithms.py +++ b/algorithms.py @@ -30,8 +30,12 @@ streamciphers = ''' rc4 seal '''.split() latindances = ''' -salsa20 salsa20/12 salsa20/8 xsalsa20 xsalsa20/12 xsalsa20/8 -chacha20 chacha12 chacha8 xchacha20 xchacha12 xchacha8 +salsa20 salsa20/12 salsa20/8 +salsa20-ietf salsa20/12-ietf salsa20/8-ietf +xsalsa20 xsalsa20/12 xsalsa20/8 +chacha20 chacha12 chacha8 +chacha20-ietf chacha12-ietf chacha8-ietf +xchacha20 xchacha12 xchacha8 '''.split() streamciphers += map(lambda s: s.translate(None, '/'), latindances) hashes = ''' @@ -84,9 +88,10 @@ for i in latindances: break else: raise ValueError, 'failed to find root name for %s' % i + if i.endswith('-ietf'): root += '_ietf' print ('\t_("%(name)s", %(root)s_keysz, %(id)s_rand, ' + - 'RNGF_NONCE, %(ROOT)s_NONCESZ) \\') % \ - {'name': i, 'id': i.translate(None, '/'), + 'RNGF_NONCE | RNGF_LATIN, %(ROOT)s_NONCESZ) \\') % \ + {'name': i, 'id': i.translate(None, '/').replace('-', '_'), 'root': root, 'ROOT': root.upper()} print '\t/* end */' print diff --git a/buffer.c b/buffer.c index 6569516..43bf02d 100644 --- a/buffer.c +++ b/buffer.c @@ -53,7 +53,7 @@ static PyObject *buferr; static PyObject *rbuf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) { char *p, *q; - int n; + Py_ssize_t n; buf_pyobj *me = 0; static char *kwlist[] = { "data", 0 }; @@ -387,7 +387,7 @@ static PyObject *wbmeth_zero(PyObject *me, PyObject *arg) static PyObject *wbmeth_put(PyObject *me, PyObject *arg) { void *p; - int n; + Py_ssize_t 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))); @@ -410,7 +410,7 @@ DOUINTCONV(WBMETH_PUTU_) static PyObject *wbmeth_putblk##w(PyObject *me, PyObject *arg) \ { \ char *p; \ - int sz; \ + Py_ssize_t 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))); \ diff --git a/bytestring.c b/bytestring.c index 4a7378d..4abb260 100644 --- a/bytestring.c +++ b/bytestring.c @@ -54,13 +54,59 @@ static PyObject *bytestring_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) { const char *p; - int n; + Py_ssize_t n; static char *kwlist[] = { "data", 0 }; if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &p, &n)) return (0); return (dowrap(ty, p, n)); } +static PyObject *meth_ctstreq(PyObject *me, PyObject *args) +{ + char *p, *q; + Py_ssize_t psz, qsz; + if (!PyArg_ParseTuple(args, "s#s#:ctstreq", &p, &psz, &q, &qsz)) + goto end; + if (psz == qsz && ct_memeq(p, q, psz)) RETURN_TRUE; + else RETURN_FALSE; +end: + return (0); +} + +static PyObject *bytestring_pyrichcompare(PyObject *me, + PyObject *you, int op) +{ + int b; + void *mystr, *yourstr; + Py_ssize_t mylen, yourlen, minlen; + + if (!PyString_Check(me) || !PyString_Check(you)) RETURN_NOTIMPL; + mystr = PyString_AS_STRING(me); mylen = PyString_GET_SIZE(me); + yourstr = PyString_AS_STRING(you); yourlen = PyString_GET_SIZE(you); + + switch (op) { + case Py_EQ: + b = mylen == yourlen && ct_memeq(mystr, yourstr, mylen); + break; + case Py_NE: + b = mylen != yourlen || !ct_memeq(mystr, yourstr, mylen); + break; + default: + minlen = mylen < yourlen ? mylen : yourlen; + b = memcmp(mystr, yourstr, minlen); + if (!b) b = mylen < yourlen ? -1 : mylen > yourlen ? +1 : 0; + switch (op) { + case Py_LT: b = b < 0; break; + case Py_LE: b = b <= 0; break; + case Py_GE: b = b >= 0; break; + case Py_GT: b = b > 0; break; + default: abort(); + } + } + if (b) RETURN_TRUE; + else RETURN_FALSE; +} + #define BINOP(name, op) \ static PyObject *bytestring_py##name(PyObject *x, PyObject *y) { \ const void *xv, *yv; \ @@ -158,7 +204,7 @@ static PyTypeObject bytestring_pytype_skel = { 0, /* @tp_traverse@ */ 0, /* @tp_clear@ */ - 0, /* @tp_richcompare@ */ + bytestring_pyrichcompare, /* @tp_richcompare@ */ 0, /* @tp_weaklistoffset@ */ 0, /* @tp_iter@ */ 0, /* @tp_iternext@ */ @@ -179,10 +225,18 @@ static PyTypeObject bytestring_pytype_skel = { /*----- Initialization ----------------------------------------------------*/ +static PyMethodDef methods[] = { +#define METHNAME(func) meth_##func + METH (ctstreq, "ctstreq(S, T) -> BOOL") +#undef METHNAME + { 0 } +}; + #define string_pytype &PyString_Type void bytestring_pyinit(void) { INITTYPE(bytestring, string); + addmethods(methods); } void bytestring_pyinsert(PyObject *mod) diff --git a/catacomb-python.h b/catacomb-python.h index bed97d5..d7e2543 100644 --- a/catacomb-python.h +++ b/catacomb-python.h @@ -33,13 +33,12 @@ /*----- Header files ------------------------------------------------------*/ +#define PY_SSIZE_T_CLEAN + #include #include #include -#undef ULLONG_MAX -#undef ULONG_LONG_MAX - #include #include #include @@ -47,6 +46,7 @@ #include #include +#include #include #include @@ -65,6 +65,7 @@ #include #include #include +#include #include #include #include @@ -86,6 +87,9 @@ #include #include #include +#include +#include +#include #include #include @@ -158,10 +162,11 @@ #define root_pytype 0 #define type_pytype &PyType_Type -#define INITTYPE(ty, base) do { \ +#define INITTYPE_META(ty, base, meta) do { \ ty##_pytype_skel.tp_base = base##_pytype; \ - ty##_pytype = inittype(&ty##_pytype_skel); \ + ty##_pytype = inittype(&ty##_pytype_skel, meta##_pytype); \ } while (0) +#define INITTYPE(ty, base) INITTYPE_META(ty, base, type) #define INSERT(name, ob) do { \ PyObject *_o = (PyObject *)(ob); \ @@ -238,16 +243,18 @@ extern int convulong(PyObject *, void *); DOUINTSZ(DECL_CONVU_) extern int convmpw(PyObject *, void *); extern int convuint(PyObject *, void *); +extern int convk64(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 *getulong(unsigned long); +extern PyObject *getk64(kludge64); extern void *newtype(PyTypeObject *, const PyTypeObject *, const char *); extern PyObject *mkexc(PyObject *, PyObject *, const char *, PyMethodDef *); extern void typeready(PyTypeObject *); -extern PyTypeObject *inittype(PyTypeObject *); +extern PyTypeObject *inittype(PyTypeObject *, PyTypeObject *); extern void addmethods(const PyMethodDef *); extern PyMethodDef *donemethods(void); diff --git a/catacomb.c b/catacomb.c index 49d0f40..9c83c9d 100644 --- a/catacomb.c +++ b/catacomb.c @@ -45,6 +45,9 @@ static const struct nameval consts[] = { C(KF_NONSECRET), C(KF_BURN), C(KF_OPT), C(EC_XONLY), C(EC_YBIT), C(EC_LSB), C(EC_CMPR), C(EC_EXPLY), C(EC_SORT), + C(X25519_KEYSZ), C(X25519_PUBSZ), C(X25519_OUTSZ), + C(X448_KEYSZ), C(X448_PUBSZ), C(X448_OUTSZ), + C(ED25519_KEYSZ), C(ED25519_PUBSZ), C(ED25519_SIGSZ), #define ENTRY(tag, val, str) C(KERR_##tag), KEY_ERRORS(ENTRY) #undef ENTRY diff --git a/catacomb/__init__.py b/catacomb/__init__.py index f79b4d2..785838e 100644 --- a/catacomb/__init__.py +++ b/catacomb/__init__.py @@ -96,6 +96,44 @@ def _checkend(r): raise SyntaxError, 'junk at end of string' return x +## Some pretty-printing utilities. +PRINT_SECRETS = False +def _clsname(me): return type(me).__name__ +def _repr_secret(thing, secretp = True): + if not secretp or PRINT_SECRETS: return repr(thing) + else: return '#' +def _pp_str(me, pp, cyclep): pp.text(cyclep and '...' or str(me)) +def _pp_secret(pp, thing, secretp = True): + if not secretp or PRINT_SECRETS: pp.pretty(thing) + else: pp.text('#') +def _pp_bgroup(pp, text): + ind = len(text) + pp.begin_group(ind, text) + return ind +def _pp_bgroup_tyname(pp, obj, open = '('): + return _pp_bgroup(pp, _clsname(obj) + open) +def _pp_kv(pp, k, v, secretp = False): + ind = _pp_bgroup(pp, k + ' = ') + _pp_secret(pp, v, secretp) + pp.end_group(ind, '') +def _pp_commas(pp, printfn, items): + firstp = True + for i in items: + if firstp: firstp = False + else: pp.text(','); pp.breakable() + printfn(i) +def _pp_dict(pp, items): + def p((k, v)): + pp.begin_group(0) + pp.pretty(k) + pp.text(':') + pp.begin_group(2) + pp.breakable() + pp.pretty(v) + pp.end_group(2) + pp.end_group(0) + _pp_commas(pp, p, items) + ###-------------------------------------------------------------------------- ### Bytestrings. @@ -108,8 +146,39 @@ class _tmp: def __repr__(me): return 'bytes(%r)' % hex(me) _augment(ByteString, _tmp) +ByteString.__hash__ = str.__hash__ bytes = ByteString.fromhex +###-------------------------------------------------------------------------- +### Hashing. + +class _tmp: + def check(me, h): + hh = me.done() + return ctstreq(h, hh) +_augment(GHash, _tmp) +_augment(Poly1305Hash, _tmp) + +###-------------------------------------------------------------------------- +### NaCl `secretbox'. + +def secret_box(k, n, m): + E = xsalsa20(k).setiv(n) + r = E.enczero(poly1305.keysz.default) + s = E.enczero(poly1305.masksz) + y = E.encrypt(m) + t = poly1305(r)(s).hash(y).done() + return ByteString(t + y) + +def secret_unbox(k, n, c): + E = xsalsa20(k).setiv(n) + r = E.enczero(poly1305.keysz.default) + s = E.enczero(poly1305.masksz) + y = c[poly1305.tagsz:] + if not poly1305(r)(s).hash(y).check(c[0:poly1305.tagsz]): + raise ValueError, 'decryption failed' + return E.decrypt(c[poly1305.tagsz:]) + ###-------------------------------------------------------------------------- ### Multiprecision integers and binary polynomials. @@ -132,7 +201,8 @@ class BaseRat (object): @property def denom(me): return me._d def __str__(me): return '%s/%s' % (me._n, me._d) - def __repr__(me): return '%s(%s, %s)' % (type(me).__name__, me._n, me._d) + def __repr__(me): return '%s(%s, %s)' % (_clsname(me), me._n, me._d) + _repr_pretty_ = _pp_str def __add__(me, you): n, d = _split_rat(you) @@ -177,6 +247,7 @@ class _tmp: def reduce(x): return MPReduce(x) def __div__(me, you): return IntRat(me, you) def __rdiv__(me, you): return IntRat(you, me) + _repr_pretty_ = _pp_str _augment(MP, _tmp) class _tmp: @@ -188,6 +259,7 @@ class _tmp: def quadsolve(x, y): return x.reduce().quadsolve(y) def __div__(me, you): return GFRat(me, you) def __rdiv__(me, you): return GFRat(you, me) + _repr_pretty_ = _pp_str _augment(GF, _tmp) class _tmp: @@ -206,14 +278,24 @@ class _tmp: _augment(Field, _tmp) class _tmp: - def __repr__(me): return '%s(%sL)' % (type(me).__name__, me.p) + def __repr__(me): return '%s(%sL)' % (_clsname(me), me.p) def __hash__(me): return 0x114401de ^ hash(me.p) + def _repr_pretty_(me, pp, cyclep): + ind = _pp_bgroup_tyname(pp, me) + if cyclep: pp.text('...') + else: pp.pretty(me.p) + pp.end_group(ind, ')') def ec(me, a, b): return ECPrimeProjCurve(me, a, b) _augment(PrimeField, _tmp) class _tmp: - def __repr__(me): return '%s(%sL)' % (type(me).__name__, hex(me.p)) + def __repr__(me): return '%s(%#xL)' % (_clsname(me), me.p) def ec(me, a, b): return ECBinProjCurve(me, a, b) + def _repr_pretty_(me, pp, cyclep): + ind = _pp_bgroup_tyname(pp, me) + if cyclep: pp.text('...') + else: pp.text('%#x' % me.p) + pp.end_group(ind, ')') _augment(BinField, _tmp) class _tmp: @@ -231,6 +313,7 @@ _augment(BinNormField, _tmp) class _tmp: def __str__(me): return str(me.value) def __repr__(me): return '%s(%s)' % (repr(me.field), repr(me.value)) + _repr_pretty_ = _pp_str _augment(FE, _tmp) ###-------------------------------------------------------------------------- @@ -238,7 +321,16 @@ _augment(FE, _tmp) class _tmp: def __repr__(me): - return '%s(%r, %s, %s)' % (type(me).__name__, me.field, me.a, me.b) + return '%s(%r, %s, %s)' % (_clsname(me), me.field, me.a, me.b) + def _repr_pretty_(me, pp, cyclep): + ind = _pp_bgroup_tyname(pp, me) + if cyclep: + pp.text('...') + else: + pp.pretty(me.field); pp.text(','); pp.breakable() + pp.pretty(me.a); pp.text(','); pp.breakable() + pp.pretty(me.b) + pp.end_group(ind, ')') def frombuf(me, s): return ecpt.frombuf(me, s) def fromraw(me, s): @@ -267,17 +359,37 @@ _augment(ECBinCurve, _tmp) class _tmp: def __repr__(me): - if not me: return 'ECPt()' - return 'ECPt(%s, %s)' % (me.ix, me.iy) + if not me: return '%s()' % _clsname(me) + return '%s(%s, %s)' % (_clsname(me), me.ix, me.iy) def __str__(me): if not me: return 'inf' return '(%s, %s)' % (me.ix, me.iy) + def _repr_pretty_(me, pp, cyclep): + if cyclep: + pp.text('...') + elif not me: + pp.text('inf') + else: + ind = _pp_bgroup(pp, '(') + pp.pretty(me.ix); pp.text(','); pp.breakable() + pp.pretty(me.iy) + pp.end_group(ind, ')') _augment(ECPt, _tmp) class _tmp: def __repr__(me): - return 'ECInfo(curve = %r, G = %r, r = %s, h = %s)' % \ - (me.curve, me.G, me.r, me.h) + return '%s(curve = %r, G = %r, r = %s, h = %s)' % \ + (_clsname(me), me.curve, me.G, me.r, me.h) + def _repr_pretty_(me, pp, cyclep): + ind = _pp_bgroup_tyname(pp, me) + if cyclep: + pp.text('...') + else: + _pp_kv(pp, 'curve', me.curve); pp.text(','); pp.breakable() + _pp_kv(pp, 'G', me.G); pp.text(','); pp.breakable() + _pp_kv(pp, 'r', me.r); pp.text(','); pp.breakable() + _pp_kv(pp, 'h', me.h) + pp.end_group(ind, ')') def __hash__(me): h = 0x9bedb8de h ^= hash(me.curve) @@ -294,21 +406,41 @@ class _tmp: def __str__(me): if not me: return 'inf' return '(%s, %s)' % (me.x, me.y) + def _repr_pretty_(me, pp, cyclep): + if cyclep: + pp.text('...') + elif not me: + pp.text('inf') + else: + ind = _pp_bgroup(pp, '(') + pp.pretty(me.x); pp.text(','); pp.breakable() + pp.pretty(me.y) + pp.end_group(ind, ')') _augment(ECPtCurve, _tmp) ###-------------------------------------------------------------------------- ### Key sizes. class _tmp: - def __repr__(me): return 'KeySZAny(%d)' % me.default + def __repr__(me): return '%s(%d)' % (_clsname(me), me.default) def check(me, sz): return True def best(me, sz): return sz _augment(KeySZAny, _tmp) class _tmp: def __repr__(me): - return 'KeySZRange(%d, %d, %d, %d)' % \ - (me.default, me.min, me.max, me.mod) + return '%s(%d, %d, %d, %d)' % \ + (_clsname(me), me.default, me.min, me.max, me.mod) + def _repr_pretty_(me, pp, cyclep): + ind = _pp_bgroup_tyname(pp, me) + if cyclep: + pp.text('...') + else: + pp.pretty(me.default); pp.text(','); pp.breakable() + pp.pretty(me.min); pp.text(','); pp.breakable() + pp.pretty(me.max); pp.text(','); pp.breakable() + pp.pretty(me.mod) + pp.end_group(ind, ')') def check(me, sz): return me.min <= sz <= me.max and sz % me.mod == 0 def best(me, sz): if sz < me.min: raise ValueError, 'key too small' @@ -317,7 +449,17 @@ class _tmp: _augment(KeySZRange, _tmp) class _tmp: - def __repr__(me): return 'KeySZSet(%d, %s)' % (me.default, me.set) + def __repr__(me): return '%s(%d, %s)' % (_clsname(me), me.default, me.set) + def _repr_pretty_(me, pp, cyclep): + ind = _pp_bgroup_tyname(pp, me) + if cyclep: + pp.text('...') + else: + pp.pretty(me.default); pp.text(','); pp.breakable() + ind1 = _pp_bgroup(pp, '{') + _pp_commas(pp, pp.pretty, me.set) + pp.end_group(ind1, '}') + pp.end_group(ind, ')') def check(me, sz): return sz in me.set def best(me, sz): found = -1 @@ -327,13 +469,91 @@ class _tmp: return found _augment(KeySZSet, _tmp) +###-------------------------------------------------------------------------- +### Key data objects. + +class _tmp: + def __repr__(me): return '%s(%r)' % (_clsname(me), me.name) +_augment(KeyFile, _tmp) + +class _tmp: + def __repr__(me): return '%s(%r)' % (_clsname(me), me.fulltag) +_augment(Key, _tmp) + +class _tmp: + def __repr__(me): + return '%s({%s})' % (_clsname(me), + ', '.join(['%r: %r' % kv for kv in me.iteritems()])) + def _repr_pretty_(me, pp, cyclep): + ind = _pp_bgroup_tyname(pp, me) + if cyclep: pp.text('...') + else: _pp_dict(pp, me.iteritems()) + pp.end_group(ind, ')') +_augment(KeyAttributes, _tmp) + +class _tmp: + def __repr__(me): + return '%s(%s, %r)' % (_clsname(me), + _repr_secret(me._guts(), + not (me.flags & KF_NONSECRET)), + me.writeflags(me.flags)) + def _repr_pretty_(me, pp, cyclep): + ind = _pp_bgroup_tyname(pp, me) + if cyclep: + pp.text('...') + else: + _pp_secret(pp, me._guts(), not (me.flags & KF_NONSECRET)) + pp.text(','); pp.breakable() + pp.pretty(me.writeflags(me.flags)) + pp.end_group(ind, ')') +_augment(KeyData, _tmp) + +class _tmp: + def _guts(me): return me.bin +_augment(KeyDataBinary, _tmp) + +class _tmp: + def _guts(me): return me.ct +_augment(KeyDataEncrypted, _tmp) + +class _tmp: + def _guts(me): return me.mp +_augment(KeyDataMP, _tmp) + +class _tmp: + def _guts(me): return me.str +_augment(KeyDataString, _tmp) + +class _tmp: + def _guts(me): return me.ecpt +_augment(KeyDataECPt, _tmp) + +class _tmp: + def __repr__(me): + return '%s({%s})' % (_clsname(me), + ', '.join(['%r: %r' % kv for kv in me.iteritems()])) + def _repr_pretty_(me, pp, cyclep): + ind = _pp_bgroup_tyname(pp, me, '({ ') + if cyclep: pp.text('...') + else: _pp_dict(pp, me.iteritems()) + pp.end_group(ind, ' })') +_augment(KeyDataStructured, _tmp) + ###-------------------------------------------------------------------------- ### Abstract groups. class _tmp: def __repr__(me): - return '%s(p = %s, r = %s, g = %s)' % \ - (type(me).__name__, me.p, me.r, me.g) + return '%s(p = %s, r = %s, g = %s)' % (_clsname(me), me.p, me.r, me.g) + def _repr_pretty_(me, pp, cyclep): + ind = _pp_bgroup_tyname(pp, me) + if cyclep: + pp.text('...') + else: + _pp_kv(pp, 'p', me.p); pp.text(','); pp.breakable() + _pp_kv(pp, 'r', me.r); pp.text(','); pp.breakable() + _pp_kv(pp, 'g', me.g) + pp.end_group(ind, ')') _augment(FGInfo, _tmp) class _tmp: @@ -346,7 +566,12 @@ _augment(BinDHInfo, _tmp) class _tmp: def __repr__(me): - return '%s(%r)' % (type(me).__name__, me.info) + return '%s(%r)' % (_clsname(me), me.info) + def _repr_pretty_(me, pp, cyclep): + ind = _pp_bgroup_tyname(pp, me) + if cyclep: pp.text('...') + else: pp.pretty(me.info) + pp.end_group(ind, ')') _augment(Group, _tmp) class _tmp: @@ -357,6 +582,7 @@ class _tmp: h ^= 2*hash(info.r) & 0xffffffff h ^= 5*hash(info.g) & 0xffffffff return h + def _get_geval(me, x): return MP(x) _augment(PrimeGroup, _tmp) class _tmp: @@ -367,15 +593,19 @@ class _tmp: h ^= 2*hash(info.r) & 0xffffffff h ^= 5*hash(info.g) & 0xffffffff return h + def _get_geval(me, x): return GF(x) _augment(BinGroup, _tmp) class _tmp: def __hash__(me): return 0x0ec23dab ^ hash(me.info) + def _get_geval(me, x): return x.toec() _augment(ECGroup, _tmp) class _tmp: def __repr__(me): return '%r(%r)' % (me.group, str(me)) + def _repr_pretty_(me, pp, cyclep): + pp.pretty(type(me)._get_geval(me)) _augment(GE, _tmp) ###-------------------------------------------------------------------------- @@ -434,13 +664,158 @@ class _tmp: return x is None or x == msg except ValueError: return False + def __repr__(me): + return '%s(n = %r, e = %r)' % (_clsname(me), me.n, me.e) + def _repr_pretty_(me, pp, cyclep): + ind = _pp_bgroup_tyname(pp, me) + if cyclep: + pp.text('...') + else: + _pp_kv(pp, 'n', me.n); pp.text(','); pp.breakable() + _pp_kv(pp, 'e', me.e) + pp.end_group(ind, ')') _augment(RSAPub, _tmp) class _tmp: def decrypt(me, ct, enc): return enc.decode(me.privop(ct), me.n.nbits) def sign(me, msg, enc): return me.privop(enc.encode(msg, me.n.nbits)) + def __repr__(me): + return '%s(n = %r, e = %r, d = %s, ' \ + 'p = %s, q = %s, dp = %s, dq = %s, q_inv = %s)' % \ + (_clsname(me), me.n, me.e, + _repr_secret(me.d), _repr_secret(me.p), _repr_secret(me.q), + _repr_secret(me.dp), _repr_secret(me.dq), _repr_secret(me.q_inv)) + def _repr_pretty_(me, pp, cyclep): + ind = _pp_bgroup_tyname(pp, me) + if cyclep: + pp.text('...') + else: + _pp_kv(pp, 'n', me.n); pp.text(','); pp.breakable() + _pp_kv(pp, 'e', me.e); pp.text(','); pp.breakable() + _pp_kv(pp, 'd', me.d, secretp = True); pp.text(','); pp.breakable() + _pp_kv(pp, 'p', me.p, secretp = True); pp.text(','); pp.breakable() + _pp_kv(pp, 'q', me.q, secretp = True); pp.text(','); pp.breakable() + _pp_kv(pp, 'dp', me.dp, secretp = True); pp.text(','); pp.breakable() + _pp_kv(pp, 'dq', me.dq, secretp = True); pp.text(','); pp.breakable() + _pp_kv(pp, 'q_inv', me.q_inv, secretp = True) + pp.end_group(ind, ')') _augment(RSAPriv, _tmp) +###-------------------------------------------------------------------------- +### DSA and related schemes. + +class _tmp: + def __repr__(me): return '%s(G = %r, p = %r)' % (_clsname(me), me.G, me.p) + def _repr_pretty_(me, pp, cyclep): + ind = _pp_bgroup_tyname(pp, me) + if cyclep: + pp.text('...') + else: + _pp_kv(pp, 'G', me.G); pp.text(','); pp.breakable() + _pp_kv(pp, 'p', me.p) + pp.end_group(ind, ')') +_augment(DSAPub, _tmp) +_augment(KCDSAPub, _tmp) + +class _tmp: + def __repr__(me): return '%s(G = %r, u = %s, p = %r)' % \ + (_clsname(me), me.G, _repr_secret(me.u), me.p) + def _repr_pretty_(me, pp, cyclep): + ind = _pp_bgroup_tyname(pp, me) + if cyclep: + pp.text('...') + else: + _pp_kv(pp, 'G', me.G); pp.text(','); pp.breakable() + _pp_kv(pp, 'u', me.u, True); pp.text(','); pp.breakable() + _pp_kv(pp, 'p', me.p) + pp.end_group(ind, ')') +_augment(DSAPriv, _tmp) +_augment(KCDSAPriv, _tmp) + +###-------------------------------------------------------------------------- +### Bernstein's elliptic curve crypto and related schemes. + +X25519_BASE = \ + bytes('0900000000000000000000000000000000000000000000000000000000000000') + +X448_BASE = \ + bytes('05000000000000000000000000000000000000000000000000000000' + '00000000000000000000000000000000000000000000000000000000') + +Z128 = bytes('00000000000000000000000000000000') + +class _BoxyPub (object): + def __init__(me, pub, *kw, **kwargs): + if len(pub) != me._PUBSZ: raise ValueError, 'bad public key' + super(_BoxyPub, me).__init__(*kw, **kwargs) + me.pub = pub + def __repr__(me): return '%s(pub = %r)' % (_clsname(me), me.pub) + def _repr_pretty_(me, pp, cyclep): + ind = _pp_bgroup_tyname(pp, me) + if cyclep: + pp.text('...') + else: + _pp_kv(pp, 'pub', me.pub) + pp.end_group(ind, ')') + +class _BoxyPriv (_BoxyPub): + def __init__(me, priv, pub = None, *kw, **kwargs): + if len(priv) != me._KEYSZ: raise ValueError, 'bad private key' + if pub is None: pub = me._op(priv, me._BASE) + super(_BoxyPriv, me).__init__(pub = pub, *kw, **kwargs) + me.priv = priv + def agree(me, you): return me._op(me.priv, you.pub) + def boxkey(me, recip): + return me._hashkey(me.agree(recip)) + def box(me, recip, n, m): + return secret_box(me.boxkey(recip), n, m) + def unbox(me, recip, n, c): + return secret_unbox(me.boxkey(recip, n, c)) + def __repr__(me): return '%s(priv = %s, pub = %r)' % \ + (_clsname(me), _repr_secret(me.priv), me.pub) + def _repr_pretty_(me, pp, cyclep): + ind = _pp_bgroup_tyname(pp, me) + if cyclep: + pp.text('...') + else: + _pp_kv(pp, 'priv', me.priv, True); pp.text(','); pp.breakable() + _pp_kv(pp, 'pub', me.pub) + pp.end_group(ind, ')') + +class X25519Pub (_BoxyPub): + _PUBSZ = X25519_PUBSZ + _BASE = X25519_BASE + +class X25519Priv (_BoxyPriv, X25519Pub): + _KEYSZ = X25519_KEYSZ + def _op(me, k, X): return x25519(k, X) + def _hashkey(me, z): return hsalsa20_prf(z, Z128) + +class X448Pub (_BoxyPub): + _PUBSZ = X448_PUBSZ + _BASE = X448_BASE + +class X448Priv (_BoxyPriv, X448Pub): + _KEYSZ = X448_KEYSZ + def _op(me, k, X): return x448(k, X) + ##def _hashkey(me, z): return ??? + +class Ed25519Pub (object): + def __init__(me, pub): + me.pub = pub + def verify(me, msg, sig): + return ed25519_verify(me.pub, msg, sig) + +class Ed25519Priv (Ed25519Pub): + def __init__(me, priv): + me.priv = priv + Ed25519Pub.__init__(me, ed25519_pubkey(priv)) + def sign(me, msg): + return ed25519_sign(me.priv, msg, pub = me.pub) + @classmethod + def generate(cls, rng = rand): + return cls(rng.block(ED25519_KEYSZ)) + ###-------------------------------------------------------------------------- ### Built-in named curves and prime groups. @@ -448,9 +823,17 @@ class _groupmap (object): def __init__(me, map, nth): me.map = map me.nth = nth - me.i = [None] * (max(map.values()) + 1) + me._n = max(map.values()) + 1 + me.i = me._n*[None] def __repr__(me): - return '{%s}' % ', '.join(['%r: %r' % (k, me[k]) for k in me]) + return '{%s}' % ', '.join(['%r: %r' % kv for kv in me.iteritems()]) + def _repr_pretty_(me, pp, cyclep): + ind = _pp_bgroup(pp, '{ ') + if cyclep: pp.text('...') + else: _pp_dict(pp, me.iteritems()) + pp.end_group(ind, ' }') + def __len__(me): + return me._n def __contains__(me, k): return k in me.map def __getitem__(me, k): diff --git a/debian/control b/debian/control index 444feba..c9e5b41 100644 --- a/debian/control +++ b/debian/control @@ -5,7 +5,7 @@ XS-Python-Version: >= 2.6, << 2.8 Maintainer: Mark Wooding Build-Depends: debhelper (>= 9), pkg-config, python, python2.6-dev, python2.7-dev, - mlib-dev (>= 2.2.2.1), catacomb-dev (>= 2.2.5+14) + mlib-dev (>= 2.2.2.1), catacomb-dev (>= 2.3.0.1+3) Standards-Version: 3.8.0 Package: python-catacomb diff --git a/ec.c b/ec.c index 63d97d8..0489bc0 100644 --- a/ec.c +++ b/ec.c @@ -835,7 +835,7 @@ static PyObject *ecmeth_mmul(PyObject *me, PyObject *arg) static PyObject *meth__ECPtCurve_fromraw(PyObject *me, PyObject *arg) { char *p; - int len; + Py_ssize_t len; buf b; PyObject *rc = 0; ec_curve *cc; @@ -857,7 +857,7 @@ static PyObject *meth__ECPtCurve_os2ecp(PyObject *me, PyObject *arg, PyObject *kw) { char *p; - int len; + Py_ssize_t len; buf b; PyObject *rc = 0; ec_curve *cc; @@ -881,7 +881,7 @@ static PyObject *meth__ECPt_frombuf(PyObject *me, PyObject *arg) { buf b; char *p; - int sz; + Py_ssize_t sz; PyObject *rc = 0; ec pp = EC_INIT; diff --git a/group.c b/group.c index ba59a8a..cc8bbc1 100644 --- a/group.c +++ b/group.c @@ -184,7 +184,7 @@ static PyObject *meth__DHInfo_gendsa(PyObject *me, unsigned steps = 0; dsa_seed ds; char *k; - int ksz; + Py_ssize_t ksz; pgev evt = { 0 }; char *kwlist[] = { "class", "pbits", "qbits", "seed", "event", "nsteps", 0 }; @@ -449,12 +449,6 @@ static PyTypeObject bindhinfo_pytype_skel = { PyTypeObject *ge_pytype, *group_pytype; PyTypeObject *primegroup_pytype, *bingroup_pytype, *ecgroup_pytype; -#ifdef GROUP_GUTS_MPSTRUCT -# define GG_GEN(gg) ((gg)->gen.x) -#else -# define GG_GEN(gg) ((gg)->gen) -#endif - group *group_copy(group *g) { if (strcmp(G_NAME(g), "prime") == 0) { @@ -723,18 +717,34 @@ end: static PyObject *gemeth_toec(PyObject *me, PyObject *arg, PyObject *kw) { char *kwlist[] = { "curve", 0 }; - PyTypeObject *cty = ecpt_pytype; + PyTypeObject *cty = 0; + PyObject *rc = 0; + group *g; + ec_curve *c; ec p = EC_INIT; if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O:toec", kwlist, &cty)) goto end; - if (!PyType_Check(cty) || !PyType_IsSubtype(cty, ecpt_pytype)) - TYERR("want subtype of catacomb.ECPt"); - if (G_TOEC(GE_G(me), &p, GE_X(me))) + g = GROUP_G(GE_GOBJ(me)); + if (cty) { + if (!PyType_Check(cty) || !PyType_IsSubtype(cty, ecpt_pytype)) + TYERR("want subtype of catacomb.ECPt"); + Py_INCREF((PyObject *)cty); + } else if (strcmp(G_NAME(g), "ec") == 0) { + c = eccurve_copy(((gctx_ec *)g)->ei.c); + cty = (PyTypeObject *)eccurve_pywrap(0, c); + } else { + cty = ecpt_pytype; + Py_INCREF((PyObject *)cty); + } + if (G_TOEC(GE_G(me), &p, GE_X(me))) { + Py_DECREF((PyObject *)cty); TYERR("can't convert to ec point"); - return (ecpt_pywrapout(cty, &p)); + } + rc = ecpt_pywrapout(cty, &p); + Py_DECREF((PyObject *)cty); end: - return (0); + return (rc); } static PyObject *gemeth_tobuf(PyObject *me, PyObject *arg) @@ -821,7 +831,7 @@ static PyObject *meth__GE_frombuf(PyObject *me, PyObject *arg) { buf b; char *p; - int n; + Py_ssize_t n; group *g; ge *x = 0; @@ -842,7 +852,7 @@ static PyObject *meth__GE_fromraw(PyObject *me, PyObject *arg) { buf b; char *p; - int n; + Py_ssize_t n; group *g; ge *x = 0; @@ -863,7 +873,7 @@ static PyObject *meth__GE_fromstring(PyObject *me, PyObject *arg) { mptext_stringctx sc; char *p; - int n; + Py_ssize_t n; group *g; ge *x = 0; @@ -876,7 +886,7 @@ static PyObject *meth__GE_fromstring(PyObject *me, PyObject *arg) if (G_READ(g, x, &mptext_stringops, &sc)) VALERR("bad group element string"); return (Py_BuildValue("(Ns#)", ge_pywrap(me, x), - sc.buf, (int)(sc.lim - sc.buf))); + sc.buf, (Py_ssize_t)(sc.lim - sc.buf))); end: if (x) G_DESTROY(g, x); return (0); @@ -1128,7 +1138,7 @@ static PyObject *pgget_info(PyObject *me, void *hunoz) gctx_prime *gg = (gctx_prime *)GROUP_G(me); dp.p = MP_COPY(gg->mm.m); dp.q = MP_COPY(gg->g.r); - dp.g = mpmont_reduce(&gg->mm, MP_NEW, GG_GEN(gg)); + dp.g = mpmont_reduce(&gg->mm, MP_NEW, gg->gen.x); return (fginfo_pywrap(&dp, dhinfo_pytype)); } @@ -1205,7 +1215,7 @@ static PyObject *bgget_info(PyObject *me, void *hunoz) gctx_bin *gg = (gctx_bin *)GROUP_G(me); dp.p = MP_COPY(gg->r.p); dp.q = MP_COPY(gg->g.r); - dp.g = MP_COPY(GG_GEN(gg)); + dp.g = MP_COPY(gg->gen.x); return (fginfo_pywrap(&dp, bindhinfo_pytype)); } diff --git a/key.c b/key.c index a3cd200..8dec99c 100644 --- a/key.c +++ b/key.c @@ -414,7 +414,7 @@ end: static PyObject *kdmeth_lock(PyObject *me, PyObject *arg) { char *p; - int n; + Py_ssize_t n; PyObject *rc = 0; key_data *kd; @@ -445,7 +445,7 @@ end: static PyObject *meth__KeyData_decode(PyObject *me, PyObject *arg) { const char *p; - int n; + Py_ssize_t n; key_data *kd; PyObject *rc = 0; @@ -533,7 +533,7 @@ static PyObject *keydatabin_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) { char *p; - int n; + Py_ssize_t n; unsigned f = 0; keydata_pyobj *me = 0; static char *kwlist[] = { "key", "flags", 0 }; @@ -610,7 +610,7 @@ static PyObject *keydataenc_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) { char *p; - int n; + Py_ssize_t n; unsigned f = 0; keydata_pyobj *me = 0; static char *kwlist[] = { "key", "flags", 0 }; @@ -636,7 +636,7 @@ end: static PyObject *kdemeth_lock(PyObject *me, PyObject *arg) { char *hunoz; - int hukairz; + Py_ssize_t hukairz; if (!PyArg_ParseTuple(arg, "s#:lock", &hunoz, &hukairz)) goto end; KEYERR(KERR_WRONGTYPE); end: @@ -662,7 +662,7 @@ end: static PyObject *kdemeth_unlock(PyObject *me, PyObject *arg) { char *p; - int n; + Py_ssize_t n; int err; PyObject *rc = 0; key_data *kd; @@ -1969,7 +1969,7 @@ static PyObject *kfmeth_qtag(PyObject *me, PyObject *arg, PyObject *kw) } key_incref(*kd); rc = Py_BuildValue("(s#NN)", - d.buf, d.len, + d.buf, (Py_ssize_t)d.len, key_pywrap(me, k), keydata_pywrap(okd)); end: diff --git a/mp.c b/mp.c index f5f4320..79c6cf2 100644 --- a/mp.c +++ b/mp.c @@ -713,7 +713,7 @@ STOREOP(storeb2c, 2c) { \ buf b; \ char *p; \ - int sz; \ + Py_ssize_t sz; \ PyObject *rc = 0; \ mp *x; \ \ @@ -911,7 +911,7 @@ static PyObject *meth__MP_fromstring(PyObject *me, { int r = 0; char *p; - int len; + Py_ssize_t len; PyObject *z = 0; mp *zz; mptext_stringctx sc; @@ -924,7 +924,8 @@ static PyObject *meth__MP_fromstring(PyObject *me, sc.buf = p; sc.lim = p + len; if ((zz = mp_read(MP_NEW, r, &mptext_stringops, &sc)) == 0) VALERR("bad integer"); - z = Py_BuildValue("(Ns#)", mp_pywrap(zz), sc.buf, (int)(sc.lim - sc.buf)); + z = Py_BuildValue("(Ns#)", mp_pywrap(zz), + sc.buf, (Py_ssize_t)(sc.lim - sc.buf)); end: return (z); } @@ -952,7 +953,7 @@ static PyObject *meth__MP_fibonacci(PyObject *me, PyObject *arg) static PyObject *meth__##py##_##name(PyObject *me, PyObject *arg) \ { \ char *p; \ - int len; \ + Py_ssize_t len; \ if (!PyArg_ParseTuple(arg, "Os#:" #name, &me, &p, &len)) return (0); \ return (pre##_pywrap(mp_##name(MP_NEW, p, len))); \ } @@ -2111,7 +2112,7 @@ static PyObject *meth__GF_fromstring(PyObject *me, { int r = 0; char *p; - int len; + Py_ssize_t len; PyObject *z = 0; mp *zz; mptext_stringctx sc; @@ -2127,7 +2128,8 @@ static PyObject *meth__GF_fromstring(PyObject *me, if (zz) MP_DROP(zz); VALERR("bad binary polynomial"); } - z = Py_BuildValue("(Ns#)", gf_pywrap(zz), sc.buf, (int)(sc.lim - sc.buf)); + z = Py_BuildValue("(Ns#)", gf_pywrap(zz), + sc.buf, (Py_ssize_t)(sc.lim - sc.buf)); end: return (z); } diff --git a/pubkey.c b/pubkey.c index 4c4eb1d..4067ae0 100644 --- a/pubkey.c +++ b/pubkey.c @@ -54,26 +54,35 @@ static void dsa_pydealloc(PyObject *me) } static PyObject *dsa_setup(PyTypeObject *ty, PyObject *G, PyObject *u, - PyObject *p, PyObject *rng, PyObject *hash) + PyObject *p, PyObject *rng, PyObject *hash, + void (*calcpub)(group *, ge *, mp *)) { dsa_pyobj *g; + ge *pp; g = PyObject_New(dsa_pyobj, ty); - if (GROUP_G(G) != GE_G(p) && !group_samep(GROUP_G(G), GE_G(p))) - TYERR("public key not from group"); + if (p) Py_INCREF(p); if (!u) { g->d.u = 0; u = Py_None; } else if ((g->d.u = getmp(u)) == 0) goto end; + if (!p) { + assert(g->d.u); assert(calcpub); + pp = G_CREATE(GROUP_G(G)); + calcpub(GROUP_G(G), pp, g->d.u); + p = ge_pywrap(G, pp); + } else if (GROUP_G(G) != GE_G(p) && !group_samep(GROUP_G(G), GE_G(p))) + TYERR("public key not from group"); g->d.g = GROUP_G(G); g->d.p = GE_X(p); g->d.r = GRAND_R(rng); g->d.h = GCHASH_CH(hash); - g->G = G; Py_INCREF(G); g->u = u; Py_INCREF(u); g->p = p; Py_INCREF(p); + g->G = G; Py_INCREF(G); g->u = u; Py_INCREF(u); g->p = p; g->rng = rng; Py_INCREF(rng); g->hash = hash; Py_INCREF(hash); return ((PyObject *)g); end: + if (p) Py_DECREF(p); FREEOBJ(g); return (0); } @@ -81,17 +90,16 @@ end: static PyObject *dsapub_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) { - PyObject *G, *p, *u = 0, *rng = rand_pyobj, *hash = sha_pyobj; + PyObject *G, *p, *rng = rand_pyobj, *hash = sha_pyobj; PyObject *rc = 0; - char *kwlist[] = { "G", "p", "u", "hash", "rng", 0 }; + char *kwlist[] = { "G", "p", "hash", "rng", 0 }; - if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!|OO!O!:new", kwlist, + if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!|O!O!:new", kwlist, group_pytype, &G, ge_pytype, &p, - &u, gchash_pytype, &hash, grand_pytype, &rng) || - (rc = dsa_setup(dsapub_pytype, G, u, p, rng, hash)) == 0) + (rc = dsa_setup(dsapub_pytype, G, 0, p, rng, hash, 0)) == 0) goto end; end: return (rc); @@ -120,7 +128,7 @@ static PyObject *dsameth_sign(PyObject *me, PyObject *arg, PyObject *kw) { gdsa_sig s = GDSA_SIG_INIT; char *p; - int n; + Py_ssize_t n; mp *k = 0; PyObject *rc = 0; char *kwlist[] = { "msg", "k", 0 }; @@ -140,7 +148,7 @@ end: static PyObject *dsameth_verify(PyObject *me, PyObject *arg) { char *p; - int n; + Py_ssize_t n; gdsa_sig s = GDSA_SIG_INIT; PyObject *rc = 0; @@ -156,20 +164,22 @@ end: return (rc); } +static void dsa_calcpub(group *g, ge *p, mp *u) { G_EXP(g, p, g->g, u); } + static PyObject *dsapriv_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) { - PyObject *G, *p, *u = Py_None, *rng = rand_pyobj, *hash = sha_pyobj; + PyObject *G, *p = 0, *u, *rng = rand_pyobj, *hash = sha_pyobj; PyObject *rc = 0; - char *kwlist[] = { "G", "p", "u", "hash", "rng", 0 }; + char *kwlist[] = { "G", "u", "p", "hash", "rng", 0 }; - if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!O|O!O!:new", kwlist, + if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O|O!O!O!:new", kwlist, group_pytype, &G, - ge_pytype, &p, &u, + ge_pytype, &p, gchash_pytype, &hash, grand_pytype, &rng) || - (rc = dsa_setup(dsapriv_pytype, G, u, p, rng, hash)) == 0) + (rc = dsa_setup(dsapriv_pytype, G, u, p, rng, hash, dsa_calcpub)) == 0) goto end; end: return (rc); @@ -307,36 +317,43 @@ static PyTypeObject dsapriv_pytype_skel = { static PyObject *kcdsapub_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) { - PyObject *G, *p, *u = 0, *rng = rand_pyobj, *hash = has160_pyobj; + PyObject *G, *p, *rng = rand_pyobj, *hash = has160_pyobj; PyObject *rc = 0; - char *kwlist[] = { "G", "p", "u", "hash", "rng", 0 }; + char *kwlist[] = { "G", "p", "hash", "rng", 0 }; - if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!O|O!O!:new", kwlist, + if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!|O!O!:new", kwlist, group_pytype, &G, ge_pytype, &p, - &u, gchash_pytype, &hash, grand_pytype, &rng) || - (rc = dsa_setup(kcdsapub_pytype, G, u, p, rng, hash)) == 0) + (rc = dsa_setup(kcdsapub_pytype, G, 0, p, rng, hash, 0)) == 0) goto end; end: return (rc); } +static void kcdsa_calcpub(group *g, ge *p, mp *u) +{ + mp *uinv = mp_modinv(MP_NEW, u, g->r); + G_EXP(g, p, g->g, uinv); + mp_drop(uinv); +} + static PyObject *kcdsapriv_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) { - PyObject *G, *p, *u = Py_None, *rng = rand_pyobj, *hash = has160_pyobj; + PyObject *G, *u, *p = 0, *rng = rand_pyobj, *hash = has160_pyobj; PyObject *rc = 0; char *kwlist[] = { "G", "p", "u", "hash", "rng", 0 }; - if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O!|OO!O!:new", kwlist, + if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O|O!O!O!:new", kwlist, group_pytype, &G, - ge_pytype, &p, &u, + ge_pytype, &p, gchash_pytype, &hash, grand_pytype, &rng) || - (rc = dsa_setup(kcdsapriv_pytype, G, u, p, rng, hash)) == 0) + (rc = dsa_setup(kcdsapriv_pytype, G, u, p, + rng, hash, kcdsa_calcpub)) == 0) goto end; end: return (rc); @@ -365,7 +382,7 @@ static PyObject *kcdsameth_sign(PyObject *me, PyObject *arg, PyObject *kw) { gkcdsa_sig s = GKCDSA_SIG_INIT; char *p; - int n; + Py_ssize_t n; mp *k = 0; PyObject *r = 0, *rc = 0; char *kwlist[] = { "msg", "k", 0 }; @@ -388,7 +405,7 @@ end: static PyObject *kcdsameth_verify(PyObject *me, PyObject *arg) { char *p; - int n, rn; + Py_ssize_t n, rn; gkcdsa_sig s = GKCDSA_SIG_INIT; PyObject *rc = 0; @@ -865,7 +882,7 @@ static PyObject *meth__p1crypt_encode(PyObject *me, { pkcs1 p1; char *m, *ep; - int msz, epsz; + Py_ssize_t msz, epsz; unsigned long nbits; PyObject *rc = 0; octet *b = 0; @@ -894,7 +911,7 @@ static PyObject *meth__p1crypt_decode(PyObject *me, { pkcs1 p1; char *ep; - int epsz; + Py_ssize_t epsz; unsigned long nbits; int n; PyObject *rc = 0; @@ -926,7 +943,7 @@ static PyObject *meth__p1sig_encode(PyObject *me, { pkcs1 p1; char *m, *ep; - int msz, epsz; + Py_ssize_t msz, epsz; unsigned long nbits; PyObject *rc = 0; octet *b = 0; @@ -955,7 +972,7 @@ static PyObject *meth__p1sig_decode(PyObject *me, { pkcs1 p1; char *ep; - int epsz; + Py_ssize_t epsz; unsigned long nbits; int n; PyObject *hukairz; @@ -988,7 +1005,7 @@ static PyObject *meth__oaep_encode(PyObject *me, { oaep o; char *m, *ep; - int msz, epsz; + Py_ssize_t msz, epsz; unsigned long nbits; PyObject *rc = 0; octet *b = 0; @@ -1020,7 +1037,7 @@ static PyObject *meth__oaep_decode(PyObject *me, { oaep o; char *ep; - int epsz; + Py_ssize_t epsz; unsigned long nbits; int n; PyObject *rc = 0; @@ -1055,7 +1072,7 @@ static PyObject *meth__pss_encode(PyObject *me, { pss p; char *m; - int msz; + Py_ssize_t msz; unsigned long nbits; PyObject *rc = 0; octet *b = 0; @@ -1087,7 +1104,7 @@ static PyObject *meth__pss_decode(PyObject *me, { pss p; char *m; - int msz; + Py_ssize_t msz; unsigned long nbits; PyObject *rc = 0; octet *b = 0; @@ -1118,6 +1135,91 @@ end: return (rc); } +/*----- X25519 and related algorithms -------------------------------------*/ + +static PyObject *meth_x25519(PyObject *me, PyObject *arg) +{ + const char *k, *p; + Py_ssize_t ksz, psz; + PyObject *rc = 0; + if (!PyArg_ParseTuple(arg, "s#s#:x25519", &k, &ksz, &p, &psz)) goto end; + if (ksz != X25519_KEYSZ) VALERR("bad key length"); + if (psz != X25519_PUBSZ) VALERR("bad public length"); + rc = bytestring_pywrap(0, X25519_OUTSZ); + x25519((octet *)PyString_AS_STRING(rc), + (const octet *)k, (const octet *)p); + return (rc); +end: + return (0); +} + +static PyObject *meth_x448(PyObject *me, PyObject *arg) +{ + const char *k, *p; + Py_ssize_t ksz, psz; + PyObject *rc = 0; + if (!PyArg_ParseTuple(arg, "s#s#:x448", &k, &ksz, &p, &psz)) goto end; + if (ksz != X448_KEYSZ) VALERR("bad key length"); + if (psz != X448_PUBSZ) VALERR("bad public length"); + rc = bytestring_pywrap(0, X448_OUTSZ); + x448((octet *)PyString_AS_STRING(rc), + (const octet *)k, (const octet *)p); + return (rc); +end: + return (0); +} + +/*----- Ed25519 -----------------------------------------------------------*/ + +static PyObject *meth_ed25519_pubkey(PyObject *me, PyObject *arg) +{ + const char *k; + Py_ssize_t ksz; + PyObject *rc = 0; + if (!PyArg_ParseTuple(arg, "s#:ed25519_pubkey", &k, &ksz)) goto end; + rc = bytestring_pywrap(0, ED25519_PUBSZ); + ed25519_pubkey((octet *)PyString_AS_STRING(rc), k, ksz); + return (rc); +end: + return (0); +} + +static PyObject *meth_ed25519_sign(PyObject *me, PyObject *arg, PyObject *kw) +{ + const char *k, *p = 0, *m; + Py_ssize_t ksz, psz, msz; + PyObject *rc = 0; + octet pp[ED25519_PUBSZ]; + char *kwlist[] = { "key", "msg", "pub", 0 }; + if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#s#|s#:ed25519_sign", kwlist, + &k, &ksz, &m, &msz, &p, &psz)) + goto end; + if (p && psz != ED25519_PUBSZ) VALERR("bad public length"); + if (!p) { p = (const char *)pp; ed25519_pubkey(pp, k, ksz); } + rc = bytestring_pywrap(0, ED25519_SIGSZ); + ed25519_sign((octet *)PyString_AS_STRING(rc), k, ksz, + (const octet *)p, m, msz); + return (rc); +end: + return (0); +} + +static PyObject *meth_ed25519_verify(PyObject *me, PyObject *arg) +{ + const char *p, *m, *s; + Py_ssize_t psz, msz, ssz; + PyObject *rc = 0; + if (!PyArg_ParseTuple(arg, "s#s#s#:ed25519_verify", + &p, &psz, &m, &msz, &s, &ssz)) + goto end; + if (psz != ED25519_PUBSZ) VALERR("bad public length"); + if (ssz != ED25519_SIGSZ) VALERR("bad signature length"); + rc = getbool(!ed25519_verify((const octet *)p, m, msz, (const octet *)s)); + return (rc); +end: + return (0); +} + /*----- Global stuff ------------------------------------------------------*/ static PyMethodDef methods[] = { @@ -1132,6 +1234,16 @@ static PyMethodDef methods[] = { KWMETH(_pss_decode, 0) KWMETH(_RSAPriv_generate, "\ generate(NBITS, [event = pgen_nullev, rng = rand, nsteps = 0]) -> R") + METH (x25519, "\ +x25519(KEY, PUBLIC) -> SHARED") + METH (x448, "\ +x448(KEY, PUBLIC) -> SHARED") + METH (ed25519_pubkey, "\ +ed25519_pubkey(KEY) -> PUBLIC") + KWMETH(ed25519_sign, "\ +ed25519_sign(KEY, MSG, [PUBLIC]) -> SIG") + METH (ed25519_verify, "\ +ed25519_verify(PUBLIC, MSG, SIG) -> BOOL") #undef METHNAME { 0 } }; diff --git a/rand.c b/rand.c index 4fcb155..f163efa 100644 --- a/rand.c +++ b/rand.c @@ -173,7 +173,7 @@ end: static PyObject *grmeth_seedblock(PyObject *me, PyObject *arg) { char *p; - int n; + Py_ssize_t n; grand *r = GRAND_R(me); if (!PyArg_ParseTuple(arg, "s#:seedblock", &p, &n) || checkop(r, GRAND_SEEDBLOCK, "seedblock")) @@ -219,7 +219,7 @@ static PyObject *grmeth_mask(PyObject *me, PyObject *arg) { grand *r = GRAND_R(me); char *p, *q; - int sz; + Py_ssize_t sz; PyObject *rc; if (!PyArg_ParseTuple(arg, "s#:mask", &p, &sz)) return (0); @@ -452,7 +452,7 @@ static PyObject *trmeth_stretch(PyObject *me, PyObject *arg) static PyObject *trmeth_add(PyObject *me, PyObject *arg) { grand *r = GRAND_R(me); - char *p; int n; unsigned goodbits; + char *p; Py_ssize_t n; unsigned goodbits; if (!PyArg_ParseTuple(arg, "s#O&:add", &p, &n, convuint, &goodbits)) return (0); r->ops->misc(r, RAND_ADD, p, (size_t)n, goodbits); @@ -462,7 +462,7 @@ static PyObject *trmeth_add(PyObject *me, PyObject *arg) static PyObject *trmeth_key(PyObject *me, PyObject *arg) { grand *r = GRAND_R(me); - char *p; int n; + char *p; Py_ssize_t n; if (!PyArg_ParseTuple(arg, "s#:key", &p, &n)) return (0); r->ops->misc(r, RAND_KEY, p, (size_t)n); RETURN_ME; @@ -578,7 +578,7 @@ static PyTypeObject truerand_pytype_skel = { /*----- Generators from symmetric encryption algorithms -------------------*/ -static PyTypeObject *gccrand_pytype, *gcrand_pytype; +static PyTypeObject *gccrand_pytype, *gcrand_pytype, *gclatinrand_pytype; typedef grand *gcrand_func(const void *, size_t sz); typedef grand *gcirand_func(const void *, size_t sz, uint32); @@ -593,6 +593,7 @@ typedef struct gccrand_info { #define RNGF_INT 1u #define RNGF_NONCE 2u +#define RNGF_LATIN 4u typedef struct gccrand_pyobj { PyHeapTypeObject ty; @@ -616,7 +617,7 @@ static PyObject *gcrand_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) const gccrand_info *info = GCCRAND_INFO(ty); static char *kwlist[] = { "key", 0 }; char *k; - int n; + Py_ssize_t n; if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#:new", kwlist, &k, &n)) goto end; @@ -632,7 +633,7 @@ static PyObject *gcirand_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) uint32 i = 0; static char *kwlist[] = { "key", "i", 0 }; char *k; - int n; + Py_ssize_t n; if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#O&:new", kwlist, &k, &n, convu32, &i)) @@ -650,7 +651,7 @@ static PyObject *gcnrand_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) const gccrand_info *info = GCCRAND_INFO(ty); static char *kwlist[] = { "key", "nonce", 0 }; char *k, *n; - int ksz, nsz; + Py_ssize_t ksz, nsz; if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#s#:new", kwlist, &k, &ksz, &n, &nsz)) @@ -669,8 +670,9 @@ static PyObject *gccrand_pywrap(const gccrand_info *info) gccrand_pyobj *g = newtype(gccrand_pytype, 0, info->name); g->info = info; g->ty.ht_type.tp_basicsize = sizeof(grand_pyobj); - g->ty.ht_type.tp_base = gcrand_pytype; - Py_INCREF(gcrand_pytype); + g->ty.ht_type.tp_base = + (info->f & RNGF_LATIN) ? gclatinrand_pytype : gcrand_pytype; + Py_INCREF(g->ty.ht_type.tp_base); g->ty.ht_type.tp_flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HEAPTYPE); @@ -688,6 +690,28 @@ static PyObject *gccrget_name(PyObject *me, void *hunoz) static PyObject *gccrget_keysz(PyObject *me, void *hunoz) { return (keysz_pywrap(GCCRAND_INFO(me)->keysz)); } +static PyObject *gclrmeth_tell(PyObject *me, PyObject *arg) +{ + grand *r = GRAND_R(me); + PyObject *rc = 0; + kludge64 off; + + if (!PyArg_ParseTuple(arg, ":tell")) return (0); + r->ops->misc(r, SALSA20_TELLU64, &off); + rc = getk64(off); + return (rc); +} + +static PyObject *gclrmeth_seek(PyObject *me, PyObject *arg) +{ + grand *r = GRAND_R(me); + kludge64 off; + + if (!PyArg_ParseTuple(arg, "O&:seek", convk64, &off)) return (0); + r->ops->misc(r, SALSA20_SEEKU64, off); + RETURN_ME; +} + static PyGetSetDef gccrand_pygetset[] = { #define GETSETNAME(op, name) gccr##op##_##name GET (keysz, "CR.keysz -> acceptable key sizes") @@ -696,6 +720,14 @@ static PyGetSetDef gccrand_pygetset[] = { { 0 } }; +static PyMethodDef gclatinrand_pymethods[] = { +#define METHNAME(name) gclrmeth_##name + METH (tell, "R.tell() -> OFF") + METH (seek, "R.seek(OFF)") +#undef METHNAME + { 0 } +}; + static PyTypeObject gccrand_pytype_skel = { PyObject_HEAD_INIT(0) 0, /* Header */ "GCCRand", /* @tp_name@ */ @@ -792,6 +824,54 @@ static PyTypeObject gcrand_pytype_skel = { 0 /* @tp_is_gc@ */ }; +static PyTypeObject gclatinrand_pytype_skel = { + PyObject_HEAD_INIT(0) 0, /* Header */ + "GCLatinRand", /* @tp_name@ */ + sizeof(grand_pyobj), /* @tp_basicsize@ */ + 0, /* @tp_itemsize@ */ + + grand_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@ */ +"Abstract base class for symmetric crypto-based generators.", + + 0, /* @tp_traverse@ */ + 0, /* @tp_clear@ */ + 0, /* @tp_richcompare@ */ + 0, /* @tp_weaklistoffset@ */ + 0, /* @tp_iter@ */ + 0, /* @tp_iternext@ */ + gclatinrand_pymethods, /* @tp_methods@ */ + 0, /* @tp_members@ */ + 0, /* @tp_getset@ */ + 0, /* @tp_base@ */ + 0, /* @tp_dict@ */ + 0, /* @tp_descr_get@ */ + 0, /* @tp_descr_set@ */ + 0, /* @tp_dictoffset@ */ + 0, /* @tp_init@ */ + PyType_GenericAlloc, /* @tp_alloc@ */ + abstract_pynew, /* @tp_new@ */ + 0, /* @tp_free@ */ + 0 /* @tp_is_gc@ */ +}; + /*----- SSL and TLS generators --------------------------------------------*/ static PyObject *sslprf_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) @@ -1382,6 +1462,7 @@ void rand_pyinit(void) INITTYPE(tlsprf, grand); INITTYPE(gccrand, type); INITTYPE(gcrand, grand); + INITTYPE(gclatinrand, gcrand); rand_noisesrc(RAND_GLOBAL, &noise_source); rand_seed(RAND_GLOBAL, 160); addmethods(methods); @@ -1404,6 +1485,7 @@ void rand_pyinsert(PyObject *mod) INSERT("BBSPriv", bbspriv_pytype); INSERT("GCCRand", gccrand_pytype); INSERT("GCRand", gcrand_pytype); + INSERT("GCLatinRand", gclatinrand_pytype); rand_pyobj = grand_pywrap(&rand_global, 0); Py_INCREF(rand_pyobj); gccrands_dict = gccrands(); Py_INCREF(gccrands_dict); INSERT("gccrands", gccrands_dict); diff --git a/setup.py b/setup.py index 161e2af..fe0ed53 100755 --- a/setup.py +++ b/setup.py @@ -3,7 +3,7 @@ import distutils.core as DC import mdwsetup as MS -MS.pkg_config('catacomb', '2.2.0') +MS.pkg_config('catacomb', '2.3.0.1+4') MS.pkg_config('mLib', '2.0.4') cat = DC.Extension('catacomb._base', diff --git a/share.c b/share.c index ad56d31..2caa718 100644 --- a/share.c +++ b/share.c @@ -113,7 +113,7 @@ static PyObject *gfsharesplit_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw) { char *p; - int n; + Py_ssize_t n; unsigned t; grand *r = &rand_global; gfshare_pyobj *s; @@ -228,7 +228,7 @@ static PyObject *gfsmeth_add(PyObject *me, PyObject *arg) { unsigned i; char *p; - int n; + Py_ssize_t 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"); diff --git a/util.c b/util.c index 8fab0bf..d4b7fb0 100644 --- a/util.c +++ b/util.c @@ -42,6 +42,29 @@ PyObject *getulong(unsigned long w) return (PyLong_FromUnsignedLong(w)); } +static PyObject *i32 = 0; +static int init_i32(void) + { if (!i32 && (i32 = PyInt_FromLong(32)) == 0) return (-1); return (0); } + +PyObject *getk64(kludge64 u) +{ + PyObject *i = 0, *j = 0, *t; + PyObject *rc = 0; + + if (init_i32()) goto end; + if ((i = PyLong_FromUnsignedLong(HI64(u))) == 0) goto end; + if ((t = PyNumber_InPlaceLshift(i, i32)) == 0) goto end; + Py_DECREF(i); i = t; + if ((j = PyLong_FromUnsignedLong(LO64(u))) == 0) goto end; + if ((t = PyNumber_InPlaceOr(i, j)) == 0) goto end; + Py_DECREF(i); i = t; + if ((rc = PyNumber_Int(i)) == 0) goto end; +end: + if (i) Py_DECREF(i); + if (j) Py_DECREF(j); + return (rc); +} + PyObject *getbool(int b) { if (b) RETURN_TRUE; @@ -104,6 +127,28 @@ end: return (0); } +int convk64(PyObject *o, void *pp) +{ + PyObject *i = 0, *t; + int rc = 0; + uint32 lo, hi; + + if (init_i32()) goto end; + if ((i = PyNumber_Int(o)) == 0) goto end; + lo = PyInt_AsUnsignedLongMask(i); + if ((t = PyNumber_InPlaceRshift(i, i32)) == 0) goto end; + Py_DECREF(i); i = t; + hi = PyInt_AsUnsignedLongMask(i); + if ((t = PyNumber_InPlaceRshift(i, i32)) == 0) goto end; + Py_DECREF(i); i = t; + if (PyObject_IsTrue(i)) VALERR("out of range"); + SET64(*(kludge64 *)pp, hi, lo); + rc = 1; +end: + if (i) Py_DECREF(i); + return (rc); +} + int convmpw(PyObject *o, void *pp) { unsigned long u; @@ -182,9 +227,9 @@ void typeready(PyTypeObject *ty) PyDict_SetItemString(ty->tp_dict, "__module__", modname); } -PyTypeObject *inittype(PyTypeObject *tyskel) +PyTypeObject *inittype(PyTypeObject *tyskel, PyTypeObject *meta) { - PyTypeObject *ty = newtype(&PyType_Type, tyskel, 0); + PyTypeObject *ty = newtype(meta, tyskel, 0); ty->tp_flags |= Py_TPFLAGS_HEAPTYPE; typeready(ty); return (ty); @@ -230,8 +275,8 @@ PyMethodDef *donemethods(void) /*----- Exceptions --------------------------------------------------------*/ -PyObject * mkexc(PyObject *mod, PyObject *base, - const char *name, PyMethodDef *mm) +PyObject *mkexc(PyObject *mod, PyObject *base, + const char *name, PyMethodDef *mm) { PyObject *nameobj = 0; PyObject *dict = 0;