#include "Python.h"
+#include "kalyna.h"
+
/*----- Utilities ---------------------------------------------------------*/
+#define EXCERR(exc, str) do { \
+ PyErr_SetString(exc, str); \
+ goto end; \
+} while (0)
+#define VALERR(str) EXCERR(PyExc_ValueError, str)
+
#define INSERT(name, ob) do { \
PyObject *_o = (PyObject *)(ob); \
Py_INCREF(_o); \
PyModule_AddObject(mod, name, _o); \
} while (0)
+#define FREEOBJ(obj) \
+ (((PyObject *)(obj))->ob_type->tp_free((PyObject *)(obj)))
+
+int convulong(PyObject *o, void *pp)
+{
+ long i;
+ unsigned long *p = pp;
+ PyObject *t;
+
+ if (!o) VALERR("can't delete");
+ if (PyInt_Check(o)) {
+ i = PyInt_AS_LONG(o);
+ if (i < 0) VALERR("must be nonnegative");
+ *p = i;
+ } else {
+ if ((t = PyNumber_Long(o)) == 0) goto end;
+ *p = PyLong_AsUnsignedLong(t);
+ Py_DECREF(t);
+ if (PyErr_Occurred()) goto end;
+ }
+ return (1);
+end:
+ return (0);
+}
+
+static int convszt(PyObject *o, void *pp)
+{
+ unsigned long u;
+ size_t *p = pp;
+
+ if (!convulong(o, &u)) goto end;
+ if (u > ~(size_t)0) VALERR("out of range");
+ *p = u;
+ return (1);
+end:
+ return (0);
+}
+
+static inline void store64(void *p, uint64_t x)
+{
+ unsigned char *pp = p;
+
+ pp[0] = (x >> 0)&0xff; pp[1] = (x >> 8)&0xff;
+ pp[2] = (x >> 16)&0xff; pp[3] = (x >> 24)&0xff;
+ pp[4] = (x >> 32)&0xff; pp[5] = (x >> 40)&0xff;
+ pp[6] = (x >> 48)&0xff; pp[7] = (x >> 56)&0xff;
+}
+
+static inline uint64_t load64(const void *p)
+{
+ const unsigned char *pp = p;
+
+ return ((((uint64_t )pp[0]&0xff) << 0) | (((uint64_t )pp[1]&0xff) << 8) |
+ (((uint64_t )pp[2]&0xff) << 16) | (((uint64_t )pp[3]&0xff) << 24) |
+ (((uint64_t )pp[4]&0xff) << 32) | (((uint64_t )pp[5]&0xff) << 40) |
+ (((uint64_t )pp[6]&0xff) << 48) | (((uint64_t )pp[7]&0xff) << 56));
+}
+
+/*----- The Kalyna block cipher -------------------------------------------*/
+
+static PyTypeObject kalyna_pytype;
+
+typedef struct kalyna_pyobj {
+ PyObject_HEAD
+ kalyna_t *k;
+} kalyna_pyobj;
+
+static PyObject *kalyna_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
+{
+ char *kwlist[] = { "key", "blksz", 0 };
+ size_t blksz;
+ char *k;
+ Py_ssize_t ksz;
+ kalyna_t *kk;
+ kalyna_pyobj *rc = 0;
+ size_t i;
+ uint64_t k64[8];
+
+ if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#O&:new", kwlist,
+ &k, &ksz, convszt, &blksz))
+ goto end;
+ switch (blksz) {
+ case 16: case 32: case 64: break;
+ default: VALERR("bad block size");
+ }
+ if ((ksz != blksz && ksz != 2*blksz) || ksz > 64)
+ VALERR("bad key length");
+
+ kk = KalynaInit(8*blksz, 8*ksz); if (!kk) VALERR("unknown error");
+ for (i = 0; i < kk->nk; i++) k64[i] = load64(k + 8*i);
+ KalynaKeyExpand(k64, kk);
+ rc = PyObject_NEW(kalyna_pyobj, ty);
+ rc->k = kk;
+end:
+ return ((PyObject *)rc);
+}
+
+static void kalyna_pydealloc(PyObject *me)
+{
+ kalyna_pyobj *kobj = (kalyna_pyobj *)me;
+ KalynaDelete(kobj->k);
+ FREEOBJ(kobj);
+}
+
+static PyObject *kalynameth_encrypt(PyObject *me, PyObject *arg)
+{
+ char *p, *q;
+ Py_ssize_t psz;
+ PyObject *rc = 0;
+ kalyna_pyobj *kobj = (kalyna_pyobj *)me;
+ size_t i;
+ uint64_t p64[8];
+
+ if (!PyArg_ParseTuple(arg, "s#:encrypt", &p, &psz)) goto end;
+ if (psz != 8*kobj->k->nb) VALERR("incorrect block size");
+ rc = PyString_FromStringAndSize(0, psz); q = PyString_AS_STRING(rc);
+ for (i = 0; i < kobj->k->nb; i++) p64[i] = load64(p + 8*i);
+ KalynaEncipher(p64, kobj->k, p64);
+ for (i = 0; i < kobj->k->nb; i++) store64(q + 8*i, p64[i]);
+end:
+ return (rc);
+}
+
+static PyObject *kalynameth_decrypt(PyObject *me, PyObject *arg)
+{
+ char *p, *q;
+ Py_ssize_t psz;
+ PyObject *rc = 0;
+ kalyna_pyobj *kobj = (kalyna_pyobj *)me;
+ size_t i;
+ uint64_t p64[8];
+
+ if (!PyArg_ParseTuple(arg, "s#:encrypt", &p, &psz)) goto end;
+ if (psz != 8*kobj->k->nb) VALERR("incorrect block size");
+ rc = PyString_FromStringAndSize(0, psz); q = PyString_AS_STRING(rc);
+ for (i = 0; i < kobj->k->nb; i++) p64[i] = load64(p + 8*i);
+ KalynaDecipher(p64, kobj->k, p64);
+ for (i = 0; i < kobj->k->nb; i++) store64(q + 8*i, p64[i]);
+end:
+ return (rc);
+}
+
+static PyMethodDef kalyna_pymethods[] = {
+ { "encrypt", kalynameth_encrypt, METH_VARARGS,
+ "encrypt(PTBLK) -> CTBLK" },
+ { "decrypt", kalynameth_decrypt, METH_VARARGS,
+ "decrypt(CTBLK) -> PTBLK" },
+ { 0 }
+};
+
+static PyTypeObject kalyna_pytype = {
+ PyObject_HEAD_INIT(0) 0, /* Header */
+ "Kalyna", /* @tp_name@ */
+ sizeof(kalyna_pyobj), /* @tp_basicsize@ */
+ 0, /* @tp_itemsize@ */
+
+ kalyna_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@ */
+"Kalyna block cipher instance.",
+
+ 0, /* @tp_traverse@ */
+ 0, /* @tp_clear@ */
+ 0, /* @tp_richcompare@ */
+ 0, /* @tp_weaklistoffset@ */
+ 0, /* @tp_iter@ */
+ 0, /* @tp_iternext@ */
+ kalyna_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@ */
+ kalyna_pynew, /* @tp_new@ */
+ 0, /* @tp_free@ */
+ 0 /* @tp_is_gc@ */
+};
+
/*----- Main code ---------------------------------------------------------*/
void initkalyna(void)
{
PyObject *mod = Py_InitModule("kalyna", 0);
+ if (PyType_Ready(&kalyna_pytype) < 0) return;
INSERT("version", PyString_FromString(VERSION));
+ INSERT("Kalyna", &kalyna_pytype);
}
/*----- That's all, folks -------------------------------------------------*/