|
1 | 1 | #include <Python.h> |
2 | 2 | #include <openssl/conf.h> |
3 | 3 | #include <openssl/bn.h> |
| 4 | +#include <openssl/rand.h> |
| 5 | + |
| 6 | +// By default, use 32 BYTE of randomness |
| 7 | +#define RAND_LEN 32 |
4 | 8 |
|
5 | 9 | // Generate a safe prime using OpenSSL |
6 | 10 | static PyObject * gensafeprime_generate(PyObject *self, PyObject *args) { |
@@ -47,5 +51,73 @@ static PyMethodDef GenPrime_Methods[] = { |
47 | 51 | PyMODINIT_FUNC |
48 | 52 | initgensafeprime(void) |
49 | 53 | { |
50 | | - (void) Py_InitModule("gensafeprime", GenPrime_Methods); |
| 54 | + PyObject *modname, *mod, *mdict, *func, *args, *rslt; |
| 55 | + char * rnd; |
| 56 | + // int i; |
| 57 | + |
| 58 | + // first, standard initialization |
| 59 | + if (!Py_InitModule("gensafeprime", GenPrime_Methods)) { |
| 60 | + PyErr_SetString(PyExc_RuntimeError, "cannot init module"); |
| 61 | + return; |
| 62 | + } |
| 63 | + |
| 64 | + // seed the random number generator of OpenSSL using os.urandom(RAND_LEN) |
| 65 | + // According to https://docs.python.org/2.7/library/random.html os.urandom |
| 66 | + // generates secure random numbers for cryptographic applications. |
| 67 | + |
| 68 | + // Code based on |
| 69 | + // https://www.daniweb.com/software-development/python/threads/31682/calling-python-function-from-cc- |
| 70 | + // but has been heavily modified. |
| 71 | + |
| 72 | + // Import os and get a reference to os.urandom |
| 73 | + modname = PyString_FromString("os"); |
| 74 | + mod = PyImport_Import(modname); |
| 75 | + if (mod) { |
| 76 | + mdict = PyModule_GetDict(mod); |
| 77 | + func = PyDict_GetItemString(mdict, "urandom"); |
| 78 | + if (func) { |
| 79 | + // Call urandom(RAND_LEN) |
| 80 | + if (PyCallable_Check(func)) { |
| 81 | + args = Py_BuildValue("(i)", RAND_LEN); |
| 82 | + rslt = PyObject_CallObject(func, args); |
| 83 | + Py_XDECREF(args); |
| 84 | + // Check the result, when the call failed, rslt will be NULL |
| 85 | + if (rslt) { |
| 86 | + // Get random bytes as char* representation |
| 87 | + rnd = PyString_AsString(rslt); |
| 88 | + if (rnd) { |
| 89 | + // Check that really RAND_LEN bytes have been returned |
| 90 | + if (PyString_Size(rslt) == RAND_LEN) { |
| 91 | + // rnd should now contain RAND_LEN securely random characters |
| 92 | + // terminated by a 0 byte, pass it to OpenSSL RAND_seed |
| 93 | + RAND_seed(rnd, RAND_LEN); |
| 94 | + |
| 95 | + // DEBUG code, uncomment to see the seed |
| 96 | + //printf("prng has been seeded with"); |
| 97 | + //for (i = 0; i < RAND_LEN; i++) { |
| 98 | + // printf(" %02x", 0xff & rnd[i]); |
| 99 | + //} |
| 100 | + //printf("\n"); |
| 101 | + } else { |
| 102 | + PyErr_SetString(PyExc_RuntimeError, "wrong length of random data"); |
| 103 | + } |
| 104 | + } else { |
| 105 | + PyErr_SetString(PyExc_RuntimeError, "parsing result failed, rnd == NULL"); |
| 106 | + } |
| 107 | + Py_XDECREF(rslt); |
| 108 | + } else { |
| 109 | + PyErr_SetString(PyExc_RuntimeError, "call to urandom returned NULL pointer"); |
| 110 | + } |
| 111 | + } else { |
| 112 | + PyErr_SetString(PyExc_RuntimeError, "urandom not callable"); |
| 113 | + } |
| 114 | + } else { |
| 115 | + PyErr_SetString(PyExc_RuntimeError, "could not get reference to os.urandom"); |
| 116 | + } |
| 117 | + Py_XDECREF(mod); |
| 118 | + } else { |
| 119 | + PyErr_SetString(PyExc_RuntimeError, "could not import os"); |
| 120 | + } |
| 121 | + Py_XDECREF(modname); |
| 122 | + |
51 | 123 | } |
0 commit comments