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