summaryrefslogtreecommitdiffstats
path: root/src/lib/tlslite/utils/entropy.c
blob: c627794d2da21f10aae56046c3cf584193d46769 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
#include "Python.h"


#ifdef MS_WINDOWS

/* The following #define is not needed on VC6 with the Platform SDK, and it
may not be needed on VC7, I'm not sure.  I don't think it hurts anything.*/
#define _WIN32_WINNT 0x0400

#include <windows.h>


typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTA)(HCRYPTPROV *phProv,\
              LPCSTR pszContainer, LPCSTR pszProvider, DWORD dwProvType,\
              DWORD dwFlags );
typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen,\
              BYTE *pbBuffer );
typedef BOOL (WINAPI *CRYPTRELEASECONTEXT)(HCRYPTPROV hProv,\
              DWORD dwFlags);


static PyObject* entropy(PyObject *self, PyObject *args)
{
    int howMany = 0;
    HINSTANCE hAdvAPI32 = NULL;
    CRYPTACQUIRECONTEXTA pCryptAcquireContextA = NULL;
    CRYPTGENRANDOM pCryptGenRandom = NULL;
    CRYPTRELEASECONTEXT pCryptReleaseContext = NULL;
    HCRYPTPROV hCryptProv = 0;
    unsigned char* bytes = NULL;
    PyObject* returnVal = NULL;


    /* Read arguments */
    if (!PyArg_ParseTuple(args, "i", &howMany))
        return(NULL);

	/* Obtain handle to the DLL containing CryptoAPI
	   This should not fail	*/
	if( (hAdvAPI32 = GetModuleHandle("advapi32.dll")) == NULL) {
        PyErr_Format(PyExc_SystemError,
            "Advapi32.dll not found");
        return NULL;
	}

	/* Obtain pointers to the CryptoAPI functions
	   This will fail on some early version of Win95 */
	pCryptAcquireContextA = (CRYPTACQUIRECONTEXTA)GetProcAddress(hAdvAPI32,\
	                        "CryptAcquireContextA");
	pCryptGenRandom = (CRYPTGENRANDOM)GetProcAddress(hAdvAPI32,\
	                  "CryptGenRandom");
	pCryptReleaseContext = (CRYPTRELEASECONTEXT) GetProcAddress(hAdvAPI32,\
	                       "CryptReleaseContext");
	if (pCryptAcquireContextA == NULL || pCryptGenRandom == NULL ||
	                                     pCryptReleaseContext == NULL) {
        PyErr_Format(PyExc_NotImplementedError,
            "CryptoAPI not available on this version of Windows");
        return NULL;
	}

    /* Allocate bytes */
    if ((bytes = (unsigned char*)PyMem_Malloc(howMany)) == NULL)
        return PyErr_NoMemory();


    /* Acquire context */
    if(!pCryptAcquireContextA(&hCryptProv, NULL, NULL, PROV_RSA_FULL,
                            CRYPT_VERIFYCONTEXT)) {
        PyErr_Format(PyExc_SystemError,
                     "CryptAcquireContext failed, error %d", GetLastError());
        PyMem_Free(bytes);
        return NULL;
    }

    /* Get random data */
    if(!pCryptGenRandom(hCryptProv, howMany, bytes)) {
        PyErr_Format(PyExc_SystemError,
                     "CryptGenRandom failed, error %d", GetLastError());
        PyMem_Free(bytes);
        CryptReleaseContext(hCryptProv, 0);
        return NULL;
    }

    /* Build return value */
    returnVal = Py_BuildValue("s#", bytes, howMany);
    PyMem_Free(bytes);

    /* Release context */
    if (!pCryptReleaseContext(hCryptProv, 0)) {
        PyErr_Format(PyExc_SystemError,
                     "CryptReleaseContext failed, error %d", GetLastError());
        return NULL;
    }

    return returnVal;
}

#elif defined(HAVE_UNISTD_H) && defined(HAVE_FCNTL_H)

#include <unistd.h>
#include <fcntl.h>

static PyObject* entropy(PyObject *self, PyObject *args)
{
    int howMany;
    int fd;
    unsigned char* bytes = NULL;
    PyObject* returnVal = NULL;


    /* Read arguments */
    if (!PyArg_ParseTuple(args, "i", &howMany))
        return(NULL);

    /* Allocate bytes */
    if ((bytes = (unsigned char*)PyMem_Malloc(howMany)) == NULL)
        return PyErr_NoMemory();

    /* Open device */
    if ((fd = open("/dev/urandom", O_RDONLY, 0)) == -1) {
        PyErr_Format(PyExc_NotImplementedError,
            "No entropy source found");
        PyMem_Free(bytes);
        return NULL;
    }

    /* Get random data */
    if (read(fd, bytes, howMany) < howMany) {
        PyErr_Format(PyExc_SystemError,
            "Reading from /dev/urandom failed");
        PyMem_Free(bytes);
        close(fd);
        return NULL;
    }

    /* Build return value */
    returnVal = Py_BuildValue("s#", bytes, howMany);
    PyMem_Free(bytes);

    /* Close device */
    close(fd);

    return returnVal;
}

#else

static PyObject* entropy(PyObject *self, PyObject *args)
{
    PyErr_Format(PyExc_NotImplementedError,
            "Function not supported");
    return NULL;
}

#endif



/* List of functions exported by this module */

static struct PyMethodDef entropy_functions[] = {
    {"entropy", (PyCFunction)entropy, METH_VARARGS, "Return a string of random bytes produced by a platform-specific\nentropy source."},
    {NULL,  NULL}        /* Sentinel */
};


/* Initialize this module. */

PyMODINIT_FUNC initentropy(void)
{
    Py_InitModule("entropy", entropy_functions);
}