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+
1347typedef struct {
1448 PyObject_HEAD
1549 NESSIEstruct whirlpool ; /* the context holder */
@@ -45,10 +79,18 @@ whirlpool_dealloc(whirlpoolobject *wpp)
4579static PyObject *
4680whirlpool_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
82128PyDoc_STRVAR (digest_doc ,
83- "digest() -> string\n\
129+ "digest() -> string of binary data \n\
84130\n\
85131Return the digest of the strings passed to the update() method so\n\
86132far. 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,
147204Return 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[] = {
159216static PyObject *
160217whirlpool_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
165226static PyObject *
166227whirlpool_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
171236static PyObject *
172237whirlpool_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
177246static 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
194277PyDoc_STRVAR (module_doc ,
195278"This module implements the interface to the whirlpool message digest\n\
196279algorithm. 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 \
205288compatibility\n\
206289\n\
207290Special Objects:\n\
208- \n\
209291WhirlpoolType -- type object for whirlpool objects" );
292+ #endif
210293
211294PyDoc_STRVAR (whirlpooltype_doc ,
212295"A whirlpool represents the object used to calculate the WHIRLPOOL checksum of\n\
213296a string of information.\n\
214297\n\
215298Methods:\n\
216- \n\
217299update(arg) -- updates the current digest with an additional string\n\
218300digest() -- return the current digest value\n\
219301hexdigest() -- 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\
287377is made." );
288378
289379
380+ #if PY_MAJOR_VERSION < 3
381+ /* Function is deprecated and only available in Python 2.7 */
290382static PyObject *
291383whirlpool_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) {
308399PyDoc_STRVAR (hash_doc ,
309400"Returns a hash of argument using the whirlpool algorithm.\n\
310401This 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