winrand.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. /* -*- C -*- */
  2. /*
  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.
  7. *
  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.
  11. *
  12. * =======================================================================
  13. * The contents of this file are dedicated to the public domain. To the
  14. * extent that dedication to the public domain is not available, everyone
  15. * is granted a worldwide, perpetual, royalty-free, non-exclusive license
  16. * to exercise all rights associated with the contents of this file for
  17. * any purpose whatsoever. No rights are reserved.
  18. *
  19. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  20. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  21. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  22. * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  23. * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  24. * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  25. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  26. * SOFTWARE.
  27. * =======================================================================
  28. *
  29. */
  30. /* Author: Mark Moraes */
  31. #include "Python.h"
  32. #include "pycrypto_compat.h"
  33. #ifdef MS_WIN32
  34. #define _WIN32_WINNT 0x400
  35. #define WINSOCK
  36. #include <windows.h>
  37. #include <wincrypt.h>
  38. #ifdef HAVE_INTEL_RNG
  39. # include "icsp4ms.h"
  40. #else
  41. # define PROV_INTEL_SEC 22
  42. # define INTEL_DEF_PROV "Intel Hardware Cryptographic Service Provider"
  43. #endif
  44. /* To-Do: store provider name and type for print/repr? */
  45. typedef struct
  46. {
  47. PyObject_HEAD
  48. HCRYPTPROV hcp;
  49. } WRobject;
  50. /* Please see PEP3123 for a discussion of PyObject_HEAD and changes made in 3.x to make it conform to Standard C.
  51. * These changes also dictate using Py_TYPE to check type, and PyVarObject_HEAD_INIT(NULL, 0) to initialize
  52. */
  53. #ifdef IS_PY3K
  54. static PyTypeObject WRtype;
  55. #define is_WRobject(v) (Py_TYPE(v) == &WRtype)
  56. #else
  57. staticforward PyTypeObject WRtype;
  58. #define is_WRobject(v) ((v)->ob_type == &WRtype)
  59. #define PyLong_FromLong PyInt_FromLong /* for Python 2.x */
  60. #endif
  61. static void
  62. WRdealloc(PyObject *ptr)
  63. {
  64. WRobject *o = (WRobject *)ptr;
  65. if (! is_WRobject(ptr)) {
  66. PyErr_Format(PyExc_TypeError,
  67. "WinRandom trying to dealloc non-WinRandom object");
  68. return;
  69. }
  70. if (! CryptReleaseContext(o->hcp, 0)) {
  71. PyErr_Format(PyExc_SystemError,
  72. "CryptReleaseContext failed, error 0x%x",
  73. (unsigned int) GetLastError());
  74. return;
  75. }
  76. /* Overwrite the contents of the object */
  77. o->hcp = 0;
  78. PyObject_Del(ptr);
  79. }
  80. static char winrandom__doc__[] =
  81. "new([provider], [provtype]): Returns an object handle to Windows\n\
  82. CryptoAPI that can be used to access a cryptographically strong\n\
  83. pseudo-random generator that uses OS-gathered entropy.\n\
  84. Provider is a string that specifies the Cryptographic Service Provider\n\
  85. to use, default is the default OS CSP.\n\
  86. provtype is an integer specifying the provider type to use, default\n\
  87. is 1 (PROV_RSA_FULL)";
  88. static char WR_get_bytes__doc__[] =
  89. "get_bytes(nbytes, [userdata]]): Returns nbytes of random data\n\
  90. from Windows CryptGenRandom.\n\
  91. userdata is a string with any additional entropic data that the\n\
  92. user wishes to provide.";
  93. static WRobject *
  94. winrandom_new(PyObject *self, PyObject *args, PyObject *kwdict)
  95. {
  96. HCRYPTPROV hcp = 0;
  97. WRobject *res;
  98. char *provname = NULL;
  99. int provtype = PROV_RSA_FULL;
  100. static char *kwlist[] = { "provider", "provtype", NULL};
  101. if (!PyArg_ParseTupleAndKeywords(args, kwdict, "|si", kwlist,
  102. &provname, &provtype)) {
  103. return NULL;
  104. }
  105. if (! CryptAcquireContext(&hcp, NULL, (LPCTSTR) provname,
  106. (DWORD) provtype,
  107. CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
  108. PyErr_Format(PyExc_SystemError,
  109. "CryptAcquireContext for provider \"%s\" type %i failed, error 0x%x",
  110. provname? provname : "(null)", provtype,
  111. (unsigned int) GetLastError());
  112. return NULL;
  113. }
  114. res = PyObject_New(WRobject, &WRtype);
  115. res->hcp = hcp;
  116. return res;
  117. }
  118. static PyObject *
  119. WR_get_bytes(WRobject *self, PyObject *args)
  120. {
  121. int n, nbytes, len = 0;
  122. PyObject *res;
  123. char *buf, *str = NULL;
  124. if (! is_WRobject(self)) {
  125. PyErr_Format(PyExc_TypeError,
  126. "WinRandom trying to get_bytes with non-WinRandom object");
  127. return NULL;
  128. }
  129. if (!PyArg_ParseTuple(args, "i|s#", &n, &str, &len)) {
  130. return NULL;
  131. }
  132. if (n <= 0) {
  133. PyErr_SetString(PyExc_ValueError, "nbytes must be positive number");
  134. return NULL;
  135. }
  136. /* Just in case char != BYTE, or userdata > desired result */
  137. nbytes = (((n > len) ? n : len) * sizeof(char)) / sizeof(BYTE) + 1;
  138. if ((buf = (char *) PyMem_Malloc(nbytes)) == NULL)
  139. return PyErr_NoMemory();
  140. if (len > 0)
  141. memcpy(buf, str, len);
  142. /*
  143. * if userdata > desired result, we end up getting
  144. * more bytes than we really needed to return. No
  145. * easy way to avoid that: we prefer that
  146. * CryptGenRandom does the distillation of userdata
  147. * down to entropy, rather than trying to do it
  148. * ourselves. Since the extra bytes presumably come
  149. * from an RC4 stream, they should be relatively
  150. * cheap.
  151. */
  152. if (! CryptGenRandom(self->hcp, (DWORD) nbytes, (BYTE *) buf)) {
  153. PyErr_Format(PyExc_SystemError,
  154. "CryptGenRandom failed, error 0x%x",
  155. (unsigned int) GetLastError());
  156. PyMem_Free(buf);
  157. return NULL;
  158. }
  159. res = PyBytes_FromStringAndSize(buf, n);
  160. PyMem_Free(buf);
  161. return res;
  162. }
  163. /* WinRandom object methods */
  164. static PyMethodDef WRmethods[] =
  165. {
  166. {"get_bytes", (PyCFunction) WR_get_bytes, METH_VARARGS,
  167. WR_get_bytes__doc__},
  168. {NULL, NULL} /* sentinel */
  169. };
  170. /* winrandom module methods */
  171. static PyMethodDef WR_mod_methods[] = {
  172. {"new", (PyCFunction) winrandom_new, METH_VARARGS|METH_KEYWORDS,
  173. winrandom__doc__},
  174. {NULL, NULL} /* Sentinel */
  175. };
  176. static PyObject *
  177. #ifdef IS_PY3K
  178. WRgetattro(PyObject *s, PyObject *attr)
  179. #else
  180. WRgetattr(PyObject *s, char *name)
  181. #endif
  182. {
  183. WRobject *self = (WRobject*)s;
  184. if (! is_WRobject(self)) {
  185. PyErr_Format(PyExc_TypeError,
  186. "WinRandom trying to getattr with non-WinRandom object");
  187. return NULL;
  188. }
  189. #ifdef IS_PY3K
  190. if (!PyUnicode_Check(attr))
  191. goto generic;
  192. if (PyUnicode_CompareWithASCIIString(attr, "hcp") == 0)
  193. #else
  194. if (strcmp(name, "hcp") == 0)
  195. #endif
  196. return PyLong_FromLong((long) self->hcp);
  197. #ifdef IS_PY3K
  198. generic:
  199. return PyObject_GenericGetAttr(s, attr);
  200. #else
  201. return Py_FindMethod(WRmethods, (PyObject *) self, name);
  202. #endif
  203. }
  204. static PyTypeObject WRtype =
  205. {
  206. #ifdef IS_PY3K
  207. PyVarObject_HEAD_INIT(NULL, 0) /* deferred type init for compilation on Windows, type will be filled in at runtime */
  208. #else
  209. PyObject_HEAD_INIT(NULL)
  210. 0, /*ob_size*/
  211. #endif
  212. "winrandom.WinRandom", /*tp_name*/
  213. sizeof(WRobject), /*tp_size*/
  214. 0, /*tp_itemsize*/
  215. /* methods */
  216. (destructor) WRdealloc, /*tp_dealloc*/
  217. 0, /*tp_print*/
  218. #ifndef IS_PY3K
  219. WRgetattr, /*tp_getattr*/
  220. #else
  221. 0, /*tp_getattr*/
  222. 0, /*tp_setattr*/
  223. 0, /*tp_compare*/
  224. 0, /*tp_repr*/
  225. 0, /*tp_as_number */
  226. 0, /*tp_as_sequence */
  227. 0, /*tp_as_mapping */
  228. 0, /*tp_hash*/
  229. 0, /*tp_call*/
  230. 0, /*tp_str*/
  231. WRgetattro, /*tp_getattro*/
  232. 0, /*tp_setattro*/
  233. 0, /*tp_as_buffer*/
  234. Py_TPFLAGS_DEFAULT, /*tp_flags*/
  235. 0, /*tp_doc*/
  236. 0, /*tp_traverse*/
  237. 0, /*tp_clear*/
  238. 0, /*tp_richcompare*/
  239. 0, /*tp_weaklistoffset*/
  240. 0, /*tp_iter*/
  241. 0, /*tp_iternext*/
  242. WRmethods, /*tp_methods*/
  243. #endif
  244. };
  245. #ifdef IS_PY3K
  246. static struct PyModuleDef moduledef = {
  247. PyModuleDef_HEAD_INIT,
  248. "winrandom",
  249. NULL,
  250. -1,
  251. WR_mod_methods,
  252. NULL,
  253. NULL,
  254. NULL,
  255. NULL
  256. };
  257. #endif
  258. #ifdef IS_PY3K
  259. PyMODINIT_FUNC
  260. PyInit_winrandom()
  261. #else
  262. void
  263. initwinrandom()
  264. #endif
  265. {
  266. PyObject *m;
  267. #ifdef IS_PY3K
  268. /* PyType_Ready automatically fills in ob_type with &PyType_Type if it's not already set */
  269. if (PyType_Ready(&WRtype) < 0)
  270. return NULL;
  271. /* Initialize the module */
  272. m = PyModule_Create(&moduledef);
  273. if (m == NULL)
  274. return NULL;
  275. #else
  276. WRtype.ob_type = &PyType_Type;
  277. m = Py_InitModule("winrandom", WR_mod_methods);
  278. #endif
  279. /* define Windows CSP Provider Types */
  280. #ifdef PROV_RSA_FULL
  281. PyModule_AddIntConstant(m, "PROV_RSA_FULL", PROV_RSA_FULL);
  282. #endif
  283. #ifdef PROV_RSA_SIG
  284. PyModule_AddIntConstant(m, "PROV_RSA_SIG", PROV_RSA_SIG);
  285. #endif
  286. #ifdef PROV_DSS
  287. PyModule_AddIntConstant(m, "PROV_DSS", PROV_DSS);
  288. #endif
  289. #ifdef PROV_FORTEZZA
  290. PyModule_AddIntConstant(m, "PROV_FORTEZZA", PROV_FORTEZZA);
  291. #endif
  292. #ifdef PROV_MS_EXCHANGE
  293. PyModule_AddIntConstant(m, "PROV_MS_EXCHANGE", PROV_MS_EXCHANGE);
  294. #endif
  295. #ifdef PROV_SSL
  296. PyModule_AddIntConstant(m, "PROV_SSL", PROV_SSL);
  297. #endif
  298. #ifdef PROV_RSA_SCHANNEL
  299. PyModule_AddIntConstant(m, "PROV_RSA_SCHANNEL", PROV_RSA_SCHANNEL);
  300. #endif
  301. #ifdef PROV_DSS_DH
  302. PyModule_AddIntConstant(m, "PROV_DSS_DH", PROV_DSS_DH);
  303. #endif
  304. #ifdef PROV_EC_ECDSA_SIG
  305. PyModule_AddIntConstant(m, "PROV_EC_ECDSA_SIG", PROV_EC_ECDSA_SIG);
  306. #endif
  307. #ifdef PROV_EC_ECNRA_SIG
  308. PyModule_AddIntConstant(m, "PROV_EC_ECNRA_SIG", PROV_EC_ECNRA_SIG);
  309. #endif
  310. #ifdef PROV_EC_ECDSA_FULL
  311. PyModule_AddIntConstant(m, "PROV_EC_ECDSA_FULL", PROV_EC_ECDSA_FULL);
  312. #endif
  313. #ifdef PROV_EC_ECNRA_FULL
  314. PyModule_AddIntConstant(m, "PROV_EC_ECNRA_FULL", PROV_EC_ECNRA_FULL);
  315. #endif
  316. #ifdef PROV_SPYRUS_LYNKS
  317. PyModule_AddIntConstant(m, "PROV_SPYRUS_LYNKS", PROV_SPYRUS_LYNKS);
  318. #endif
  319. #ifdef PROV_INTEL_SEC
  320. PyModule_AddIntConstant(m, "PROV_INTEL_SEC", PROV_INTEL_SEC);
  321. #endif
  322. /* Define Windows CSP Provider Names */
  323. #ifdef MS_DEF_PROV
  324. PyModule_AddStringConstant(m, "MS_DEF_PROV", MS_DEF_PROV);
  325. #endif
  326. #ifdef MS_ENHANCED_PROV
  327. PyModule_AddStringConstant(m, "MS_ENHANCED_PROV", MS_ENHANCED_PROV);
  328. #endif
  329. #ifdef MS_DEF_RSA_SIG_PROV
  330. PyModule_AddStringConstant(m, "MS_DEF_RSA_SIG_PROV",
  331. MS_DEF_RSA_SIG_PROV);
  332. #endif
  333. #ifdef MS_DEF_RSA_SCHANNEL_PROV
  334. PyModule_AddStringConstant(m, "MS_DEF_RSA_SCHANNEL_PROV",
  335. MS_DEF_RSA_SCHANNEL_PROV);
  336. #endif
  337. #ifdef MS_ENHANCED_RSA_SCHANNEL_PROV
  338. PyModule_AddStringConstant(m, "MS_ENHANCED_RSA_SCHANNEL_PROV",
  339. MS_ENHANCED_RSA_SCHANNEL_PROV);
  340. #endif
  341. #ifdef MS_DEF_DSS_PROV
  342. PyModule_AddStringConstant(m, "MS_DEF_DSS_PROV", MS_DEF_DSS_PROV);
  343. #endif
  344. #ifdef MS_DEF_DSS_DH_PROV
  345. PyModule_AddStringConstant(m, "MS_DEF_DSS_DH_PROV",
  346. MS_DEF_DSS_DH_PROV);
  347. #endif
  348. #ifdef INTEL_DEF_PROV
  349. PyModule_AddStringConstant(m, "INTEL_DEF_PROV", INTEL_DEF_PROV);
  350. #endif
  351. if (PyErr_Occurred())
  352. Py_FatalError("can't initialize module winrandom");
  353. #ifdef IS_PY3K
  354. return m;
  355. #endif
  356. }
  357. /*
  358. CryptGenRandom usage is described in
  359. http://msdn.microsoft.com/library/en-us/security/security/cryptgenrandom.asp
  360. and many associated pages on Windows Cryptographic Service
  361. Providers, which say:
  362. With Microsoft CSPs, CryptGenRandom uses the same
  363. random number generator used by other security
  364. components. This allows numerous processes to
  365. contribute to a system-wide seed. CryptoAPI stores
  366. an intermediate random seed with every user. To form
  367. the seed for the random number generator, a calling
  368. application supplies bits it might havefor instance,
  369. mouse or keyboard timing inputthat are then added to
  370. both the stored seed and various system data and
  371. user data such as the process ID and thread ID, the
  372. system clock, the system time, the system counter,
  373. memory status, free disk clusters, the hashed user
  374. environment block. This result is SHA-1 hashed, and
  375. the output is used to seed an RC4 stream, which is
  376. then used as the random stream and used to update
  377. the stored seed.
  378. The only other detailed description I've found of the
  379. sources of randomness for CryptGenRandom is this excerpt
  380. from a posting
  381. http://www.der-keiler.de/Newsgroups/comp.security.ssh/2002-06/0169.html
  382. From: Jon McClelland (dowot69@hotmail.com)
  383. Date: 06/12/02
  384. ...
  385. Windows, call a function such as CryptGenRandom, which has two of
  386. the properties of a good random number generator, unpredictability and
  387. even value distribution. This function, declared in Wincrypt.h, is
  388. available on just about every Windows platform, including Windows 95
  389. with Internet Explorer 3.02 or later, Windows 98, Windows Me, Windows
  390. CE v3, Windows NT 4, Windows 2000, and Windows XP.
  391. CryptGenRandom gets its randomness, also known as entropy, from many
  392. sources in Windows 2000, including the following:
  393. The current process ID (GetCurrentProcessID).
  394. The current thread ID (GetCurrentThreadID).
  395. The ticks since boot (GetTickCount).
  396. The current time (GetLocalTime).
  397. Various high-precision performance counters (QueryPerformanceCounter).
  398. A Message Digest 4 (MD4) hash of the user's environment block, which
  399. includes username, computer name, and search path.
  400. High-precision internal CPU counters, such as RDTSC, RDMSR, RDPMC (x86
  401. only-more information about these counters is at
  402. developer.intel.com/software/idap/resources/technical_collateral/pentiumii/RDTSCPM1.HTM
  403. <http://developer.intel.com>).
  404. Low-level system information, such as idle time, kernel time,
  405. interrupt times, commit limit, page read count, cache read count,
  406. nonpaged pool allocations, alignment fixup count, operating system
  407. lookaside information.
  408. Such information is added to a buffer, which is hashed using MD4 and
  409. used as the key to modify a buffer, using RC4, provided by the user.
  410. (Refer to the CryptGenRandom documentation in the Platform SDK for
  411. more information about the user-provided buffer.) Hence, if the user
  412. provides additional data in the buffer, this is used as an element in
  413. the witches brew to generate the random data. The result is a
  414. cryptographically random number generator.
  415. Also, note that if you plan to sell your software to the United States
  416. federal government, you'll need to use FIPS 140-1-approved algorithms.
  417. The default versions of CryptGenRandom in Microsoft Windows CE v3,
  418. Windows 95, Windows 98, Windows Me, Windows 2000, and Windows XP are
  419. FIPS-approved. Obviously FIPS-140 compliance is necessary but not
  420. sufficient to provide a properly secure source of random data.
  421. */
  422. /*
  423. [Update: 2007-11-13]
  424. CryptGenRandom does not necessarily provide forward secrecy or reverse
  425. secrecy. See the paper by Leo Dorrendorf and Zvi Gutterman and Benny
  426. Pinkas, _Cryptanalysis of the Random Number Generator of the Windows
  427. Operating System_, Cryptology ePrint Archive, Report 2007/419,
  428. http://eprint.iacr.org/2007/419
  429. */
  430. #endif /* MS_WIN32 */