/* -*- C -*- */ /* * Uses Windows CryptoAPI CryptGenRandom to get random bytes * * Distribute and use freely; there are no restrictions on further * dissemination and usage except those imposed by the laws of your * country of residence. This software is provided "as is" without * warranty of fitness for use or suitability for any purpose, express * or implied. Use at your own risk or not at all. * */ /* Author: Mark Moraes */ #include "Python.h" #ifdef MS_WIN32 #define _WIN32_WINNT 0x400 #define WINSOCK #include #include LPVOID PrintWindowsError(char* msg, DWORD error) { LPVOID lpMsgBuf; if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language (LPTSTR) &lpMsgBuf, 0, NULL )) { fprintf(stderr, "FormatMessage had an error when processing this error (%d) and this message (%s)!", error, msg); } fprintf(stderr, "%s: %s\n", msg, lpMsgBuf); LocalFree(lpMsgBuf); } static char winrandom__doc__[] = "winrandom(nbytes): Returns nbytes of random data from Windows CryptGenRandom," "a cryptographically strong pseudo-random generator using system entropy"; static PyObject * winrandom(PyObject *self, PyObject *args) { HCRYPTPROV hcp = 0; int n, nbytes; PyObject *res; char *buf; if (!PyArg_ParseTuple(args, "i", &n)) { return NULL; } /* Just in case char != BYTE */ nbytes = (n * sizeof(char)) / sizeof(BYTE); if (nbytes <= 0) { PyErr_SetString(PyExc_ValueError, "nbytes must be positive number"); return NULL; } if ((buf = (char *) PyMem_Malloc(nbytes)) == NULL) return PyErr_NoMemory(); if (! CryptAcquireContext(&hcp, NULL, NULL, PROV_RSA_FULL, 0)) { // If the last error was a bad keyset, then it might be // because we need to generate a keyset, so we call // CryptAcquireContext again in order to try to create // a key set this time. DWORD lastError = GetLastError(); if (lastError == NTE_BAD_KEYSET) { if (!CryptAcquireContext(&hcp, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) { lastError = GetLastError(); } else { lastError = 0; } } if (lastError != 0) { PyErr_Format(PyExc_SystemError, "CryptAcquireContext failed, error %i", lastError); PrintWindowsError("CryptAcquireContext failed", lastError); PyMem_Free(buf); return NULL; } } if (! CryptGenRandom(hcp, (DWORD) nbytes, (BYTE *) buf)) { PyErr_Format(PyExc_SystemError, "CryptGenRandom failed, error %i", GetLastError()); PyMem_Free(buf); (void) CryptReleaseContext(hcp, 0); return NULL; } if (! CryptReleaseContext(hcp, 0)) { PyErr_Format(PyExc_SystemError, "CryptReleaseContext failed, error %i", GetLastError()); return NULL; } res = PyString_FromStringAndSize(buf, n); PyMem_Free(buf); return res; } static PyMethodDef WRMethods[] = { {"winrandom", (PyCFunction) winrandom, METH_VARARGS, winrandom__doc__}, {NULL, NULL} /* Sentinel */ }; void initwinrandom() { (void) Py_InitModule("winrandom", WRMethods); } #endif /* MS_WIN32 */