1 /*
2  * TLSH is provided for use under two licenses: Apache OR BSD.
3  * Users may opt to use either license depending on the license
4  * restictions of the systems with which they plan to integrate
5  * the TLSH code.
6  */
7 
8 /* ==============
9  * Apache License
10  * ==============
11  * Copyright 2013 Trend Micro Incorporated
12  *
13  * Licensed under the Apache License, Version 2.0 (the "License");
14  * you may not use this file except in compliance with the License.
15  * You may obtain a copy of the License at
16  *
17  *     http://www.apache.org/licenses/LICENSE-2.0
18  *
19  * Unless required by applicable law or agreed to in writing, software
20  * distributed under the License is distributed on an "AS IS" BASIS,
21  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22  * See the License for the specific language governing permissions and
23  * limitations under the License.
24  */
25 
26 /* ===========
27  * BSD License
28  * ===========
29  * Copyright (c) 2013, Trend Micro Incorporated
30  * All rights reserved.
31  *
32  * Redistribution and use in source and binary forms, with or without modification,
33  * are permitted provided that the following conditions are met:
34  *
35  * 1. Redistributions of source code must retain the above copyright notice, this
36  *    list of conditions and the following disclaimer.
37  *
38  * 2. Redistributions in binary form must reproduce the above copyright notice,
39  *    this list of conditions and the following disclaimer in the documentation
40  *    and/or other materials provided with the distribution.
41 
42  * 3. Neither the name of the copyright holder nor the names of its contributors
43  *    may be used to endorse or promote products derived from this software without
44  *    specific prior written permission.
45  *
46  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
47  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
48  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
49  * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
50  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
51  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
52  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
53  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
54  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
55  * OF THE POSSIBILITY OF SUCH DAMAGE.
56  */
57 
58 #define PY_SSIZE_T_CLEAN 1
59 #include <Python.h>
60 #include <new>
61 #include <bytesobject.h>
62 #include "tlsh.h"
63 
64 // to generate the "T1" hashes introduced in TLSH 4.0.0
65 // see 4.0.0 from 26/Mar/2020 at https://github.com/trendmicro/tlsh/blob/master/Change_History.md
66 #define SHOWVERSION	1
67 
68 #define TLSH_VERSION "4.7.1"
69 #define AUTHOR "Jonathan Oliver, Chun Cheng and Yanggui Chen"
70 
71 /* We want to update the hash using bytes object in Python 3 */
72 #if PY_MAJOR_VERSION >= 3
73 # define BYTES_VALUE_CHAR "y"
74 #else
75 # define BYTES_VALUE_CHAR "s"
76 #endif
77 
78 static char tlsh_doc[] =
79   "TLSH C version - similarity matching and searching";
80 static char tlsh_hash_doc[] =
81   "tlsh.hash(data)\n\n\
82   returns tlsh hexadecimal representation (string)";
83 static char tlsh_oldhash_doc[] =
84   "tlsh.oldhash(data)\n\n\
85   returns old tlsh hexadecimal representation (string) - no 'T1'";
86 static char tlsh_forcehash_doc[] =
87   "tlsh.forcehash(data)\n\n\
88   returns tlsh hexadecimal representation (string) - allows strings down to 50 char";
89 static char tlsh_conservativehash_doc[] =
90   "tlsh.conservativehash(data)\n\n\
91   returns tlsh hexadecimal representation (string) - does not allow strings < 256 char";
92 static char tlsh_oldconservativehash_doc[] =
93   "tlsh.oldconservativehash(data)\n\n\
94   returns tlsh hexadecimal representation (string) - does not allow strings < 256 char";
95 static char tlsh_diff_doc[] =
96   "tlsh.diff(hash1, hash2)\n\n\
97   returns tlsh score (integer)";
98 static char tlsh_diffxlen_doc[] =
99   "tlsh.diffxlen(hash1, hash2) - ignore object lengths\n\n\
100   returns tlsh score (integer)";
101 
eval_tlsh(unsigned char * pBuffer,Py_ssize_t len,int showvers)102 static PyObject* eval_tlsh(unsigned char* pBuffer, Py_ssize_t len, int showvers)
103 {
104 Tlsh tlsh;
105 	tlsh.update(pBuffer, len);
106 	tlsh.final();
107 	const char *s = tlsh.getHash(showvers);
108 	if (*s == '\0')
109 		return Py_BuildValue("s", "TNULL");
110 	return Py_BuildValue("s", s);
111 }
112 
113 // hash(data) returns byte buffer
hash_py(PyObject * self,PyObject * args)114 static PyObject* hash_py(PyObject* self, PyObject* args)
115 {
116 	unsigned char* pBuffer;
117 	Py_ssize_t len;
118 	if (!PyArg_ParseTuple(args, BYTES_VALUE_CHAR "#", &pBuffer, &len)) {
119 		return NULL;
120 	}
121 	return (eval_tlsh(pBuffer, len, SHOWVERSION));
122 }
123 
124 // oldhash(data) returns byte buffer
oldhash_py(PyObject * self,PyObject * args)125 static PyObject* oldhash_py(PyObject* self, PyObject* args) {
126 	unsigned char* pBuffer;
127 	Py_ssize_t len;
128 	if (!PyArg_ParseTuple(args, BYTES_VALUE_CHAR "#", &pBuffer, &len)) {
129 		return NULL;
130 	}
131 	return (eval_tlsh(pBuffer, len, 0));
132 }
133 
134 // forcehash(data) returns byte buffer
forcehash_py(PyObject * self,PyObject * args)135 static PyObject* forcehash_py(PyObject* self, PyObject* args)
136 {
137 	return ( hash_py(self, args) );
138 }
139 
140 
eval_cons_tlsh(unsigned char * pBuffer,Py_ssize_t len,int showvers)141 static PyObject* eval_cons_tlsh(unsigned char* pBuffer, Py_ssize_t len, int showvers)
142 {
143 Tlsh tlsh;
144 	tlsh.update(pBuffer, len);
145 	tlsh.final(NULL, 0, 2);
146 	const char *s = tlsh.getHash(showvers);
147 	if (*s == '\0')
148 		return Py_BuildValue("s", "TNULL");
149 	return Py_BuildValue("s", s);
150 }
151 
152 // conservativehash(data) returns byte buffer
conservativehash_py(PyObject * self,PyObject * args)153 static PyObject* conservativehash_py(PyObject* self, PyObject* args)
154 {
155 	unsigned char* pBuffer;
156 	Py_ssize_t len;
157 	if (!PyArg_ParseTuple(args, BYTES_VALUE_CHAR "#", &pBuffer, &len)) {
158 		return NULL;
159 	}
160 	return (eval_cons_tlsh(pBuffer, len, SHOWVERSION));
161 }
162 
163 // oldconservativehash(data) returns byte buffer
oldconservativehash_py(PyObject * self,PyObject * args)164 static PyObject* oldconservativehash_py(PyObject* self, PyObject* args)
165 {
166 	unsigned char* pBuffer;
167 	Py_ssize_t len;
168 	if (!PyArg_ParseTuple(args, BYTES_VALUE_CHAR "#", &pBuffer, &len)) {
169 		return NULL;
170 	}
171 	return (eval_cons_tlsh(pBuffer, len, 0));
172 }
173 
174 // diff(hash1, hash2) returns integer
diff_py(PyObject * self,PyObject * args)175 static PyObject* diff_py(PyObject* self, PyObject* args) {
176   char *hash1, *hash2;
177   if (!PyArg_ParseTuple(args, "ss", &hash1, &hash2)) {
178     return NULL;
179   }
180 
181   Tlsh tlsh1, tlsh2;
182   if (tlsh1.fromTlshStr(hash1) != 0) {
183     return PyErr_Format(PyExc_ValueError, "argument %s is not a TLSH hex string", hash1);
184   }
185   if (tlsh2.fromTlshStr(hash2) != 0) {
186     return PyErr_Format(PyExc_ValueError, "argument %s is not a TLSH hex string", hash2);
187   }
188 
189   int score = tlsh1.totalDiff(&tlsh2);
190 
191   return Py_BuildValue("i", score);
192 }
193 
194 //diffxlen(hash1, hash2) returns integer
diffxlen_py(PyObject * self,PyObject * args)195 static PyObject* diffxlen_py(PyObject* self, PyObject* args) {
196   char *hash1, *hash2;
197   if (!PyArg_ParseTuple(args, "ss", &hash1, &hash2)) {
198       return NULL;
199   }
200 
201   Tlsh tlsh1, tlsh2;
202   if (tlsh1.fromTlshStr(hash1) != 0) {
203     return PyErr_Format(PyExc_ValueError, "argument %s is not a TLSH hex string", hash1);
204   }
205   if (tlsh2.fromTlshStr(hash2) != 0) {
206     return PyErr_Format(PyExc_ValueError, "argument %s is not a TLSH hex string", hash2);
207   }
208 
209   int score = tlsh1.totalDiff(&tlsh2, false);
210 
211   return Py_BuildValue("i", score);
212 }
213 
214 // The module's methods
215 static PyMethodDef tlsh_methods[] =
216 {
217   { "hash", hash_py, METH_VARARGS, tlsh_hash_doc },
218   { "oldhash", oldhash_py, METH_VARARGS, tlsh_oldhash_doc },
219   { "forcehash", forcehash_py, METH_VARARGS, tlsh_forcehash_doc },
220   { "conservativehash", conservativehash_py, METH_VARARGS, tlsh_conservativehash_doc },
221   { "oldconservativehash", oldconservativehash_py, METH_VARARGS, tlsh_oldconservativehash_doc },
222   { "diff", diff_py, METH_VARARGS, tlsh_diff_doc },
223   { "diffxlen", diffxlen_py, METH_VARARGS, tlsh_diffxlen_doc },
224   { NULL, NULL } /* sentinel */
225 };
226 
227 typedef struct {
228     PyObject_HEAD
229     unsigned short required_data;
230     bool finalized;
231     Tlsh tlsh;
232 } tlsh_TlshObject;
233 
234 static int Tlsh_init(PyObject *, PyObject *, PyObject *);
235 static PyObject * Tlsh_fromTlshStr(tlsh_TlshObject *, PyObject *);
236 static PyObject * Tlsh_update(tlsh_TlshObject *, PyObject *);
237 static PyObject * Tlsh_final(tlsh_TlshObject *);
238 static PyObject * Tlsh_hexdigest(tlsh_TlshObject *);
239 static PyObject * Tlsh_diff(tlsh_TlshObject *, PyObject *);
240 static PyObject * Tlsh_lvalue(tlsh_TlshObject *);
241 static PyObject * Tlsh_q1ratio(tlsh_TlshObject *);
242 static PyObject * Tlsh_q2ratio(tlsh_TlshObject *);
243 static PyObject * Tlsh_is_valid(tlsh_TlshObject *);
244 static PyObject * Tlsh_checksum(tlsh_TlshObject *, PyObject *);
245 static PyObject * Tlsh_bucket_value(tlsh_TlshObject *, PyObject *);
246 
247 static PyMethodDef Tlsh_methods[] = {
248     {"fromTlshStr", (PyCFunction) Tlsh_fromTlshStr, METH_VARARGS,
249      "Create a TLSH instance from a hex string."
250     },
251     {"update", (PyCFunction) Tlsh_update, METH_VARARGS,
252      "Update the TLSH with the given string."
253     },
254     {"final", (PyCFunction) Tlsh_final, METH_NOARGS,
255      "Signal that no more data will be added. This is required before reading the hash."
256     },
257     {"hexdigest", (PyCFunction) Tlsh_hexdigest, METH_NOARGS,
258      "Get the computed TLSH as a string object containing only hexadecimal digits."
259     },
260     {"diff", (PyCFunction) Tlsh_diff, METH_VARARGS,
261      "Returns the TLSH score compared to the given Tlsh object or hexadecimal string."
262     },
263     {"checksum", (PyCFunction) Tlsh_checksum, METH_VARARGS,
264      "TLSH checksum."
265     },
266     {"bucket_value", (PyCFunction) Tlsh_bucket_value, METH_VARARGS,
267      "TLSH bucket value."
268     },
269     {NULL} /* Sentinel */
270 };
271 
272 static PyGetSetDef Tlsh_getsetters[] = {
273     {"lvalue", (getter) Tlsh_lvalue, NULL,
274      "TLSH Lvalue.", NULL
275     },
276     {"q1ratio", (getter) Tlsh_q1ratio, NULL,
277      "TLSH Q1ratio.", NULL
278     },
279     {"q2ratio", (getter) Tlsh_q2ratio, NULL,
280      "TLSH Q2ratio.", NULL
281     },
282     {"is_valid", (getter) Tlsh_is_valid, NULL,
283      "Is it a valid TLSH.", NULL
284     },
285     {NULL} /* Sentinel */
286 };
287 
288 static PyTypeObject tlsh_TlshType = {
289     PyObject_HEAD_INIT(NULL)
290 #if PY_MAJOR_VERSION < 3
291     0,                         /* ob_size */
292 #endif
293     "tlsh.Tlsh",               /* tp_name */
294     sizeof(tlsh_TlshObject),   /* tp_basicsize */
295     0,                         /* tp_itemsize */
296     0,                         /* tp_dealloc */
297     0,                         /* tp_print */
298     0,                         /* tp_getattr */
299     0,                         /* tp_setattr */
300     0,                         /* tp_compare */
301     0,                         /* tp_repr */
302     0,                         /* tp_as_number */
303     0,                         /* tp_as_sequence */
304     0,                         /* tp_as_mapping */
305     0,                         /* tp_hash  */
306     0,                         /* tp_call */
307     0,                         /* tp_str */
308     0,                         /* tp_getattro */
309     0,                         /* tp_setattro */
310     0,                         /* tp_as_buffer */
311     Py_TPFLAGS_DEFAULT,        /* tp_flags */
312     "TLSH objects",            /* tp_doc */
313     0,                         /* tp_traverse */
314     0,                         /* tp_clear */
315     0,                         /* tp_richcompare */
316     0,                         /* tp_weaklistoffset */
317     0,                         /* tp_iter */
318     0,                         /* tp_iternext */
319     Tlsh_methods,              /* tp_methods */
320     0,                         /* tp_members */
321     Tlsh_getsetters,           /* tp_getset */
322     0,                         /* tp_base */
323     0,                         /* tp_dict */
324     0,                         /* tp_descr_get */
325     0,                         /* tp_descr_set */
326     0,                         /* tp_dictoffset */
327     Tlsh_init,                 /* tp_init */
328     0,                         /* tp_alloc */
329     0,                         /* tp_new */
330 };
331 
332 static int
Tlsh_init(PyObject * self,PyObject * args,PyObject * kwds)333 Tlsh_init(PyObject *self, PyObject *args, PyObject *kwds)
334 {
335     tlsh_TlshObject * tlsh_object = (tlsh_TlshObject *) self;
336 
337     if (PyTuple_Size(args) > 1) {
338         PyErr_Format(PyExc_TypeError, "Tlsh() takes at most 1 argument (%lu given)", PyTuple_Size(args));
339         return -1;
340     }
341     if (kwds) {
342         PyErr_SetString(PyExc_TypeError, "Tlsh() takes no keyword arguments");
343         return -1;
344     }
345 
346    /* Call Tlsh() constructor. */
347    new (&tlsh_object->tlsh) Tlsh();
348 
349    if (PyTuple_Size(args) == 1) {
350         Tlsh_update(tlsh_object, args);
351         if (PyErr_Occurred())
352             return -1;
353    }
354 
355     return 0;
356 }
357 
358 static PyObject *
Tlsh_fromTlshStr(tlsh_TlshObject * self,PyObject * args)359 Tlsh_fromTlshStr(tlsh_TlshObject *self, PyObject *args)
360 {
361     char *str;
362     Py_ssize_t len;
363 
364     PyObject *arg;
365 
366     if (PyTuple_Size(args) != 1)
367         return PyErr_Format(PyExc_TypeError, "function takes exactly 1 argument (%lu given)", PyTuple_Size(args));
368 
369     arg = PyTuple_GetItem(args, 0);
370 #if PY_MAJOR_VERSION >= 3
371     if (!PyUnicode_Check(arg) || (arg = PyUnicode_AsASCIIString(arg)) == NULL) {
372       PyErr_SetString(PyExc_ValueError, "argument is not a TLSH hex string");
373       return NULL;
374     }
375 #else
376     if (!PyString_Check(arg)) {
377       PyErr_SetString(PyExc_ValueError, "argument is not a TLSH hex string");
378       return NULL;
379     }
380 #endif
381 
382     if (PyBytes_AsStringAndSize(arg, &str, &len) == -1) {
383         PyErr_SetString(PyExc_ValueError, "argument is not a TLSH hex string");
384         return NULL;
385     }
386 
387     if ((len != TLSH_STRING_LEN_REQ) && (len != TLSH_STRING_LEN_REQ-2)) {
388         PyErr_SetString(PyExc_ValueError, "argument length incorrect: not a TLSH hex string");
389         return NULL;
390     }
391 
392     if (self->tlsh.fromTlshStr(str) != 0) {
393         PyErr_SetString(PyExc_ValueError, "argument value incorrect: not a TLSH hex string");
394         return NULL;
395     }
396     self->finalized = true;
397 
398     Py_RETURN_NONE;
399 }
400 
401 static PyObject *
Tlsh_update(tlsh_TlshObject * self,PyObject * args)402 Tlsh_update(tlsh_TlshObject *self, PyObject *args)
403 {
404     const char *str;
405     Py_ssize_t len;
406 
407     if (!PyArg_ParseTuple(args, BYTES_VALUE_CHAR "#", &str, &len))
408         return NULL;
409 
410     if (self->finalized) {
411         PyErr_SetString(PyExc_ValueError, "final() has already been called");
412         return NULL;
413     }
414     if (self->required_data < MIN_DATA_LENGTH) {
415         self->required_data += len > MIN_DATA_LENGTH ? MIN_DATA_LENGTH : len;
416     }
417 
418     self->tlsh.update((unsigned char *) str, (unsigned int) len);
419 
420     Py_RETURN_NONE;
421 }
422 
423 static PyObject *
Tlsh_final(tlsh_TlshObject * self)424 Tlsh_final(tlsh_TlshObject *self)
425 {
426     if (self->finalized) {
427         PyErr_SetString(PyExc_ValueError, "final() has already been called");
428         return NULL;
429     }
430     if (self->required_data < MIN_DATA_LENGTH) {
431         return PyErr_Format(PyExc_ValueError, "less than %u of input", MIN_DATA_LENGTH);
432     }
433     self->finalized = true;
434     self->tlsh.final();
435 
436     Py_RETURN_NONE;
437 }
438 
439 static PyObject *
Tlsh_hexdigest(tlsh_TlshObject * self)440 Tlsh_hexdigest(tlsh_TlshObject *self)
441 {
442     char hash[TLSH_STRING_LEN_REQ + 1];
443 
444     if (!self->finalized) {
445         PyErr_SetString(PyExc_ValueError, "final() has not been called");
446         return NULL;
447     }
448     self->tlsh.getHash(hash, TLSH_STRING_LEN_REQ + 1, SHOWVERSION);
449     if (hash[0] == '\0') {
450         PyErr_SetString(PyExc_ValueError, "error while getting hash (not enough variation in input?)");
451         return NULL;
452     }
453     return Py_BuildValue("s", hash);
454 }
455 
456 static PyObject *
Tlsh_diff(tlsh_TlshObject * self,PyObject * args)457 Tlsh_diff(tlsh_TlshObject *self, PyObject *args)
458 {
459     PyObject *arg;
460     int score;
461 
462     if (PyTuple_Size(args) != 1)
463         return PyErr_Format(PyExc_TypeError, "function takes exactly 1 argument (%lu given)", PyTuple_Size(args));
464 
465     arg = PyTuple_GetItem(args, 0);
466 #if PY_MAJOR_VERSION >= 3
467     if (PyUnicode_Check(arg)) {
468       if ((arg = PyUnicode_AsASCIIString(arg)) == NULL) {
469         PyErr_SetString(PyExc_ValueError, "argument is not a TLSH hex string");
470         return NULL;
471       }
472 #else
473     if (PyString_Check(arg)) {
474 #endif
475       char *str;
476       Py_ssize_t len;
477       Tlsh other;
478       if (PyBytes_AsStringAndSize(arg, &str, &len) == -1) {
479         PyErr_SetString(PyExc_ValueError, "argument is not a TLSH hex string");
480         return NULL;
481       }
482       if ((len != TLSH_STRING_LEN_REQ) && (len != TLSH_STRING_LEN_REQ-2)) {
483         PyErr_SetString(PyExc_ValueError, "argument is not a TLSH hex string");
484         return NULL;
485       }
486       if (other.fromTlshStr(str) != 0) {
487         PyErr_SetString(PyExc_ValueError, "argument is not a TLSH hex string");
488         return NULL;
489       }
490       score = self->tlsh.totalDiff(&other);
491     } else if (PyObject_TypeCheck(arg, &tlsh_TlshType)) {
492       tlsh_TlshObject * other_tlsh = (tlsh_TlshObject *) arg;
493       score = self->tlsh.totalDiff(&other_tlsh->tlsh);
494     } else {
495       PyErr_SetString(PyExc_ValueError, "argument is neither a Tlsh object nor a TLSH hex string");
496       return NULL;
497     }
498 
499     return Py_BuildValue("i", score);
500 }
501 
502 static PyObject *
503 Tlsh_lvalue(tlsh_TlshObject *self)
504 {
505     if (!self->finalized) {
506         PyErr_SetString(PyExc_ValueError, "final() has not been called");
507         return NULL;
508     }
509     return Py_BuildValue("i", self->tlsh.Lvalue());
510 }
511 
512 static PyObject *
513 Tlsh_q1ratio(tlsh_TlshObject *self)
514 {
515     if (!self->finalized) {
516         PyErr_SetString(PyExc_ValueError, "final() has not been called");
517         return NULL;
518     }
519     return Py_BuildValue("i", self->tlsh.Q1ratio());
520 }
521 
522 static PyObject *
523 Tlsh_q2ratio(tlsh_TlshObject *self)
524 {
525     if (!self->finalized) {
526         PyErr_SetString(PyExc_ValueError, "final() has not been called");
527         return NULL;
528     }
529     return Py_BuildValue("i", self->tlsh.Q2ratio());
530 }
531 
532 static PyObject *
533 Tlsh_is_valid(tlsh_TlshObject *self)
534 {
535     return PyBool_FromLong(self->tlsh.isValid());
536 }
537 
538 static PyObject *
539 Tlsh_checksum(tlsh_TlshObject *self, PyObject *args)
540 {
541     int id;
542     if (!self->finalized) {
543         PyErr_SetString(PyExc_ValueError, "final() has not been called");
544         return NULL;
545     }
546     PyArg_ParseTuple(args, "i", &id);
547 
548     return Py_BuildValue("i", self->tlsh.Checksum(id));
549 }
550 
551 static PyObject *
552 Tlsh_bucket_value(tlsh_TlshObject *self, PyObject *args)
553 {
554     int id;
555     if (!self->finalized) {
556         PyErr_SetString(PyExc_ValueError, "final() has not been called");
557         return NULL;
558     }
559     PyArg_ParseTuple(args, "i", &id);
560 
561     return Py_BuildValue("i", self->tlsh.BucketValue(id));
562 }
563 
564 // Initializes the module
565 #if PY_MAJOR_VERSION >= 3
566     static struct PyModuleDef moduledef = {
567             PyModuleDef_HEAD_INIT,
568             "tlsh",     /* m_name */
569             tlsh_doc,  /* m_doc */
570             -1,                  /* m_size */
571             tlsh_methods,    /* m_methods */
572             NULL,                /* m_reload */
573             NULL,                /* m_traverse */
574             NULL,                /* m_clear */
575             NULL,                /* m_free */
576         };
577 
578     PyMODINIT_FUNC PyInit_tlsh(void)
579     {
580         PyObject *module;
581 
582         tlsh_TlshType.tp_new = PyType_GenericNew;
583         if (PyType_Ready(&tlsh_TlshType) < 0)
584             return NULL;
585 
586         module = PyModule_Create(&moduledef);
587         PyModule_AddStringConstant(module,
588         "__version__",
589         TLSH_VERSION);
590         PyModule_AddStringConstant(module,
591         "__author__",
592         AUTHOR);
593 
594         Py_INCREF(&tlsh_TlshType);
595         PyModule_AddObject(module, "Tlsh", (PyObject *) &tlsh_TlshType);
596 
597         return module;
598     }
599 #else
600 
601     PyMODINIT_FUNC inittlsh(void)
602     {
603         PyObject *module;
604 
605         tlsh_TlshType.tp_new = PyType_GenericNew;
606         if (PyType_Ready(&tlsh_TlshType) < 0)
607             return;
608 
609         module = Py_InitModule3("tlsh",
610         tlsh_methods,
611         tlsh_doc);
612         PyModule_AddStringConstant(module,
613         "__version__",
614         TLSH_VERSION);
615         PyModule_AddStringConstant(module,
616         "__author__",
617         AUTHOR);
618 
619         Py_INCREF(&tlsh_TlshType);
620         PyModule_AddObject(module, "Tlsh", (PyObject *) &tlsh_TlshType);
621     }
622 #endif
623