3 * Python binding to Kalyna reference implementation
5 * (c) 2017 Mark Wooding
8 /*----- Licensing notice --------------------------------------------------*
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 /*----- Header files ------------------------------------------------------*/
27 #define PY_SSIZE_T_CLEAN
33 /*----- Utilities ---------------------------------------------------------*/
35 #define EXCERR(exc, str) do { \
36 PyErr_SetString(exc, str); \
39 #define VALERR(str) EXCERR(PyExc_ValueError, str)
41 #define INSERT(name, ob) do { \
42 PyObject *_o = (PyObject *)(ob); \
44 PyModule_AddObject(mod, name, _o); \
47 #define FREEOBJ(obj) \
48 (((PyObject *)(obj))->ob_type->tp_free((PyObject *)(obj)))
50 int convulong(PyObject *o, void *pp)
53 unsigned long *p = pp;
56 if (!o) VALERR("can't delete");
59 if (i < 0) VALERR("must be nonnegative");
62 if ((t = PyNumber_Long(o)) == 0) goto end;
63 *p = PyLong_AsUnsignedLong(t);
65 if (PyErr_Occurred()) goto end;
72 static int convszt(PyObject *o, void *pp)
77 if (!convulong(o, &u)) goto end;
78 if (u > ~(size_t)0) VALERR("out of range");
85 static inline void store64(void *p, uint64_t x)
87 unsigned char *pp = p;
89 pp[0] = (x >> 0)&0xff; pp[1] = (x >> 8)&0xff;
90 pp[2] = (x >> 16)&0xff; pp[3] = (x >> 24)&0xff;
91 pp[4] = (x >> 32)&0xff; pp[5] = (x >> 40)&0xff;
92 pp[6] = (x >> 48)&0xff; pp[7] = (x >> 56)&0xff;
95 static inline uint64_t load64(const void *p)
97 const unsigned char *pp = p;
99 return ((((uint64_t )pp[0]&0xff) << 0) | (((uint64_t )pp[1]&0xff) << 8) |
100 (((uint64_t )pp[2]&0xff) << 16) | (((uint64_t )pp[3]&0xff) << 24) |
101 (((uint64_t )pp[4]&0xff) << 32) | (((uint64_t )pp[5]&0xff) << 40) |
102 (((uint64_t )pp[6]&0xff) << 48) | (((uint64_t )pp[7]&0xff) << 56));
105 /*----- The Kalyna block cipher -------------------------------------------*/
107 static PyTypeObject kalyna_pytype;
109 typedef struct kalyna_pyobj {
114 static PyObject *kalyna_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
116 char *kwlist[] = { "key", "blksz", 0 };
121 kalyna_pyobj *rc = 0;
125 if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#O&:new", kwlist,
126 &k, &ksz, convszt, &blksz))
129 case 16: case 32: case 64: break;
130 default: VALERR("bad block size");
132 if ((ksz != blksz && ksz != 2*blksz) || ksz > 64)
133 VALERR("bad key length");
135 kk = KalynaInit(8*blksz, 8*ksz); if (!kk) VALERR("unknown error");
136 for (i = 0; i < kk->nk; i++) k64[i] = load64(k + 8*i);
137 KalynaKeyExpand(k64, kk);
138 rc = PyObject_NEW(kalyna_pyobj, ty);
141 return ((PyObject *)rc);
144 static void kalyna_pydealloc(PyObject *me)
146 kalyna_pyobj *kobj = (kalyna_pyobj *)me;
147 KalynaDelete(kobj->k);
151 static PyObject *kalynameth_encrypt(PyObject *me, PyObject *arg)
156 kalyna_pyobj *kobj = (kalyna_pyobj *)me;
160 if (!PyArg_ParseTuple(arg, "s#:encrypt", &p, &psz)) goto end;
161 if (psz != 8*kobj->k->nb) VALERR("incorrect block size");
162 rc = PyString_FromStringAndSize(0, psz); q = PyString_AS_STRING(rc);
163 for (i = 0; i < kobj->k->nb; i++) p64[i] = load64(p + 8*i);
164 KalynaEncipher(p64, kobj->k, p64);
165 for (i = 0; i < kobj->k->nb; i++) store64(q + 8*i, p64[i]);
170 static PyObject *kalynameth_decrypt(PyObject *me, PyObject *arg)
175 kalyna_pyobj *kobj = (kalyna_pyobj *)me;
179 if (!PyArg_ParseTuple(arg, "s#:encrypt", &p, &psz)) goto end;
180 if (psz != 8*kobj->k->nb) VALERR("incorrect block size");
181 rc = PyString_FromStringAndSize(0, psz); q = PyString_AS_STRING(rc);
182 for (i = 0; i < kobj->k->nb; i++) p64[i] = load64(p + 8*i);
183 KalynaDecipher(p64, kobj->k, p64);
184 for (i = 0; i < kobj->k->nb; i++) store64(q + 8*i, p64[i]);
189 static PyMethodDef kalyna_pymethods[] = {
190 { "encrypt", kalynameth_encrypt, METH_VARARGS,
191 "encrypt(PTBLK) -> CTBLK" },
192 { "decrypt", kalynameth_decrypt, METH_VARARGS,
193 "decrypt(CTBLK) -> PTBLK" },
197 static PyTypeObject kalyna_pytype = {
198 PyObject_HEAD_INIT(0) 0, /* Header */
199 "Kalyna", /* @tp_name@ */
200 sizeof(kalyna_pyobj), /* @tp_basicsize@ */
201 0, /* @tp_itemsize@ */
203 kalyna_pydealloc, /* @tp_dealloc@ */
205 0, /* @tp_getattr@ */
206 0, /* @tp_setattr@ */
207 0, /* @tp_compare@ */
209 0, /* @tp_as_number@ */
210 0, /* @tp_as_sequence@ */
211 0, /* @tp_as_mapping@ */
215 0, /* @tp_getattro@ */
216 0, /* @tp_setattro@ */
217 0, /* @tp_as_buffer@ */
218 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
222 "Kalyna block cipher instance.",
224 0, /* @tp_traverse@ */
226 0, /* @tp_richcompare@ */
227 0, /* @tp_weaklistoffset@ */
229 0, /* @tp_iternext@ */
230 kalyna_pymethods, /* @tp_methods@ */
231 0, /* @tp_members@ */
235 0, /* @tp_descr_get@ */
236 0, /* @tp_descr_set@ */
237 0, /* @tp_dictoffset@ */
239 PyType_GenericAlloc, /* @tp_alloc@ */
240 kalyna_pynew, /* @tp_new@ */
245 /*----- Main code ---------------------------------------------------------*/
247 void initkalyna(void)
249 PyObject *mod = Py_InitModule("kalyna", 0);
250 if (PyType_Ready(&kalyna_pytype) < 0) return;
251 INSERT("version", PyString_FromString(VERSION));
252 INSERT("Kalyna", &kalyna_pytype);
255 /*----- That's all, folks -------------------------------------------------*/