blob: 712ad569dde0b5a06851e8a12631093de30d29ad [file] [log] [blame]
Jean-Paul Calderone897bc252008-02-18 20:50:23 -05001/*
2 * rand.c
3 *
Jean-Paul Calderone8671c852011-03-02 19:26:20 -05004 * Copyright (C) AB Strakt
5 * See LICENSE file for details.
Jean-Paul Calderone897bc252008-02-18 20:50:23 -05006 *
7 * PRNG management routines, thin wrappers.
8 * See the file RATIONALE for a short explanation of why this module was written.
9 *
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050010 */
11#include <Python.h>
12
13/*
14 * In order to get the RAND_screen definition from the rand.h
15 * WIN32 or WINDOWS needs to be defined, otherwise we get a
16 * warning.
17 */
Jean-Paul Calderone7ef4ee22008-12-29 16:45:27 -050018#ifdef MS_WINDOWS
19# ifndef WIN32
20# define WIN32
21# endif
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050022#endif
23#include <openssl/rand.h>
Rick Deanb84bdcf2009-07-08 10:54:54 -050024#include "../util.h"
25
26PyObject *rand_Error;
27
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050028static char rand_doc[] = "\n\
29PRNG management routines, thin wrappers.\n\
30See the file RATIONALE for a short explanation of why this module was written.\n\
31";
32
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050033static char rand_add_doc[] = "\n\
34Add data with a given entropy to the PRNG\n\
35\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +090036:param buffer: Buffer with random data\n\
37:param entropy: The entropy (in bytes) measurement of the buffer\n\
38:return: None\n\
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050039";
40
41static PyObject *
42rand_add(PyObject *spam, PyObject *args)
43{
44 char *buf;
45 int size;
46 double entropy;
47
Jean-Paul Calderone22cb3122010-10-02 15:55:22 -040048 if (!PyArg_ParseTuple(args, BYTESTRING_FMT "#d:add", &buf, &size, &entropy))
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050049 return NULL;
50
51 RAND_add(buf, size, entropy);
52
53 Py_INCREF(Py_None);
54 return Py_None;
55}
56
57static char rand_seed_doc[] = "\n\
58Alias for rand_add, with entropy equal to length\n\
59\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +090060:param buffer: Buffer with random data\n\
61:return: None\n\
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050062";
63
64static PyObject *
65rand_seed(PyObject *spam, PyObject *args)
66{
67 char *buf;
68 int size;
69
Jean-Paul Calderone22cb3122010-10-02 15:55:22 -040070 if (!PyArg_ParseTuple(args, BYTESTRING_FMT "#:seed", &buf, &size))
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050071 return NULL;
72
73 RAND_seed(buf, size);
74
75 Py_INCREF(Py_None);
76 return Py_None;
77}
78
79static char rand_status_doc[] = "\n\
80Retrieve the status of the PRNG\n\
81\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +090082:return: True if the PRNG is seeded enough, false otherwise\n\
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050083";
84
85static PyObject *
86rand_status(PyObject *spam, PyObject *args)
87{
88 if (!PyArg_ParseTuple(args, ":status"))
89 return NULL;
90
Jean-Paul Calderonef223c482010-08-11 19:54:32 -040091 return PyLong_FromLong((long)RAND_status());
Jean-Paul Calderone897bc252008-02-18 20:50:23 -050092}
93
94#ifdef MS_WINDOWS
95static char rand_screen_doc[] = "\n\
96Add the current contents of the screen to the PRNG state. Availability:\n\
97Windows.\n\
98\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +090099:return: None\n\
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500100";
101
102static PyObject *
103rand_screen(PyObject *spam, PyObject *args)
104{
105 if (!PyArg_ParseTuple(args, ":screen"))
106 return NULL;
107
108 RAND_screen();
109 Py_INCREF(Py_None);
110 return Py_None;
111}
112#endif
113
114static char rand_egd_doc[] = "\n\
115Query an entropy gathering daemon (EGD) for random data and add it to the\n\
116PRNG. I haven't found any problems when the socket is missing, the function\n\
117just returns 0.\n\
118\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900119:param path: The path to the EGD socket\n\
120:param bytes: (optional) The number of bytes to read, default is 255\n\
121:returns: The number of bytes read (NB: a value of 0 isn't necessarily an\n\
Jean-Paul Calderone54bcc832009-05-27 14:06:48 -0400122 error, check rand.status())\n\
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500123";
124
125static PyObject *
126rand_egd(PyObject *spam, PyObject *args)
127{
128 char *path;
129 int bytes = 255;
130
131 if (!PyArg_ParseTuple(args, "s|i:egd", &path, &bytes))
132 return NULL;
133
Jean-Paul Calderonef223c482010-08-11 19:54:32 -0400134 return PyLong_FromLong((long)RAND_egd_bytes(path, bytes));
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500135}
136
137static char rand_cleanup_doc[] = "\n\
138Erase the memory used by the PRNG.\n\
139\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900140:return: None\n\
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500141";
142
143static PyObject *
144rand_cleanup(PyObject *spam, PyObject *args)
145{
146 if (!PyArg_ParseTuple(args, ":cleanup"))
147 return NULL;
148
149 RAND_cleanup();
150
151 Py_INCREF(Py_None);
152 return Py_None;
153}
154
155static char rand_load_file_doc[] = "\n\
156Seed the PRNG with data from a file\n\
157\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900158:param filename: The file to read data from\n\
159:param maxbytes: (optional) The number of bytes to read, default is\n\
Jean-Paul Calderone54bcc832009-05-27 14:06:48 -0400160 to read the entire file\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900161:return: The number of bytes read\n\
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500162";
163
164static PyObject *
165rand_load_file(PyObject *spam, PyObject *args)
166{
167 char *filename;
168 int maxbytes = -1;
169
170 if (!PyArg_ParseTuple(args, "s|i:load_file", &filename, &maxbytes))
171 return NULL;
172
Jean-Paul Calderonef223c482010-08-11 19:54:32 -0400173 return PyLong_FromLong((long)RAND_load_file(filename, maxbytes));
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500174}
175
176static char rand_write_file_doc[] = "\n\
177Save PRNG state to a file\n\
178\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900179:param filename: The file to write data to\n\
180:return: The number of bytes written\n\
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500181";
182
183static PyObject *
184rand_write_file(PyObject *spam, PyObject *args)
185{
186 char *filename;
187
188 if (!PyArg_ParseTuple(args, "s:write_file", &filename))
189 return NULL;
190
Jean-Paul Calderonef223c482010-08-11 19:54:32 -0400191 return PyLong_FromLong((long)RAND_write_file(filename));
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500192}
193
Rick Dean433dc642009-07-07 13:11:55 -0500194static char rand_bytes_doc[] = "\n\
195Get some randomm bytes as a string.\n\
196\n\
Jonathan Ballet78b92a22011-07-16 08:07:26 +0900197:param num_bytes: The number of bytes to fetch\n\
198:return: A string of random bytes\n\
Rick Dean433dc642009-07-07 13:11:55 -0500199";
200
Jean-Paul Calderoneb1753662010-07-30 17:40:42 -0400201#if PY_VERSION_HEX < 0x02050000
202#define Py_ssize_t int
203#define PY_SSIZE_FMT "i"
204#else
205#define PY_SSIZE_FMT "n"
206#endif
207
Rick Dean433dc642009-07-07 13:11:55 -0500208static PyObject *
Jean-Paul Calderoneb1753662010-07-30 17:40:42 -0400209rand_bytes(PyObject *spam, PyObject *args, PyObject *keywds) {
210 Py_ssize_t num_bytes;
Rick Dean433dc642009-07-07 13:11:55 -0500211 static char *kwlist[] = {"num_bytes", NULL};
212 char *buf;
Rick Deanb84bdcf2009-07-08 10:54:54 -0500213 unsigned int rc;
214 PyObject *obj = NULL;
Rick Dean433dc642009-07-07 13:11:55 -0500215
Jean-Paul Calderoneb1753662010-07-30 17:40:42 -0400216 if (!PyArg_ParseTupleAndKeywords(
217 args, keywds, PY_SSIZE_FMT ":bytes", kwlist, &num_bytes)) {
Rick Dean433dc642009-07-07 13:11:55 -0500218 return NULL;
Jean-Paul Calderoneb1753662010-07-30 17:40:42 -0400219 }
220
Rick Dean433dc642009-07-07 13:11:55 -0500221 if(num_bytes < 0) {
222 PyErr_SetString(PyExc_ValueError, "num_bytes must not be negative");
223 return NULL;
224 }
225 buf = malloc(num_bytes);
226 if (buf == NULL) /* out of memory */
227 return NULL;
Rick Deanb84bdcf2009-07-08 10:54:54 -0500228 rc = RAND_bytes((unsigned char *) buf, num_bytes);
229 if(rc != 1) { /* if unsuccessful */
Rick Deand369c932009-07-08 11:48:33 -0500230 exception_from_error_queue(rand_Error);
Rick Deanb84bdcf2009-07-08 10:54:54 -0500231 goto done;
232 }
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -0400233 obj = PyBytes_FromStringAndSize(buf, (unsigned) num_bytes);
Rick Deanb84bdcf2009-07-08 10:54:54 -0500234 done:
Rick Dean433dc642009-07-07 13:11:55 -0500235 free(buf);
236 return obj;
237}
238
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500239
240/* Methods in the OpenSSL.rand module */
241static PyMethodDef rand_methods[] = {
242 { "add", (PyCFunction)rand_add, METH_VARARGS, rand_add_doc },
243 { "seed", (PyCFunction)rand_seed, METH_VARARGS, rand_seed_doc },
244 { "status", (PyCFunction)rand_status, METH_VARARGS, rand_status_doc },
245#ifdef MS_WINDOWS
246 { "screen", (PyCFunction)rand_screen, METH_VARARGS, rand_screen_doc },
247#endif
248 { "egd", (PyCFunction)rand_egd, METH_VARARGS, rand_egd_doc },
249 { "cleanup", (PyCFunction)rand_cleanup, METH_VARARGS, rand_cleanup_doc },
250 { "load_file", (PyCFunction)rand_load_file, METH_VARARGS, rand_load_file_doc },
251 { "write_file",(PyCFunction)rand_write_file, METH_VARARGS, rand_write_file_doc },
Rick Dean433dc642009-07-07 13:11:55 -0500252 { "bytes", (PyCFunction)rand_bytes, METH_VARARGS|METH_KEYWORDS, rand_bytes_doc },
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500253 { NULL, NULL }
254};
255
256
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -0400257#ifdef PY3
258static struct PyModuleDef randmodule = {
259 PyModuleDef_HEAD_INIT,
260 "rand",
261 rand_doc,
262 -1,
263 rand_methods
264};
265#endif
266
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500267/*
268 * Initialize the rand sub module
269 *
270 * Arguments: None
271 * Returns: None
272 */
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -0400273PyOpenSSL_MODINIT(rand) {
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500274 PyObject *module;
275
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -0400276#ifdef PY3
277 module = PyModule_Create(&randmodule);
278#else
279 module = Py_InitModule3("rand", rand_methods, rand_doc);
280#endif
281 if (module == NULL) {
Jean-Paul Calderonedfcebfc2010-08-11 23:55:22 -0400282 PyOpenSSL_MODRETURN(NULL);
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -0400283 }
284
285 rand_Error = PyErr_NewException("OpenSSL.rand.Error", NULL, NULL);
286
287 if (rand_Error == NULL) {
288 goto error;
289 }
290
Jean-Paul Calderoneaed23582011-03-12 22:45:02 -0500291 /* PyModule_AddObject steals a reference.
292 */
Jean-Paul Calderone026f6642011-04-20 18:59:33 -0400293 Py_INCREF(rand_Error);
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -0400294 if (PyModule_AddObject(module, "Error", rand_Error) != 0) {
295 goto error;
296 }
297
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500298 ERR_load_RAND_strings();
299
Jean-Paul Calderonedfcebfc2010-08-11 23:55:22 -0400300 PyOpenSSL_MODRETURN(module);
Rick Deanb84bdcf2009-07-08 10:54:54 -0500301
Jean-Paul Calderoneef853eb2010-08-10 19:47:06 -0400302error:
Jean-Paul Calderonedfcebfc2010-08-11 23:55:22 -0400303 PyOpenSSL_MODRETURN(NULL);
Rick Deanb84bdcf2009-07-08 10:54:54 -0500304 ;
Jean-Paul Calderone897bc252008-02-18 20:50:23 -0500305}
306