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 -------------------------------------------------*/