Skip to content

Commit 940f55f

Browse files
committed
Port to Python 3
1 parent 687d19d commit 940f55f

File tree

2 files changed

+201
-47
lines changed

2 files changed

+201
-47
lines changed

main.c

Lines changed: 146 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,45 @@
55
*
66
* Wrapper written by James Cleveland with help from #python
77
* on irc.freenode.net
8+
*
9+
* Wrapper extended to use the hashlib interface and ported to
10+
* Python 3 by Olaf Conradi.
811
*/
912

1013
#include <Python.h>
1114
#include "Whirlpool.c"
1215

16+
#if PY_MAJOR_VERSION >= 3
17+
#ifndef GET_BUFFER_VIEW_OR_ERROUT
18+
/* Same as defined in hashlib.h */
19+
#define GET_BUFFER_VIEW_OR_ERROUT(obj, viewp) do { \
20+
if (PyUnicode_Check((obj))) { \
21+
PyErr_SetString(PyExc_TypeError, \
22+
"Unicode-objects must be encoded before hashing");\
23+
return NULL; \
24+
} \
25+
if (!PyObject_CheckBuffer((obj))) { \
26+
PyErr_SetString(PyExc_TypeError, \
27+
"object supporting the buffer API required"); \
28+
return NULL; \
29+
} \
30+
if (PyObject_GetBuffer((obj), (viewp), PyBUF_SIMPLE) == -1) { \
31+
return NULL; \
32+
} \
33+
if ((viewp)->ndim > 1) { \
34+
PyErr_SetString(PyExc_BufferError, \
35+
"Buffer must be single dimension"); \
36+
PyBuffer_Release((viewp)); \
37+
return NULL; \
38+
} \
39+
} while(0);
40+
#endif
41+
42+
#define HEXDIGITS(c) Py_hexdigits[c]
43+
#else
44+
#define HEXDIGITS(c) ((c>9) ? c+'a'-10 : c+'0')
45+
#endif
46+
1347
typedef struct {
1448
PyObject_HEAD
1549
NESSIEstruct whirlpool; /* the context holder */
@@ -45,10 +79,18 @@ whirlpool_dealloc(whirlpoolobject *wpp)
4579
static PyObject *
4680
whirlpool_update(whirlpoolobject *self, PyObject *args)
4781
{
48-
Py_buffer view;
82+
Py_buffer view = { 0 };
83+
#if PY_MAJOR_VERSION >= 3
84+
PyObject *obj = NULL;
4985

86+
if (!PyArg_ParseTuple(args, "O:update", &obj))
87+
return NULL;
88+
if (obj)
89+
GET_BUFFER_VIEW_OR_ERROUT(obj, &view);
90+
#else
5091
if (!PyArg_ParseTuple(args, "s*:update", &view))
5192
return NULL;
93+
#endif
5294

5395
NESSIEadd((unsigned char*)view.buf,
5496
Py_SAFE_DOWNCAST(view.len, Py_ssize_t, unsigned int) * 8,
@@ -76,11 +118,15 @@ whirlpool_digest(whirlpoolobject *self)
76118
wpContext = self->whirlpool;
77119
NESSIEfinalize(&wpContext, digest);
78120

121+
#if PY_MAJOR_VERSION >= 3
122+
return PyBytes_FromStringAndSize((const char *)digest, sizeof(digest));
123+
#else
79124
return PyString_FromStringAndSize((const char *)digest, sizeof(digest));
125+
#endif
80126
}
81127

82128
PyDoc_STRVAR(digest_doc,
83-
"digest() -> string\n\
129+
"digest() -> string of binary data\n\
84130
\n\
85131
Return the digest of the strings passed to the update() method so\n\
86132
far. This is a binary string which may contain non-ASCII characters,\n\
@@ -93,32 +139,43 @@ whirlpool_hexdigest(whirlpoolobject *self)
93139
NESSIEstruct wpContext;
94140
PyObject *retval;
95141
unsigned char digest[DIGESTBYTES];
142+
#if PY_MAJOR_VERSION >= 3
143+
Py_UCS1 *hexdigest;
144+
#else
96145
char *hexdigest;
146+
#endif
97147
int i, j;
98148

99149
/* Get the raw (binary) digest value */
100150
wpContext = self->whirlpool;
101151
NESSIEfinalize(&wpContext, digest);
102152

103153
/* Create a new string */
154+
#if PY_MAJOR_VERSION >= 3
155+
retval = PyUnicode_New(sizeof(digest) * 2, 127);
156+
#else
104157
retval = PyString_FromStringAndSize(NULL, sizeof(digest) * 2);
158+
#endif
105159
if (!retval)
106160
return NULL;
161+
162+
#if PY_MAJOR_VERSION >= 3
163+
hexdigest = PyUnicode_1BYTE_DATA(retval);
164+
#else
107165
hexdigest = PyString_AsString(retval);
166+
#endif
108167
if (!hexdigest) {
109168
Py_DECREF(retval);
110169
return NULL;
111170
}
112171

113172
/* Make hex version of the digest */
114173
for(i=j=0; i<sizeof(digest); i++) {
115-
char c;
174+
unsigned char c;
116175
c = (digest[i] >> 4) & 0xf;
117-
c = (c>9) ? c+'a'-10 : c+'0';
118-
hexdigest[j++] = c;
176+
hexdigest[j++] = HEXDIGITS(c);
119177
c = (digest[i] & 0xf);
120-
c = (c>9) ? c+'a'-10 : c+'0';
121-
hexdigest[j++] = c;
178+
hexdigest[j++] = HEXDIGITS(c);
122179
}
123180
return retval;
124181
}
@@ -147,7 +204,7 @@ PyDoc_STRVAR(copy_doc,
147204
Return a copy (``clone'') of the whirlpool object.");
148205

149206

150-
PyMethodDef whirlpool_methods[] = {
207+
static PyMethodDef whirlpool_methods[] = {
151208
{"update", (PyCFunction)whirlpool_update, METH_VARARGS, update_doc},
152209
{"digest", (PyCFunction)whirlpool_digest, METH_NOARGS, digest_doc},
153210
{"hexdigest", (PyCFunction)whirlpool_hexdigest, METH_NOARGS, hexdigest_doc},
@@ -159,19 +216,31 @@ PyMethodDef whirlpool_methods[] = {
159216
static PyObject *
160217
whirlpool_get_block_size(PyObject *self, void *closure)
161218
{
219+
#if PY_MAJOR_VERSION >= 3
220+
return PyLong_FromLong(WBLOCKBYTES);
221+
#else
162222
return PyInt_FromLong(WBLOCKBYTES);
223+
#endif
163224
}
164225

165226
static PyObject *
166227
whirlpool_get_digest_size(PyObject *self, void *closure)
167228
{
229+
#if PY_MAJOR_VERSION >= 3
230+
return PyLong_FromLong(DIGESTBYTES);
231+
#else
168232
return PyInt_FromLong(DIGESTBYTES);
233+
#endif
169234
}
170235

171236
static PyObject *
172237
whirlpool_get_name(PyObject *self, void *closure)
173238
{
239+
#if PY_MAJOR_VERSION >= 3
240+
return PyUnicode_FromStringAndSize("WHIRLPOOL", 9);
241+
#else
174242
return PyString_FromStringAndSize("WHIRLPOOL", 9);
243+
#endif
175244
}
176245

177246
static PyGetSetDef whirlpool_getseters[] = {
@@ -190,7 +259,21 @@ static PyGetSetDef whirlpool_getseters[] = {
190259
{NULL} /* sentinel */
191260
};
192261

193-
262+
#if PY_MAJOR_VERSION >= 3
263+
PyDoc_STRVAR(module_doc,
264+
"This module implements the interface to the whirlpool message digest\n\
265+
algorithm. It operates on messages less than 2^256 bits in length,\n\
266+
and produces a message digest of 512 bits. Its use is quite straighforward:\n\
267+
use new() to create a whirlpool object. You can now feed this object with\n\
268+
arbitrary strings using the update() method. At any point you can ask it for\n\
269+
the digest of the concatenation of the strings fed to it so far.\n\
270+
\n\
271+
Functions:\n\
272+
new([arg]) -- return a new whirlpool object, initialized with arg if provided\n\
273+
\n\
274+
Special Objects:\n\
275+
WhirlpoolType -- type object for whirlpool objects");
276+
#else
194277
PyDoc_STRVAR(module_doc,
195278
"This module implements the interface to the whirlpool message digest\n\
196279
algorithm. It operates on messages less than 2^256 bits in length,\n\
@@ -205,15 +288,14 @@ hash(arg) -- DEPRECATED, returns a whirlpool digest of arg, for backward \
205288
compatibility\n\
206289
\n\
207290
Special Objects:\n\
208-
\n\
209291
WhirlpoolType -- type object for whirlpool objects");
292+
#endif
210293

211294
PyDoc_STRVAR(whirlpooltype_doc,
212295
"A whirlpool represents the object used to calculate the WHIRLPOOL checksum of\n\
213296
a string of information.\n\
214297
\n\
215298
Methods:\n\
216-
\n\
217299
update(arg) -- updates the current digest with an additional string\n\
218300
digest() -- return the current digest value\n\
219301
hexdigest() -- return the current digest as a string of hexadecimal digits\n\
@@ -261,9 +343,17 @@ whirlpool_new(PyObject *self, PyObject *args)
261343
{
262344
whirlpoolobject *wpp;
263345
Py_buffer view = { 0 };
346+
#if PY_MAJOR_VERSION >= 3
347+
PyObject *obj = NULL;
264348

349+
if (!PyArg_ParseTuple(args, "|O:new", &obj))
350+
return NULL;
351+
if (obj)
352+
GET_BUFFER_VIEW_OR_ERROUT(obj, &view);
353+
#else
265354
if (!PyArg_ParseTuple(args, "|s*:new", &view))
266355
return NULL;
356+
#endif
267357

268358
if ((wpp = newwhirlpoolobject()) == NULL) {
269359
PyBuffer_Release(&view);
@@ -287,14 +377,15 @@ Return a new whirlpool object. If arg is present, the method call update(arg)\n\
287377
is made.");
288378

289379

380+
#if PY_MAJOR_VERSION < 3
381+
/* Function is deprecated and only available in Python 2.7 */
290382
static PyObject *
291383
whirlpool_hash(PyObject *self, PyObject *args) {
292384
struct NESSIEstruct w;
293385
unsigned char digest[DIGESTBYTES];
294386
Py_ssize_t data_size;
295387
unsigned char *data;
296388

297-
298389
if(!PyArg_ParseTuple(args, "s#", &data, &data_size))
299390
return NULL;
300391

@@ -308,33 +399,71 @@ whirlpool_hash(PyObject *self, PyObject *args) {
308399
PyDoc_STRVAR(hash_doc,
309400
"Returns a hash of argument using the whirlpool algorithm.\n\
310401
This function is deprecated. Please use new() and hexdigest().");
402+
#endif
311403

312404

313405
/* List of functions exported by this module */
314406

315-
static PyMethodDef whirlpool_functions[] = {
407+
static struct PyMethodDef whirlpool_functions[] = {
316408
{"new", (PyCFunction)whirlpool_new, METH_VARARGS, new_doc},
409+
#if PY_MAJOR_VERSION < 3
317410
{"hash", (PyCFunction)whirlpool_hash, METH_VARARGS, hash_doc},
411+
#endif
318412
{NULL, NULL} /* sentinel */
319413
};
320414

321415

322416
/* Initialize this module */
323417

324-
PyMODINIT_FUNC
325-
initwhirlpool(void)
418+
#if PY_MAJOR_VERSION >= 3
419+
static struct PyModuleDef moduledef = {
420+
PyModuleDef_HEAD_INIT,
421+
"whirlpool", /* m_name */
422+
module_doc, /* m_doc */
423+
-1, /* m_size */
424+
whirlpool_functions, /* m_methods */
425+
NULL, /* m_reload */
426+
NULL, /* m_traverse */
427+
NULL, /* m_clear */
428+
NULL /* m_free */
429+
};
430+
#endif
431+
432+
static PyObject *
433+
moduleinit(void)
326434
{
327435
PyObject *m, *d;
328436

329437
Py_TYPE(&Whirlpooltype) = &PyType_Type;
330438
if (PyType_Ready(&Whirlpooltype) < 0)
331-
return;
439+
return NULL;
440+
441+
#if PY_MAJOR_VERSION >= 3
442+
m = PyModule_Create(&moduledef);
443+
#else
332444
m = Py_InitModule3("whirlpool", whirlpool_functions, module_doc);
445+
#endif
333446
if (m == NULL)
334-
return;
447+
return NULL;
448+
335449
PyModule_AddIntConstant(m, "digest_size", DIGESTBYTES);
336450
PyModule_AddIntConstant(m, "block_size", WBLOCKBYTES);
337451
d = PyModule_GetDict(m);
338452
PyDict_SetItemString(d, "WhirlpoolType", (PyObject *)&Whirlpooltype);
453+
454+
return m;
339455
}
340456

457+
#if PY_MAJOR_VERSION >= 3
458+
PyMODINIT_FUNC
459+
PyInit_whirlpool(void)
460+
{
461+
return moduleinit();
462+
}
463+
#else
464+
PyMODINIT_FUNC
465+
initwhirlpool(void)
466+
{
467+
moduleinit();
468+
}
469+
#endif

0 commit comments

Comments
 (0)