1
0
mirror of https://github.com/hashcat/hashcat.git synced 2025-07-04 13:52:40 +00:00
hashcat/src/bridges/bridge_python_generic_hash_sp.c
Jens Steube 2962b9d52e - Improved strategy to detect pyenv managed python libraries
- Improved documents on python bridge
2025-06-03 07:10:50 +02:00

1178 lines
40 KiB
C

/**
* Author......: See docs/credits.txt
* License.....: MIT
*/
#include "common.h"
#include "types.h"
#include "bridges.h"
#include "memory.h"
#include "shared.h"
#include "dynloader.h"
#if defined (_WIN)
#include "processenv.h"
#endif
// python interpreter
#define PY_SSIZE_T_CLEAN
#undef _GNU_SOURCE
#include <Python.h>
#define PYTHON_API_CALL
typedef void (PYTHON_API_CALL *PY_INITIALIZE) ();
typedef void (PYTHON_API_CALL *PY_FINALIZE) ();
typedef void (PYTHON_API_CALL *PY_DECREF) (PyObject *);
typedef PyObject *(PYTHON_API_CALL *PYBOOL_FROMLONG) (long);
typedef PyObject *(PYTHON_API_CALL *PYBYTES_FROMSTRINGANDSIZE) (const char *, Py_ssize_t);
typedef int (PYTHON_API_CALL *PYDICT_DELITEMSTRING) (PyObject *, const char *);
typedef PyObject *(PYTHON_API_CALL *PYDICT_GETITEMSTRING) (PyObject *, const char *);
typedef PyObject *(PYTHON_API_CALL *PYDICT_NEW) ();
typedef int (PYTHON_API_CALL *PYDICT_SETITEMSTRING) (PyObject *, const char *, PyObject *);
typedef void (PYTHON_API_CALL *PYERR_PRINT) ();
typedef PyObject *(PYTHON_API_CALL *PYIMPORT_IMPORTMODULE) (const char *);
typedef PyObject *(PYTHON_API_CALL *PYIMPORT_IMPORT) (PyObject *);
typedef int (PYTHON_API_CALL *PYLIST_APPEND) (PyObject *, PyObject *);
typedef PyObject *(PYTHON_API_CALL *PYLIST_GETITEM) (PyObject *, Py_ssize_t);
typedef PyObject *(PYTHON_API_CALL *PYLIST_NEW) (Py_ssize_t);
typedef int (PYTHON_API_CALL *PYLIST_SETITEM) (PyObject *, Py_ssize_t, PyObject *);
typedef Py_ssize_t (PYTHON_API_CALL *PYLIST_SIZE) (PyObject *);
typedef PyObject *(PYTHON_API_CALL *PYLONG_FROMLONG) (long);
typedef PyObject *(PYTHON_API_CALL *PYOBJECT_CALLOBJECT) (PyObject *, PyObject *);
typedef PyObject *(PYTHON_API_CALL *PYOBJECT_GETATTRSTRING) (PyObject *, const char *);
typedef PyObject *(PYTHON_API_CALL *PYTUPLE_NEW) (Py_ssize_t);
typedef int (PYTHON_API_CALL *PYTUPLE_SETITEM) (PyObject *, Py_ssize_t, PyObject *);
typedef const char *(PYTHON_API_CALL *PYUNICODE_ASUTF8) (PyObject *);
typedef const char *(PYTHON_API_CALL *PYUNICODE_ASUTF8ANDSIZE) (PyObject *, Py_ssize_t *);
typedef PyObject *(PYTHON_API_CALL *PYUNICODE_DECODEFSDEFAULTANDSIZE) (const char *, Py_ssize_t);
typedef PyObject *(PYTHON_API_CALL *PYUNICODE_DECODEFSDEFAULT) (const char *);
typedef PyObject *(PYTHON_API_CALL *PYUNICODE_FROMSTRINGANDSIZE) (const char *, Py_ssize_t);
typedef PyObject *(PYTHON_API_CALL *PYUNICODE_FROMSTRING) (const char *);
typedef void (PYTHON_API_CALL *PYEVAL_ACQUIRELOCK) (void);
typedef void (PYTHON_API_CALL *PYEVAL_RELEASELOCK) (void);
typedef PyThreadState *(PYTHON_API_CALL *PYTHREADSTATE_SWAP) (PyThreadState *);
typedef PyThreadState *(PYTHON_API_CALL *PYNEWINTERPRETER) (void);
typedef void (PYTHON_API_CALL *PYENDINTERPRETER) (PyThreadState *);
typedef PyGILState_STATE (PYTHON_API_CALL *PYGILSTATE_ENSURE) (void);
typedef void (PYTHON_API_CALL *PYGILSTATE_RELEASE) (PyGILState_STATE);
typedef void (PYTHON_API_CALL *PYEVAL_ACQUIRETHREAD) (PyThreadState *);
typedef void (PYTHON_API_CALL *PYEVAL_RELEASETHREAD) (PyThreadState *);
typedef void (PYTHON_API_CALL *PYTHREADSTATE_CLEAR) (PyThreadState *);
typedef void (PYTHON_API_CALL *PYTHREADSTATE_DELETE) (PyThreadState *);
typedef PyThreadState *(PYTHON_API_CALL *PYTHREADSTATE_NEW) (PyInterpreterState *);
typedef PyInterpreterState *(PYTHON_API_CALL *PYINTERPRETERSTATE_MAIN) (void);
typedef void (PYTHON_API_CALL *PYEVAL_INITTHREADS) (void);
typedef PyThreadState *(PYTHON_API_CALL *PYEVAL_SAVETHREAD) (void);
typedef PyStatus (PYTHON_API_CALL *PYNEWINTERPRETERFROMCONFIG) (PyThreadState **, const PyInterpreterConfig *);
typedef void (PYTHON_API_CALL *PYEXITSTATUSEXCEPTION) (PyStatus);
typedef PyStatus (PYTHON_API_CALL *PYINITIALIZEFROMCONFIG) (const PyConfig *);
typedef void (PYTHON_API_CALL *PYEVAL_RESTORETHREAD) (PyThreadState *);
typedef const char *(PYTHON_API_CALL *PYGETVERSION) (void);
typedef struct hc_python_lib
{
hc_dynlib_t lib;
PY_INITIALIZE Py_Initialize;
PY_FINALIZE Py_Finalize;
PY_DECREF Py_DecRef;
PYBOOL_FROMLONG PyBool_FromLong;
PYBYTES_FROMSTRINGANDSIZE PyBytes_FromStringAndSize;
PYDICT_DELITEMSTRING PyDict_DelItemString;
PYDICT_GETITEMSTRING PyDict_GetItemString;
PYDICT_NEW PyDict_New;
PYDICT_SETITEMSTRING PyDict_SetItemString;
PYERR_PRINT PyErr_Print;
PYIMPORT_IMPORTMODULE PyImport_ImportModule;
PYIMPORT_IMPORT PyImport_Import;
PYLIST_APPEND PyList_Append;
PYLIST_GETITEM PyList_GetItem;
PYLIST_NEW PyList_New;
PYLIST_SETITEM PyList_SetItem;
PYLIST_SIZE PyList_Size;
PYLONG_FROMLONG PyLong_FromLong;
PYOBJECT_CALLOBJECT PyObject_CallObject;
PYOBJECT_GETATTRSTRING PyObject_GetAttrString;
PYTUPLE_NEW PyTuple_New;
PYTUPLE_SETITEM PyTuple_SetItem;
PYUNICODE_ASUTF8 PyUnicode_AsUTF8;
PYUNICODE_ASUTF8ANDSIZE PyUnicode_AsUTF8AndSize;
PYUNICODE_DECODEFSDEFAULTANDSIZE PyUnicode_DecodeFSDefaultAndSize;
PYUNICODE_DECODEFSDEFAULT PyUnicode_DecodeFSDefault;
PYUNICODE_FROMSTRINGANDSIZE PyUnicode_FromStringAndSize;
PYUNICODE_FROMSTRING PyUnicode_FromString;
PYEVAL_ACQUIRELOCK PyEval_AcquireLock;
PYEVAL_RELEASELOCK PyEval_ReleaseLock;
PYTHREADSTATE_SWAP PyThreadState_Swap;
PYNEWINTERPRETER Py_NewInterpreter;
PYENDINTERPRETER Py_EndInterpreter;
PYGILSTATE_ENSURE PyGILState_Ensure;
PYGILSTATE_RELEASE PyGILState_Release;
PYEVAL_ACQUIRETHREAD PyEval_AcquireThread;
PYEVAL_RELEASETHREAD PyEval_ReleaseThread;
PYTHREADSTATE_CLEAR PyThreadState_Clear;
PYTHREADSTATE_DELETE PyThreadState_Delete;
PYTHREADSTATE_NEW PyThreadState_New;
PYINTERPRETERSTATE_MAIN PyInterpreterState_Main;
PYEVAL_INITTHREADS PyEval_InitThreads;
PYEVAL_SAVETHREAD PyEval_SaveThread;
PYNEWINTERPRETERFROMCONFIG Py_NewInterpreterFromConfig;
PYEXITSTATUSEXCEPTION Py_ExitStatusException;
PYINITIALIZEFROMCONFIG Py_InitializeFromConfig;
PYEVAL_RESTORETHREAD PyEval_RestoreThread;
PYGETVERSION Py_GetVersion;
} hc_python_lib_t;
// good: we can use this multiplier do reduce copy overhead to increase the guessing speed,
// bad: but we also increase the password candidate batch size.
// slow hashes which make use of this bridge probably are used with smaller wordlists,
// and therefore it's easier for hashcat to parallelize if this multiplier is low.
// in the end, it's a trade-off.
#define N_ACCEL 8
typedef struct
{
// input
u32 pw_buf[64];
u32 pw_len;
// output
u32 out_buf[64];
u32 out_len;
} generic_io_tmp_t;
typedef struct
{
// template
char unit_info_buf[1024];
int unit_info_len;
u64 workitem_count;
size_t workitem_size;
// implementation specific
PyThreadState *tstate;
PyObject *pArgs;
PyObject *pContext;
PyObject *pModule;
PyObject *pFunc_Init;
PyObject *pFunc_Term;
PyObject *pFunc_kernel_loop;
} unit_t;
typedef struct
{
unit_t *units_buf;
int units_cnt;
hc_python_lib_t *python;
PyThreadState *thread_state;
char *source_filename;
} python_interpreter_t;
static char *DEFAULT_SOURCE_FILENAME = "generic_hash_sp";
#if defined (_WIN)
#define DEVNULL "NUL"
#else
#define DEVNULL "/dev/null"
#endif
static int suppress_stderr (void)
{
int null_fd = open (DEVNULL, O_WRONLY);
if (null_fd < 0) return -1;
int saved_fd = dup (fileno (stderr));
if (saved_fd < 0)
{
close (null_fd);
return -1;
}
dup2 (null_fd, fileno (stderr));
close (null_fd);
return saved_fd;
}
static void restore_stderr (int saved_fd)
{
if (saved_fd < 0) return;
dup2 (saved_fd, fileno (stderr));
close (saved_fd);
}
static char *expand_pyenv_libpath (const char *prefix, const int maj, const int min)
{
char *out = NULL;
#if defined (_WIN)
const int len = asprintf (&out, "%s/python%d%dt.dll", prefix, maj, min); //untested
#elif defined (__MSYS__)
const int len = asprintf (&out, "%s/msys-python%d.%dt.dll", prefix, maj, min); //untested could be wrong
#elif defined (__APPLE__)
const int len = asprintf (&out, "%s/lib/libpython%d.%dt.dylib", prefix, maj, min); //untested
#elif defined (__CYGWIN__)
const int len = asprintf (&out, "%s/lib/python%d%dt.dll", prefix, maj, min); //untested
#else
const int len = asprintf (&out, "%s/lib/libpython%d.%dt.so", prefix, maj, min);
#endif
if (len == -1) return NULL;
struct stat st;
if (stat (out, &st) != 0)
{
free (out);
return NULL;
}
return out;
}
static int resolve_pyenv_libpath (char *out_buf, const size_t out_sz)
{
// prefix
FILE *fp1 = popen ("pyenv prefix", "r");
if (fp1 == NULL) return -1;
char prefix_path[PATH_MAX];
if (fgets (prefix_path, sizeof (prefix_path), fp1) == NULL)
{
pclose (fp1);
return -1;
}
pclose (fp1);
superchop_with_length (prefix_path, strlen (prefix_path));
int maj = 0;
int min = 0;
// local
FILE *fp2 = popen ("pyenv local", "r");
if (fp2 == NULL) return -1;
if (fscanf (fp2, "%d.%d", &maj, &min) == 2)
{
pclose (fp2);
char *pyenv_libpath = expand_pyenv_libpath (prefix_path, maj, min);
if (pyenv_libpath != NULL)
{
strncpy (out_buf, pyenv_libpath, out_sz - 1);
free (pyenv_libpath);
return 0;
}
return -1;
}
pclose (fp2);
// global
FILE *fp3 = popen ("pyenv global", "r");
if (fp3 == NULL) return -1;
if (fscanf (fp3, "%d.%d", &maj, &min) == 2)
{
pclose (fp3);
char *pyenv_libpath = expand_pyenv_libpath (prefix_path, maj, min);
if (pyenv_libpath != NULL)
{
strncpy (out_buf, pyenv_libpath, out_sz - 1);
free (pyenv_libpath);
return 0;
}
return -1;
}
pclose (fp3);
return -1;
}
static bool init_python (hc_python_lib_t *python)
{
char pythondll_path[PATH_MAX];
python->lib = NULL;
if (getenv ("PYTHON_GIL") == NULL)
putenv ((char *) "PYTHON_GIL=0");
// let's see if we have pyenv, that will save us a lot of guessing...
int saved_stderr = suppress_stderr ();
const int pyenv_rc = resolve_pyenv_libpath (pythondll_path, sizeof (pythondll_path));
restore_stderr (saved_stderr);
if (pyenv_rc == 0)
{
#if defined (_WIN)
python->lib = hc_dlopen (pythondll_path);
#elif defined (__MSYS__)
python->lib = dlopen (pythondll_path, RTLD_NOW | RTLD_GLOBAL);
#elif defined (__APPLE__)
python->lib = dlopen (pythondll_path, RTLD_NOW | RTLD_GLOBAL);
#elif defined (__CYGWIN__)
python->lib = hc_dlopen (pythondll_path);
#else
python->lib = dlopen (pythondll_path, RTLD_NOW | RTLD_GLOBAL);
#endif
}
#define MIN_MAJ 3
#define MAX_MAJ 8
#define MIN_MIN 0
#define MAX_MIN 50
for (int maj = MAX_MAJ; maj >= MIN_MAJ; --maj)
{
if (python->lib != NULL) break;
for (int min = MAX_MIN; min >= MIN_MIN; --min)
{
#if defined (_WIN)
// first try %LocalAppData% default path
char expandedPath[MAX_PATH - 1];
char *libpython_namelocal = NULL;
hc_asprintf (&libpython_namelocal, "%%LocalAppData%%\\Programs\\Python\\Python%d%d\\python%d%dt.dll", maj, min, maj, min);
DWORD len = ExpandEnvironmentStringsA (libpython_namelocal, expandedPath, sizeof (expandedPath));
if (len)
{
python->lib = hc_dlopen (expandedPath);
if (python->lib != NULL)
{
strncpy (pythondll_path, expandedPath, sizeof (pythondll_path) - 1);
hcfree (libpython_namelocal);
break;
}
else
{
hcfree (libpython_namelocal);
};
}
// use %PATH%
char *libpython_namepath = NULL;
hc_asprintf (&libpython_namepath, "python%d%dt.dll", maj, min);
python->lib = hc_dlopen (libpython_namepath);
if (python->lib != NULL)
{
strncpy (pythondll_path, libpython_namepath, sizeof (pythondll_path) - 1);
hcfree (libpython_namepath);
break;
}
else
{
hcfree (libpython_namepath);
};
#elif defined (__MSYS__)
char *libpython_name = NULL;
hc_asprintf (&libpython_name, "msys-python%d.%dt.dll", maj, min);
python->lib = dlopen (libpython_name, RTLD_NOW | RTLD_GLOBAL);
if (python->lib != NULL)
{
strncpy (pythondll_path, libpython_name, sizeof (pythondll_path) - 1);
hcfree (libpython_name);
break;
}
else
{
hcfree (libpython_name);
};
#elif defined (__APPLE__)
char *libpython_name = NULL;
hc_asprintf (&libpython_name, "libpython%d.%dt.dylib", maj, min);
python->lib = dlopen (libpython_name, RTLD_NOW | RTLD_GLOBAL);
if (python->lib != NULL)
{
strncpy (pythondll_path, libpython_name, sizeof (pythondll_path) - 1);
hcfree (libpython_name);
break;
}
else
{
hcfree (libpython_name);
};
#elif defined (__CYGWIN__)
char *libpython_name = NULL;
hc_asprintf (&libpython_name, "python%d%dt.dll", maj, min);
python->lib = hc_dlopen (libpython_name);
if (python->lib != NULL)
{
strncpy (pythondll_path, libpython_name, sizeof (pythondll_path) - 1);
hcfree (libpython_name);
break;
}
else
{
hcfree (libpython_name);
};
#else
char *libpython_name = NULL;
hc_asprintf (&libpython_name, "libpython%d.%dt.so", maj, min);
python->lib = dlopen (libpython_name, RTLD_NOW | RTLD_GLOBAL);
if (python->lib != NULL)
{
strncpy (pythondll_path, libpython_name, sizeof (pythondll_path) - 1);
hcfree (libpython_name);
break;
}
else
{
hcfree (libpython_name);
};
#endif
if (python->lib != NULL) break;
}
if (python->lib != NULL) break;
}
if (python->lib == NULL)
{
fprintf (stderr, "Unable to find suitable Python library for -m 72000.\n\n");
fprintf (stderr, "Most users who encounter this error are just missing the so called 'free-threaded' library support.\n");
fprintf (stderr, "* On Windows, during install, there's an option 'free-threaded' that you need to click, it's just disabled by default.\n");
fprintf (stderr, "* On Linux, use `pyenv` and select a version that ends with a `t` (for instance `3.13t`).\n");
fprintf (stderr, " However, on Linux it's better to use -m 73000 instead. So you probably want to ignore this.\n");
fprintf (stderr, "\n");
return false;
}
else
{
printf ("Loaded python library from: %s\n\n", pythondll_path);
}
#if defined (_WIN)
#else
fprintf (stderr, "Attention!!! The 'free-threaded' python library has some major downsides.\n");
fprintf (stderr, " The main purpose of this module is to give windows users a multithreading option.\n");
fprintf (stderr, " It seems to be a lot slower, and relevant modules such as cffi are incompatibile.\n");
fprintf (stderr, " Since your are on Linux/MacOS we highly recommend to stick to multiprocessing module.\n");
fprintf (stderr, " Maybe 'free-threaded' mode will become more mature in the future.\n");
fprintf (stderr, " For now, we high recommend to stick to -m 73000 instead.\n\n");
#endif
#define HC_LOAD_FUNC_PYTHON(ptr,name,pythonname,type,libname,noerr) \
do { \
ptr->name = (type) hc_dlsym ((ptr)->lib, #pythonname); \
if ((noerr) != -1) { \
if (!(ptr)->name) { \
if ((noerr) == 1) { \
fprintf (stderr, "%s is missing from %s shared library.", #name, #libname); \
return false; \
} \
if ((noerr) != 1) { \
fprintf (stderr, "%s is missing from %s shared library.", #name, #libname); \
return true; \
} \
} \
} \
} while (0)
HC_LOAD_FUNC_PYTHON (python, Py_GetVersion, Py_GetVersion, PYGETVERSION, PYTHON, 1);
const char *version_str = python->Py_GetVersion ();
int major = 0;
int minor = 0;
if (sscanf (version_str, "%d.%d", &major, &minor) != 2)
{
fprintf (stderr, "Python version string is not valid: %s\n", version_str);
return false;
}
if ((major < 3) || (major == 3 && minor < 13))
{
fprintf (stderr, "Python version mismatch: Need at least v3.13\n");
return false;
}
HC_LOAD_FUNC_PYTHON (python, Py_Initialize, Py_Initialize, PY_INITIALIZE, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, Py_Finalize, Py_Finalize, PY_FINALIZE, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, Py_DecRef, Py_DecRef, PY_DECREF, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyBool_FromLong, PyBool_FromLong, PYBOOL_FROMLONG, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyBytes_FromStringAndSize, PyBytes_FromStringAndSize, PYBYTES_FROMSTRINGANDSIZE, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyDict_DelItemString, PyDict_DelItemString, PYDICT_DELITEMSTRING, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyDict_GetItemString, PyDict_GetItemString, PYDICT_GETITEMSTRING, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyDict_New, PyDict_New, PYDICT_NEW, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyDict_SetItemString, PyDict_SetItemString, PYDICT_SETITEMSTRING, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyErr_Print, PyErr_Print, PYERR_PRINT, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyImport_ImportModule, PyImport_ImportModule, PYIMPORT_IMPORTMODULE, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyImport_Import, PyImport_Import, PYIMPORT_IMPORT, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyList_Append, PyList_Append, PYLIST_APPEND, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyList_GetItem, PyList_GetItem, PYLIST_GETITEM, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyList_New, PyList_New, PYLIST_NEW, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyList_SetItem, PyList_SetItem, PYLIST_SETITEM, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyList_Size, PyList_Size, PYLIST_SIZE, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyLong_FromLong, PyLong_FromLong, PYLONG_FROMLONG, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyObject_CallObject, PyObject_CallObject, PYOBJECT_CALLOBJECT, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyObject_GetAttrString, PyObject_GetAttrString, PYOBJECT_GETATTRSTRING, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyTuple_New, PyTuple_New, PYTUPLE_NEW, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyTuple_SetItem, PyTuple_SetItem, PYTUPLE_SETITEM, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyUnicode_AsUTF8, PyUnicode_AsUTF8, PYUNICODE_ASUTF8, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyUnicode_AsUTF8AndSize, PyUnicode_AsUTF8AndSize, PYUNICODE_ASUTF8ANDSIZE, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyUnicode_DecodeFSDefaultAndSize, PyUnicode_DecodeFSDefaultAndSize, PYUNICODE_DECODEFSDEFAULTANDSIZE, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyUnicode_DecodeFSDefault, PyUnicode_DecodeFSDefault, PYUNICODE_DECODEFSDEFAULT, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyUnicode_FromStringAndSize, PyUnicode_FromStringAndSize, PYUNICODE_FROMSTRINGANDSIZE, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyUnicode_FromString, PyUnicode_FromString, PYUNICODE_FROMSTRING, PYTHON, 1);
//HC_LOAD_FUNC_PYTHON (python, PyEval_AcquireLock, PyEval_AcquireLock, PYEVAL_ACQUIRELOCK, PYTHON, 1);
//HC_LOAD_FUNC_PYTHON (python, PyEval_ReleaseLock, PyEval_ReleaseLock, PYEVAL_RELEASELOCK, PYTHON, 1);
//HC_LOAD_FUNC_PYTHON (python, PyThreadState_Swap, PyThreadState_Swap, PYTHREADSTATE_SWAP, PYTHON, 1);
//HC_LOAD_FUNC_PYTHON (python, Py_NewInterpreter, Py_NewInterpreter, PYNEWINTERPRETER, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, Py_EndInterpreter, Py_EndInterpreter, PYENDINTERPRETER, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyGILState_Ensure, PyGILState_Ensure, PYGILSTATE_ENSURE, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyGILState_Release, PyGILState_Release, PYGILSTATE_RELEASE, PYTHON, 1);
//HC_LOAD_FUNC_PYTHON (python, PyEval_AcquireThread, PyEval_AcquireThread, PYEVAL_ACQUIRETHREAD, PYTHON, 1);
//HC_LOAD_FUNC_PYTHON (python, PyEval_ReleaseThread, PyEval_ReleaseThread, PYEVAL_RELEASETHREAD, PYTHON, 1);
//HC_LOAD_FUNC_PYTHON (python, PyThreadState_Clear, PyThreadState_Clear, PYTHREADSTATE_CLEAR, PYTHON, 1);
//HC_LOAD_FUNC_PYTHON (python, PyThreadState_Delete, PyThreadState_Delete, PYTHREADSTATE_DELETE, PYTHON, 1);
//HC_LOAD_FUNC_PYTHON (python, PyThreadState_New, PyThreadState_New, PYTHREADSTATE_NEW, PYTHON, 1);
//HC_LOAD_FUNC_PYTHON (python, PyInterpreterState_Main, PyInterpreterState_Main, PYINTERPRETERSTATE_MAIN, PYTHON, 1);
//HC_LOAD_FUNC_PYTHON (python, PyEval_InitThreads, PyEval_InitThreads, PYEVAL_INITTHREADS, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyEval_SaveThread, PyEval_SaveThread, PYEVAL_SAVETHREAD, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, Py_NewInterpreterFromConfig, Py_NewInterpreterFromConfig, PYNEWINTERPRETERFROMCONFIG, PYTHON, 1);
//HC_LOAD_FUNC_PYTHON (python, Py_ExitStatusException, Py_ExitStatusException, PYEXITSTATUSEXCEPTION, PYTHON, 1);
//HC_LOAD_FUNC_PYTHON (python, Py_InitializeFromConfig, Py_InitializeFromConfig, PYINITIALIZEFROMCONFIG, PYTHON, 1);
HC_LOAD_FUNC_PYTHON (python, PyEval_RestoreThread, PyEval_RestoreThread, PYEVAL_RESTORETHREAD, PYTHON, 1);
return true;
}
static bool units_init (python_interpreter_t *python_interpreter)
{
#if defined (_WIN)
SYSTEM_INFO sysinfo;
GetSystemInfo (&sysinfo);
int num_devices = sysinfo.dwNumberOfProcessors;
#else
int num_devices = sysconf (_SC_NPROCESSORS_ONLN);
#endif
unit_t *units_buf = (unit_t *) hccalloc (num_devices, sizeof (unit_t));
int units_cnt = 0;
for (int i = 0; i < num_devices; i++)
{
unit_t *unit_buf = &units_buf[i];
hc_python_lib_t *python = python_interpreter->python;
unit_buf->unit_info_len = snprintf (unit_buf->unit_info_buf, sizeof (unit_buf->unit_info_buf) - 1, "Python Interpreter (%s)", python->Py_GetVersion ());
unit_buf->unit_info_buf[unit_buf->unit_info_len] = 0;
unit_buf->workitem_count = N_ACCEL;
units_cnt++;
}
python_interpreter->units_buf = units_buf;
python_interpreter->units_cnt = units_cnt;
return true;
}
static void units_term (python_interpreter_t *python_interpreter)
{
unit_t *units_buf = python_interpreter->units_buf;
if (units_buf)
{
hcfree (python_interpreter->units_buf);
}
}
void *platform_init (user_options_t *user_options)
{
python_interpreter_t *python_interpreter = (python_interpreter_t *) hcmalloc (sizeof (python_interpreter_t));
hc_python_lib_t *python = (hc_python_lib_t *) hcmalloc (sizeof (hc_python_lib_t));
python_interpreter->python = python;
if (init_python (python) == false) return NULL;
python->Py_Initialize ();
python_interpreter->thread_state = python->PyEval_SaveThread ();
python_interpreter->source_filename = (user_options->bridge_parameter1) ? user_options->bridge_parameter1 : DEFAULT_SOURCE_FILENAME;
if (units_init (python_interpreter) == false)
{
hcfree (python_interpreter);
return NULL;
}
return python_interpreter;
}
void platform_term (void *platform_context)
{
python_interpreter_t *python_interpreter = platform_context;
if (python_interpreter == NULL) return;
hc_python_lib_t *python = python_interpreter->python;
// python->PyGILState_Ensure ();
python->PyEval_RestoreThread (python_interpreter->thread_state);
python->Py_Finalize ();
units_term (python_interpreter);
hcfree (python_interpreter);
}
bool thread_init (MAYBE_UNUSED void *platform_context, MAYBE_UNUSED hc_device_param_t *device_param, MAYBE_UNUSED hashconfig_t *hashconfig, MAYBE_UNUSED hashes_t *hashes)
{
python_interpreter_t *python_interpreter = platform_context;
const int unit_idx = device_param->bridge_link_device;
unit_t *unit_buf = &python_interpreter->units_buf[unit_idx];
hc_python_lib_t *python = python_interpreter->python;
PyInterpreterConfig config =
{
.use_main_obmalloc = 0,
.allow_fork = 1,
.allow_exec = 1,
.allow_threads = 1,
.allow_daemon_threads = 0,
.check_multi_interp_extensions = 1,
.gil = PyInterpreterConfig_OWN_GIL
};
unit_buf->tstate = NULL;
PyStatus status = python->Py_NewInterpreterFromConfig (&unit_buf->tstate, &config);
if (status.exitcode)
{
python->PyErr_Print ();
return false;
}
PyObject *sys = python->PyImport_ImportModule ("sys");
PyObject *path = python->PyObject_GetAttrString (sys, "path");
python->PyList_Append (path, python->PyUnicode_FromString ("./Python"));
//python->Py_DecRef (path);
//python->Py_DecRef (sys);
PyObject *pName = python->PyUnicode_DecodeFSDefault (python_interpreter->source_filename);
if (pName == NULL)
{
python->PyErr_Print ();
return false;
}
unit_buf->pModule = python->PyImport_Import (pName);
if (unit_buf->pModule == NULL)
{
python->PyErr_Print ();
return false;
}
//python->Py_DecRef (pName);
unit_buf->pFunc_Init = python->PyObject_GetAttrString (unit_buf->pModule, "init");
if (unit_buf->pFunc_Init == NULL)
{
python->PyErr_Print ();
return false;
}
unit_buf->pFunc_Term = python->PyObject_GetAttrString (unit_buf->pModule, "term");
if (unit_buf->pFunc_Term == NULL)
{
python->PyErr_Print ();
return false;
}
unit_buf->pFunc_kernel_loop = python->PyObject_GetAttrString (unit_buf->pModule, "kernel_loop");
if (unit_buf->pFunc_kernel_loop == NULL)
{
python->PyErr_Print ();
return false;
}
// Initialize Context (which also means copy salts because they are part of the context)
unit_buf->pContext = python->PyDict_New ();
if (unit_buf->pContext == NULL)
{
python->PyErr_Print ();
return false;
}
int rc = 0;
rc |= python->PyDict_SetItemString (unit_buf->pContext, "salts_cnt", python->PyLong_FromLong (hashes->salts_cnt));
rc |= python->PyDict_SetItemString (unit_buf->pContext, "salts_size", python->PyLong_FromLong (sizeof (salt_t)));
rc |= python->PyDict_SetItemString (unit_buf->pContext, "salts_buf", python->PyBytes_FromStringAndSize ((const char *) hashes->salts_buf, sizeof (salt_t) * hashes->salts_cnt));
rc |= python->PyDict_SetItemString (unit_buf->pContext, "esalts_cnt", python->PyLong_FromLong (hashes->digests_cnt));
rc |= python->PyDict_SetItemString (unit_buf->pContext, "esalts_size", python->PyLong_FromLong (hashconfig->esalt_size));
rc |= python->PyDict_SetItemString (unit_buf->pContext, "esalts_buf", python->PyBytes_FromStringAndSize ((const char *) hashes->esalts_buf, hashconfig->esalt_size * hashes->digests_cnt));
rc |= python->PyDict_SetItemString (unit_buf->pContext, "st_salts_cnt", python->PyLong_FromLong (1));
rc |= python->PyDict_SetItemString (unit_buf->pContext, "st_salts_size", python->PyLong_FromLong (sizeof (salt_t)));
rc |= python->PyDict_SetItemString (unit_buf->pContext, "st_salts_buf", python->PyBytes_FromStringAndSize ((const char *) hashes->st_salts_buf, sizeof (salt_t) * 1));
rc |= python->PyDict_SetItemString (unit_buf->pContext, "st_esalts_cnt", python->PyLong_FromLong (1));
rc |= python->PyDict_SetItemString (unit_buf->pContext, "st_esalts_size", python->PyLong_FromLong (hashconfig->esalt_size));
rc |= python->PyDict_SetItemString (unit_buf->pContext, "st_esalts_buf", python->PyBytes_FromStringAndSize ((const char *) hashes->st_esalts_buf, hashconfig->esalt_size * 1));
if (rc != 0)
{
python->PyErr_Print ();
return false;
}
PyObject *pArgs = python->PyTuple_New (1);
if (pArgs == NULL)
{
python->PyErr_Print ();
return false;
}
python->PyTuple_SetItem (pArgs, 0, unit_buf->pContext);
python->PyObject_CallObject (unit_buf->pFunc_Init, pArgs);
// for later calls
unit_buf->pArgs = python->PyTuple_New (4);
if (unit_buf->pArgs == NULL)
{
python->PyErr_Print ();
return false;
}
python->PyTuple_SetItem (unit_buf->pArgs, 0, unit_buf->pContext);
python->PyTuple_SetItem (unit_buf->pArgs, 2, python->PyLong_FromLong (0));
python->PyTuple_SetItem (unit_buf->pArgs, 3, python->PyBool_FromLong (false));
return true;
}
void thread_term (MAYBE_UNUSED void *platform_context, MAYBE_UNUSED hc_device_param_t *device_param, MAYBE_UNUSED hashconfig_t *hashconfig, MAYBE_UNUSED hashes_t *hashes)
{
python_interpreter_t *python_interpreter = platform_context;
const int unit_idx = device_param->bridge_link_device;
unit_t *unit_buf = &python_interpreter->units_buf[unit_idx];
hc_python_lib_t *python = python_interpreter->python;
//python->Py_DecRef (python->PyDict_GetItemString (unit_buf->pContext, "salts_cnt"));
//python->Py_DecRef (python->PyDict_GetItemString (unit_buf->pContext, "salts_size"));
//python->Py_DecRef (python->PyDict_GetItemString (unit_buf->pContext, "salts_buf"));
//python->Py_DecRef (python->PyDict_GetItemString (unit_buf->pContext, "esalts_cnt"));
//python->Py_DecRef (python->PyDict_GetItemString (unit_buf->pContext, "esalts_size"));
//python->Py_DecRef (python->PyDict_GetItemString (unit_buf->pContext, "esalts_buf"));
//python->Py_DecRef (python->PyDict_GetItemString (unit_buf->pContext, "st_salts_cnt"));
//python->Py_DecRef (python->PyDict_GetItemString (unit_buf->pContext, "st_salts_size"));
//python->Py_DecRef (python->PyDict_GetItemString (unit_buf->pContext, "st_salts_buf"));
//python->Py_DecRef (python->PyDict_GetItemString (unit_buf->pContext, "st_esalts_cnt"));
//python->Py_DecRef (python->PyDict_GetItemString (unit_buf->pContext, "st_esalts_size"));
//python->Py_DecRef (python->PyDict_GetItemString (unit_buf->pContext, "st_esalts_buf"));
python->PyDict_DelItemString (unit_buf->pContext, "salts_cnt");
python->PyDict_DelItemString (unit_buf->pContext, "salts_size");
python->PyDict_DelItemString (unit_buf->pContext, "salts_buf");
python->PyDict_DelItemString (unit_buf->pContext, "esalts_cnt");
python->PyDict_DelItemString (unit_buf->pContext, "esalts_size");
python->PyDict_DelItemString (unit_buf->pContext, "esalts_buf");
python->PyDict_DelItemString (unit_buf->pContext, "st_salts_cnt");
python->PyDict_DelItemString (unit_buf->pContext, "st_salts_size");
python->PyDict_DelItemString (unit_buf->pContext, "st_salts_buf");
python->PyDict_DelItemString (unit_buf->pContext, "st_esalts_cnt");
python->PyDict_DelItemString (unit_buf->pContext, "st_esalts_size");
python->PyDict_DelItemString (unit_buf->pContext, "st_esalts_buf");
PyObject *pArgs = python->PyTuple_New (1);
if (pArgs == NULL)
{
python->PyErr_Print ();
return;
}
python->PyTuple_SetItem (pArgs, 0, unit_buf->pContext);
python->PyObject_CallObject (unit_buf->pFunc_Term, pArgs);
//python->Py_DecRef (pArgs);
//python->Py_DecRef (unit_buf->pFunc_kernel_loop);
//python->Py_DecRef (unit_buf->pFunc_Term);
//python->Py_DecRef (unit_buf->pFunc_Init);
//python->Py_DecRef (unit_buf->pModule);
//python->Py_DecRef (unit_buf->pContext);
//python->Py_DecRef (unit_buf->pArgs);
python->Py_EndInterpreter (unit_buf->tstate);
}
int get_unit_count (void *platform_context)
{
python_interpreter_t *python_interpreter = platform_context;
return python_interpreter->units_cnt;
}
// we support units of mixed speed, that's why the workitem count is unit specific
int get_workitem_count (void *platform_context, const int unit_idx)
{
python_interpreter_t *python_interpreter = platform_context;
unit_t *unit_buf = &python_interpreter->units_buf[unit_idx];
return unit_buf->workitem_count;
}
char *get_unit_info (void *platform_context, const int unit_idx)
{
python_interpreter_t *python_interpreter = platform_context;
unit_t *unit_buf = &python_interpreter->units_buf[unit_idx];
return unit_buf->unit_info_buf;
}
bool launch_loop (MAYBE_UNUSED void *platform_context, MAYBE_UNUSED hc_device_param_t *device_param, MAYBE_UNUSED hashconfig_t *hashconfig, MAYBE_UNUSED hashes_t *hashes, MAYBE_UNUSED const u32 salt_pos, MAYBE_UNUSED const u64 pws_cnt)
{
python_interpreter_t *python_interpreter = platform_context;
const int unit_idx = device_param->bridge_link_device;
unit_t *unit_buf = &python_interpreter->units_buf[unit_idx];
hc_python_lib_t *python = python_interpreter->python;
generic_io_tmp_t *generic_io_tmp = (generic_io_tmp_t *) device_param->h_tmps;
PyObject *pws = python->PyList_New (pws_cnt);
if (pws == NULL)
{
python->PyErr_Print ();
return false;
}
for (u64 i = 0; i < pws_cnt; i++)
{
PyObject *pw = python->PyBytes_FromStringAndSize ((char *) generic_io_tmp->pw_buf, generic_io_tmp->pw_len);
if (pw == NULL) return false;
python->PyList_SetItem (pws, i, pw);
generic_io_tmp++;
}
python->PyTuple_SetItem (unit_buf->pArgs, 1, pws);
python->PyTuple_SetItem (unit_buf->pArgs, 2, python->PyLong_FromLong (salt_pos));
if (hashes->salts_buf == hashes->st_salts_buf)
{
python->PyTuple_SetItem (unit_buf->pArgs, 3, python->PyBool_FromLong (true));
}
else
{
python->PyTuple_SetItem (unit_buf->pArgs, 3, python->PyBool_FromLong (false));
}
PyObject *pReturn = python->PyObject_CallObject (unit_buf->pFunc_kernel_loop, unit_buf->pArgs);
if (pReturn == NULL)
{
python->PyErr_Print ();
return false;
}
//python->Py_DecRef (pws);
Py_ssize_t retsz = python->PyList_Size (pReturn);
if (retsz != (Py_ssize_t) pws_cnt) return false;
generic_io_tmp = (generic_io_tmp_t *) device_param->h_tmps;
for (Py_ssize_t i = 0; i < retsz; i++)
{
PyObject *hash = python->PyList_GetItem (pReturn, i);
Py_ssize_t len;
const char *s = python->PyUnicode_AsUTF8AndSize (hash, &len);
if (s)
{
memcpy (generic_io_tmp->out_buf, s, len);
generic_io_tmp->out_len = len;
}
//python->Py_DecRef (hash);
generic_io_tmp++;
}
//python->Py_DecRef (pReturn);
return true;
}
const char *st_update_hash (MAYBE_UNUSED void *platform_context)
{
python_interpreter_t *python_interpreter = platform_context;
hc_python_lib_t *python = python_interpreter->python;
python->PyEval_RestoreThread (python_interpreter->thread_state);
PyObject *sys = python->PyImport_ImportModule ("sys");
PyObject *path = python->PyObject_GetAttrString (sys, "path");
python->PyList_Append (path, python->PyUnicode_FromString ("./Python"));
//python->Py_DecRef (path);
//python->Py_DecRef (sys);
PyObject *pName = python->PyUnicode_DecodeFSDefault (python_interpreter->source_filename);
if (pName == NULL)
{
python->PyErr_Print ();
python_interpreter->thread_state = python->PyEval_SaveThread ();
return false;
}
PyObject *pModule = python->PyImport_Import (pName);
if (pModule == NULL)
{
python->PyErr_Print ();
python_interpreter->thread_state = python->PyEval_SaveThread ();
return false;
}
PyObject *constant = python->PyObject_GetAttrString (pModule, "ST_HASH");
if (constant == NULL)
{
python_interpreter->thread_state = python->PyEval_SaveThread ();
return NULL;
}
const char *s = python->PyUnicode_AsUTF8 (constant);
python_interpreter->thread_state = python->PyEval_SaveThread ();
return s;
}
const char *st_update_pass (MAYBE_UNUSED void *platform_context)
{
python_interpreter_t *python_interpreter = platform_context;
hc_python_lib_t *python = python_interpreter->python;
python->PyEval_RestoreThread (python_interpreter->thread_state);
PyObject *sys = python->PyImport_ImportModule ("sys");
PyObject *path = python->PyObject_GetAttrString (sys, "path");
python->PyList_Append (path, python->PyUnicode_FromString ("./Python"));
//python->Py_DecRef (path);
//python->Py_DecRef (sys);
PyObject *pName = python->PyUnicode_DecodeFSDefault (python_interpreter->source_filename);
if (pName == NULL)
{
python->PyErr_Print ();
python_interpreter->thread_state = python->PyEval_SaveThread ();
return false;
}
PyObject *pModule = python->PyImport_Import (pName);
if (pModule == NULL)
{
python->PyErr_Print ();
python_interpreter->thread_state = python->PyEval_SaveThread ();
return false;
}
PyObject *constant = python->PyObject_GetAttrString (pModule, "ST_PASS");
if (constant == NULL)
{
python_interpreter->thread_state = python->PyEval_SaveThread ();
return NULL;
}
const char *s = python->PyUnicode_AsUTF8 (constant);
python_interpreter->thread_state = python->PyEval_SaveThread ();
return s;
}
void bridge_init (bridge_ctx_t *bridge_ctx)
{
bridge_ctx->bridge_context_size = BRIDGE_CONTEXT_SIZE_CURRENT;
bridge_ctx->bridge_interface_version = BRIDGE_INTERFACE_VERSION_CURRENT;
bridge_ctx->platform_init = platform_init;
bridge_ctx->platform_term = platform_term;
bridge_ctx->get_unit_count = get_unit_count;
bridge_ctx->get_unit_info = get_unit_info;
bridge_ctx->get_workitem_count = get_workitem_count;
bridge_ctx->thread_init = thread_init;
bridge_ctx->thread_term = thread_term;
bridge_ctx->salt_prepare = BRIDGE_DEFAULT;
bridge_ctx->salt_destroy = BRIDGE_DEFAULT;
bridge_ctx->launch_loop = launch_loop;
bridge_ctx->launch_loop2 = BRIDGE_DEFAULT;
bridge_ctx->st_update_hash = st_update_hash;
bridge_ctx->st_update_pass = st_update_pass;
}