Commits

Christian Heimes  committed 7b8309f

Moved win32_urandom code to Python/random.c and implement PyOS_URandom() for POSIX and Win32

  • Participants
  • Parent commits 5848937
  • Branches randomhash

Comments (0)

Files changed (2)

File Modules/posixmodule.c

 "urandom(n) -> str\n\n\
 Return n random bytes suitable for cryptographic use.");
 
-typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTA)(HCRYPTPROV *phProv,\
-              LPCSTR pszContainer, LPCSTR pszProvider, DWORD dwProvType,\
-              DWORD dwFlags );
-typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen,\
-              BYTE *pbBuffer );
-
-static CRYPTGENRANDOM pCryptGenRandom = NULL;
-/* This handle is never explicitly released. Instead, the operating
-   system will release it when the process terminates. */
-static HCRYPTPROV hCryptProv = 0;
-
 static PyObject*
 win32_urandom(PyObject *self, PyObject *args)
 {
     /* Read arguments */
     if (! PyArg_ParseTuple(args, "i:urandom", &howMany))
         return NULL;
-    if (howMany < 0)
-        return PyErr_Format(PyExc_ValueError,
-                            "negative argument not allowed");
-
-    if (hCryptProv == 0) {
-        HINSTANCE hAdvAPI32 = NULL;
-        CRYPTACQUIRECONTEXTA pCryptAcquireContext = NULL;
-
-        /* Obtain handle to the DLL containing CryptoAPI
-           This should not fail         */
-        hAdvAPI32 = GetModuleHandle("advapi32.dll");
-        if(hAdvAPI32 == NULL)
-            return win32_error("GetModuleHandle", NULL);
-
-        /* Obtain pointers to the CryptoAPI functions
-           This will fail on some early versions of Win95 */
-        pCryptAcquireContext = (CRYPTACQUIRECONTEXTA)GetProcAddress(
-                                        hAdvAPI32,
-                                        "CryptAcquireContextA");
-        if (pCryptAcquireContext == NULL)
-            return PyErr_Format(PyExc_NotImplementedError,
-                                "CryptAcquireContextA not found");
-
-        pCryptGenRandom = (CRYPTGENRANDOM)GetProcAddress(
-                                        hAdvAPI32, "CryptGenRandom");
-        if (pCryptGenRandom == NULL)
-            return PyErr_Format(PyExc_NotImplementedError,
-                                "CryptGenRandom not found");
-
-        /* Acquire context */
-        if (! pCryptAcquireContext(&hCryptProv, NULL, NULL,
-                                   PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
-            return win32_error("CryptAcquireContext", NULL);
-    }
 
     /* Allocate bytes */
     result = PyBytes_FromStringAndSize(NULL, howMany);
     if (result != NULL) {
         /* Get random data */
         memset(PyBytes_AS_STRING(result), 0, howMany); /* zero seed */
-        if (! pCryptGenRandom(hCryptProv, howMany, (unsigned char*)
-                              PyBytes_AS_STRING(result))) {
+        if (PyOS_URandom(PyBytes_AS_STRING(result), howMany) == -1) {
             Py_DECREF(result);
-            return win32_error("CryptGenRandom", NULL);
+            return NULL;
         }
     }
     return result;

File Python/random.c

 #include "pyrandom.h"
 #include <time.h>
 
+#ifndef DEV_URANDOM
+#define DEV_URANDOM "/dev/urandom"
+#endif
+
+#ifdef MS_WINDOWS
+
+#define win32_error(function, filename) \
+	errno = GetLastError(); \
+	PyErr_SetFromWindowsErr(errno)
+
+typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTA)(HCRYPTPROV *phProv,\
+              LPCSTR pszContainer, LPCSTR pszProvider, DWORD dwProvType,\
+              DWORD dwFlags );
+typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen,\
+              BYTE *pbBuffer );
+
+static CRYPTGENRANDOM pCryptGenRandom = NULL;
+/* This handle is never explicitly released. Instead, the operating
+   system will release it when the process terminates. */
+static HCRYPTPROV hCryptProv = 0;
+
+/*
+ * Read random data with CryptGenRandom()
+ *
+ * In case of error, an exception is set
+ *
+ * @param buf: input buffer
+ * @param len: how many bytes to read into buf
+ * @return: 0 on success, -1 on error
+ */
+int
+PyOS_URandom(unsigned char *buf, Py_ssize_t len)
+{
+    if (len < 0) {
+    	PyErr_SetString(PyExc_ValueError,
+                        "negative argument not allowed");
+    	return -1;
+    }
+
+    if (hCryptProv == 0) {
+        HINSTANCE hAdvAPI32 = NULL;
+        CRYPTACQUIRECONTEXTA pCryptAcquireContext = NULL;
+
+        /* Obtain handle to the DLL containing CryptoAPI
+           This should not fail         */
+        hAdvAPI32 = GetModuleHandle("advapi32.dll");
+        if (hAdvAPI32 == NULL) {
+        	win32_error("GetModuleHandle", NULL);
+        	return -1
+        }
+
+        /* Obtain pointers to the CryptoAPI functions
+           This will fail on some early versions of Win95 */
+        pCryptAcquireContext = (CRYPTACQUIRECONTEXTA)GetProcAddress(
+                                        hAdvAPI32,
+                                        "CryptAcquireContextA");
+        if (pCryptAcquireContext == NULL) {
+            PyErr_SetString(PyExc_NotImplementedError,
+                            "CryptAcquireContextA not found");
+            return -1;
+        }
+
+        pCryptGenRandom = (CRYPTGENRANDOM)GetProcAddress(
+                                        hAdvAPI32, "CryptGenRandom");
+        if (pCryptGenRandom == NULL) {
+            PyErr_SetString(PyExc_NotImplementedError,
+                                   "CryptGenRandom not found");
+            return -1;
+        }
+
+        /* Acquire context */
+        if (! pCryptAcquireContext(&hCryptProv, NULL, NULL,
+                                   PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
+            win32_error("CryptAcquireContext", NULL);
+            return -1;
+        }
+    }
+
+    /* Get random data */
+    memset(buf, 0, len); /* zero seed */
+    if (!pCryptGenRandom(hCryptProv, len, buf)) {
+            win32_error("CryptGenRandom", NULL);
+            return -1;
+        }
+    }
+    return 0;
+}
+#else
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+/*
+ * Read random data from /dev/urandom
+ *
+ * In case of error, an exception is set
+ *
+ * @param buf: input buffer
+ * @param len: how many bytes to read into buf
+ * @return: 0 on success, -1 on error
+ */
+int
+PyOS_URandom(unsigned char *buf, Py_ssize_t len) {
+	int fd;
+	ssize_t pos, result = 0;
+
+    if (len < 0) {
+    	PyErr_SetString(PyExc_ValueError,
+                        "negative argument not allowed");
+    	return -1;
+    }
+
+	if ((fd = open(DEV_URANDOM, O_RDONLY)) == -1) {
+		PyErr_SetFromErrnoWithFilename(PyExc_OSError, DEV_URANDOM);
+		return -1;
+	}
+
+	while (pos < len) {
+		if ((result = read(fd, buf+pos, len-pos)) == -1) {
+			close(fd);
+			PyErr_SetFromErrnoWithFilename(PyExc_OSError, DEV_URANDOM);
+			return -1;
+		}
+		pos += result;
+	}
+	close(fd);
+	return 0;
+}
+
+#endif
+
 
 /* ------------------------------------------------------------------
    The code in this module was based on a download from: