3 * Uses Windows CryptoAPI CryptGenRandom to get random bytes.
4 * The "new" method returns an object, whose "get_bytes" method
5 * can be called repeatedly to get random bytes, seeded by the
6 * OS. See the description in the comment at the end.
8 * If you have the Intel Security Driver header files (icsp4ms.h)
9 * for their hardware random number generator in the 810 and 820 chipsets,
10 * then define HAVE_INTEL_RNG.
12 * Distribute and use freely; there are no restrictions on further
13 * dissemination and usage except those imposed by the laws of your
14 * country of residence. This software is provided "as is" without
15 * warranty of fitness for use or suitability for any purpose, express
16 * or implied. Use at your own risk or not at all.
20 /* Author: Mark Moraes */
26 #define _WIN32_WINNT 0x400
35 # define PROV_INTEL_SEC 22
36 # define INTEL_DEF_PROV "Intel Hardware Cryptographic Service Provider"
39 /* To-Do: store provider name and type for print/repr? */
46 staticforward PyTypeObject WRtype;
48 #define is_WRobject(v) ((v)->ob_type == &WRtype)
51 WRdealloc(PyObject *ptr)
53 WRobject *o = (WRobject *)ptr;
55 if (! is_WRobject(ptr)) {
56 PyErr_Format(PyExc_TypeError,
57 "WinRandom trying to dealloc non-WinRandom object");
60 if (! CryptReleaseContext(o->hcp, 0)) {
61 PyErr_Format(PyExc_SystemError,
62 "CryptReleaseContext failed, error 0x%x",
66 /* Overwrite the contents of the object */
71 static char winrandom__doc__[] =
72 "new([provider], [provtype]): Returns an object handle to Windows\n\
73 CryptoAPI that can be used to access a cryptographically strong\n\
74 pseudo-random generator that uses OS-gathered entropy.\n\
75 Provider is a string that specifies the Cryptographic Service Provider\n\
76 to use, default is the default OS CSP.\n\
77 provtype is an integer specifying the provider type to use, default\n\
78 is 1 (PROV_RSA_FULL)";
80 static char WR_get_bytes__doc__[] =
81 "get_bytes(nbytes, [userdata]]): Returns nbytes of random data\n\
82 from Windows CryptGenRandom.\n\
83 userdata is a string with any additional entropic data that the\n\
84 user wishes to provide.";
87 winrandom_new(PyObject *self, PyObject *args, PyObject *kwdict)
91 char *provname = NULL;
92 int provtype = PROV_RSA_FULL;
93 static char *kwlist[] = { "provider", "provtype", NULL};
95 if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|si", kwlist,
96 &provname, &provtype)) {
99 if (! CryptAcquireContext(&hcp, NULL, (LPCTSTR) provname,
100 (DWORD) provtype, 0)) {
101 PyErr_Format(PyExc_SystemError,
102 "CryptAcquireContext for provider \"%s\" type %i failed, error 0x%x",
103 provname? provname : "(null)", provtype,
107 res = PyObject_New(WRobject, &WRtype);
113 WR_get_bytes(WRobject *self, PyObject *args)
116 int n, nbytes, len = 0;
118 char *buf, *str = NULL;
120 if (! is_WRobject(self)) {
121 PyErr_Format(PyExc_TypeError,
122 "WinRandom trying to get_bytes with non-WinRandom object");
125 if (!PyArg_ParseTuple(args, "i|s#", &n, &str, &len)) {
129 PyErr_SetString(PyExc_ValueError, "nbytes must be positive number");
132 /* Just in case char != BYTE, or userdata > desired result */
133 nbytes = (((n > len) ? n : len) * sizeof(char)) / sizeof(BYTE) + 1;
134 if ((buf = (char *) PyMem_Malloc(nbytes)) == NULL)
135 return PyErr_NoMemory();
137 memcpy(buf, str, len);
139 * if userdata > desired result, we end up getting
140 * more bytes than we really needed to return. No
141 * easy way to avoid that: we prefer that
142 * CryptGenRandom does the distillation of userdata
143 * down to entropy, rather than trying to do it
144 * ourselves. Since the extra bytes presumably come
145 * from an RC4 stream, they should be relatively
148 if (! CryptGenRandom(self->hcp, (DWORD) nbytes, (BYTE *) buf)) {
149 PyErr_Format(PyExc_SystemError,
150 "CryptGenRandom failed, error 0x%x",
155 res = PyString_FromStringAndSize(buf, n);
160 /* WinRandom object methods */
162 static PyMethodDef WRmethods[] =
164 {"get_bytes", (PyCFunction) WR_get_bytes, METH_VARARGS,
165 WR_get_bytes__doc__},
166 {NULL, NULL} /* sentinel */
169 /* winrandom module methods */
171 static PyMethodDef WR_mod_methods[] = {
172 {"new", (PyCFunction) winrandom_new, METH_VARARGS|METH_KEYWORDS,
174 {NULL, NULL} /* Sentinel */
179 WRgetattr(PyObject *s, char *name)
181 WRobject *self = (WRobject*)s;
182 if (! is_WRobject(self)) {
183 PyErr_Format(PyExc_TypeError,
184 "WinRandom trying to getattr with non-WinRandom object");
187 if (strcmp(name, "hcp") == 0)
188 return PyInt_FromLong((long) self->hcp);
189 return Py_FindMethod(WRmethods, (PyObject *) self, name);
192 static PyTypeObject WRtype =
194 PyObject_HEAD_INIT(NULL)
196 "winrandom.WinRandom", /*tp_name*/
197 sizeof(WRobject), /*tp_size*/
200 WRdealloc, /*tp_dealloc*/
202 WRgetattr, /*tp_getattr*/
209 WRtype.ob_type = &PyType_Type;
210 m = Py_InitModule("winrandom", WR_mod_methods);
212 /* define Windows CSP Provider Types */
214 PyModule_AddIntConstant(m, "PROV_RSA_FULL", PROV_RSA_FULL);
217 PyModule_AddIntConstant(m, "PROV_RSA_SIG", PROV_RSA_SIG);
220 PyModule_AddIntConstant(m, "PROV_DSS", PROV_DSS);
223 PyModule_AddIntConstant(m, "PROV_FORTEZZA", PROV_FORTEZZA);
225 #ifdef PROV_MS_EXCHANGE
226 PyModule_AddIntConstant(m, "PROV_MS_EXCHANGE", PROV_MS_EXCHANGE);
229 PyModule_AddIntConstant(m, "PROV_SSL", PROV_SSL);
231 #ifdef PROV_RSA_SCHANNEL
232 PyModule_AddIntConstant(m, "PROV_RSA_SCHANNEL", PROV_RSA_SCHANNEL);
235 PyModule_AddIntConstant(m, "PROV_DSS_DH", PROV_DSS_DH);
237 #ifdef PROV_EC_ECDSA_SIG
238 PyModule_AddIntConstant(m, "PROV_EC_ECDSA_SIG", PROV_EC_ECDSA_SIG);
240 #ifdef PROV_EC_ECNRA_SIG
241 PyModule_AddIntConstant(m, "PROV_EC_ECNRA_SIG", PROV_EC_ECNRA_SIG);
243 #ifdef PROV_EC_ECDSA_FULL
244 PyModule_AddIntConstant(m, "PROV_EC_ECDSA_FULL", PROV_EC_ECDSA_FULL);
246 #ifdef PROV_EC_ECNRA_FULL
247 PyModule_AddIntConstant(m, "PROV_EC_ECNRA_FULL", PROV_EC_ECNRA_FULL);
249 #ifdef PROV_SPYRUS_LYNKS
250 PyModule_AddIntConstant(m, "PROV_SPYRUS_LYNKS", PROV_SPYRUS_LYNKS);
252 #ifdef PROV_INTEL_SEC
253 PyModule_AddIntConstant(m, "PROV_INTEL_SEC", PROV_INTEL_SEC);
256 /* Define Windows CSP Provider Names */
258 PyModule_AddStringConstant(m, "MS_DEF_PROV", MS_DEF_PROV);
260 #ifdef MS_ENHANCED_PROV
261 PyModule_AddStringConstant(m, "MS_ENHANCED_PROV", MS_ENHANCED_PROV);
263 #ifdef MS_DEF_RSA_SIG_PROV
264 PyModule_AddStringConstant(m, "MS_DEF_RSA_SIG_PROV",
265 MS_DEF_RSA_SIG_PROV);
267 #ifdef MS_DEF_RSA_SCHANNEL_PROV
268 PyModule_AddStringConstant(m, "MS_DEF_RSA_SCHANNEL_PROV",
269 MS_DEF_RSA_SCHANNEL_PROV);
271 #ifdef MS_ENHANCED_RSA_SCHANNEL_PROV
272 PyModule_AddStringConstant(m, "MS_ENHANCED_RSA_SCHANNEL_PROV",
273 MS_ENHANCED_RSA_SCHANNEL_PROV);
275 #ifdef MS_DEF_DSS_PROV
276 PyModule_AddStringConstant(m, "MS_DEF_DSS_PROV", MS_DEF_DSS_PROV);
278 #ifdef MS_DEF_DSS_DH_PROV
279 PyModule_AddStringConstant(m, "MS_DEF_DSS_DH_PROV",
282 #ifdef INTEL_DEF_PROV
283 PyModule_AddStringConstant(m, "INTEL_DEF_PROV", INTEL_DEF_PROV);
286 if (PyErr_Occurred())
287 Py_FatalError("can't initialize module winrandom");
292 CryptGenRandom usage is described in
293 http://msdn.microsoft.com/library/en-us/security/security/cryptgenrandom.asp
294 and many associated pages on Windows Cryptographic Service
295 Providers, which say:
297 With Microsoft CSPs, CryptGenRandom uses the same
298 random number generator used by other security
299 components. This allows numerous processes to
300 contribute to a system-wide seed. CryptoAPI stores
301 an intermediate random seed with every user. To form
302 the seed for the random number generator, a calling
303 application supplies bits it might havefor instance,
304 mouse or keyboard timing inputthat are then added to
305 both the stored seed and various system data and
306 user data such as the process ID and thread ID, the
307 system clock, the system time, the system counter,
308 memory status, free disk clusters, the hashed user
309 environment block. This result is SHA-1 hashed, and
310 the output is used to seed an RC4 stream, which is
311 then used as the random stream and used to update
314 The only other detailed description I've found of the
315 sources of randomness for CryptGenRandom is this excerpt
317 http://www.der-keiler.de/Newsgroups/comp.security.ssh/2002-06/0169.html
319 From: Jon McClelland (dowot69@hotmail.com)
323 Windows, call a function such as CryptGenRandom, which has two of
324 the properties of a good random number generator, unpredictability and
325 even value distribution. This function, declared in Wincrypt.h, is
326 available on just about every Windows platform, including Windows 95
327 with Internet Explorer 3.02 or later, Windows 98, Windows Me, Windows
328 CE v3, Windows NT 4, Windows 2000, and Windows XP.
330 CryptGenRandom gets its randomness, also known as entropy, from many
331 sources in Windows 2000, including the following:
332 The current process ID (GetCurrentProcessID).
333 The current thread ID (GetCurrentThreadID).
334 The ticks since boot (GetTickCount).
335 The current time (GetLocalTime).
336 Various high-precision performance counters (QueryPerformanceCounter).
337 A Message Digest 4 (MD4) hash of the user's environment block, which
338 includes username, computer name, and search path.
340 High-precision internal CPU counters, such as RDTSC, RDMSR, RDPMC (x86
341 only-more information about these counters is at
342 developer.intel.com/software/idap/resources/technical_collateral/pentiumii/RDTSCPM1.HTM
343 <http://developer.intel.com>).
345 Low-level system information, such as idle time, kernel time,
346 interrupt times, commit limit, page read count, cache read count,
347 nonpaged pool allocations, alignment fixup count, operating system
348 lookaside information.
350 Such information is added to a buffer, which is hashed using MD4 and
351 used as the key to modify a buffer, using RC4, provided by the user.
352 (Refer to the CryptGenRandom documentation in the Platform SDK for
353 more information about the user-provided buffer.) Hence, if the user
354 provides additional data in the buffer, this is used as an element in
355 the witches brew to generate the random data. The result is a
356 cryptographically random number generator.
357 Also, note that if you plan to sell your software to the United States
358 federal government, you'll need to use FIPS 140-1-approved algorithms.
359 The default versions of CryptGenRandom in Microsoft Windows CE v3,
360 Windows 95, Windows 98, Windows Me, Windows 2000, and Windows XP are
361 FIPS-approved. Obviously FIPS-140 compliance is necessary but not
362 sufficient to provide a properly secure source of random data.
366 #endif /* MS_WIN32 */