#include <openssl/rand.h>
#include "rand_lcl.h"
-#if defined(WINDOWS) || defined(WIN32)
+#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
#include <windows.h>
#ifndef _WIN32_WINNT
# define _WIN32_WINNT 0x0400
* http://developer.intel.com/design/security/rng/redist_license.htm
*/
#define PROV_INTEL_SEC 22
-#define INTEL_DEF_PROV "Intel Hardware Cryptographic Service Provider"
+#define INTEL_DEF_PROV TEXT("Intel Hardware Cryptographic Service Provider")
static void readtimer(void);
static void readscreen(void);
+/* It appears like CURSORINFO, PCURSORINFO and LPCURSORINFO are only defined
+ when WINVER is 0x0500 and up, which currently only happens on Win2000.
+ Unfortunately, those are typedefs, so they're a little bit difficult to
+ detect properly. On the other hand, the macro CURSOR_SHOWING is defined
+ within the same conditional, so it can be use to detect the absence of said
+ typedefs. */
+
+#ifndef CURSOR_SHOWING
+/*
+ * Information about the global cursor.
+ */
+typedef struct tagCURSORINFO
+{
+ DWORD cbSize;
+ DWORD flags;
+ HCURSOR hCursor;
+ POINT ptScreenPos;
+} CURSORINFO, *PCURSORINFO, *LPCURSORINFO;
+
+#define CURSOR_SHOWING 0x00000001
+#endif /* CURSOR_SHOWING */
+
typedef BOOL (WINAPI *CRYPTACQUIRECONTEXT)(HCRYPTPROV *, LPCTSTR, LPCTSTR,
DWORD, DWORD);
typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV, DWORD, BYTE *);
typedef BOOL (WINAPI *THREAD32)(HANDLE, LPTHREADENTRY32);
typedef BOOL (WINAPI *MODULE32)(HANDLE, LPMODULEENTRY32);
+#include <lmcons.h>
+#ifndef OPENSSL_SYS_WINCE
+#include <lmstats.h>
+#endif
+#if 1 /* The NET API is Unicode only. It requires the use of the UNICODE
+ * macro. When UNICODE is defined LPTSTR becomes LPWSTR. LMSTR was
+ * was added to the Platform SDK to allow the NET API to be used in
+ * non-Unicode applications provided that Unicode strings were still
+ * used for input. LMSTR is defined as LPWSTR.
+ */
+typedef NET_API_STATUS (NET_API_FUNCTION * NETSTATGET)
+ (LPWSTR, LPWSTR, DWORD, DWORD, LPBYTE*);
+typedef NET_API_STATUS (NET_API_FUNCTION * NETFREE)(LPBYTE);
+#endif /* 1 */
+
int RAND_poll(void)
{
MEMORYSTATUS m;
DWORD w;
HWND h;
- HMODULE advapi, kernel, user;
- CRYPTACQUIRECONTEXT acquire;
- CRYPTGENRANDOM gen;
- CRYPTRELEASECONTEXT release;
+ HMODULE advapi, kernel, user, netapi;
+ CRYPTACQUIRECONTEXT acquire = 0;
+ CRYPTGENRANDOM gen = 0;
+ CRYPTRELEASECONTEXT release = 0;
+#if 1 /* There was previously a problem with NETSTATGET. Currently, this
+ * section is still experimental, but if all goes well, this conditional
+ * will be removed
+ */
+ NETSTATGET netstatget = 0;
+ NETFREE netfree = 0;
+#endif /* 1 */
+
+ /* Determine the OS version we are on so we can turn off things
+ * that do not work properly.
+ */
+ OSVERSIONINFO osverinfo ;
+ osverinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO) ;
+ GetVersionEx( &osverinfo ) ;
+
+#ifdef OPENSSL_SYS_WINCE
+ /* poll the CryptoAPI PRNG */
+ /* The CryptoAPI returns sizeof(buf) bytes of randomness */
+ if (CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
+ {
+ if (CryptGenRandom(hProvider, sizeof(buf), buf))
+ RAND_add(buf, sizeof(buf), sizeof(buf));
+ CryptReleaseContext(hProvider, 0);
+ }
+#endif
/* load functions dynamically - not available on all systems */
- advapi = GetModuleHandle("ADVAPI32.DLL");
- kernel = GetModuleHandle("KERNEL32.DLL");
- user = GetModuleHandle("USER32.DLL");
+ advapi = LoadLibrary(TEXT("ADVAPI32.DLL"));
+ kernel = LoadLibrary(TEXT("KERNEL32.DLL"));
+ user = LoadLibrary(TEXT("USER32.DLL"));
+ netapi = LoadLibrary(TEXT("NETAPI32.DLL"));
+
+#ifndef OPENSSL_SYS_WINCE
+#if 1 /* There was previously a problem with NETSTATGET. Currently, this
+ * section is still experimental, but if all goes well, this conditional
+ * will be removed
+ */
+ if (netapi)
+ {
+ netstatget = (NETSTATGET) GetProcAddress(netapi,TEXT("NetStatisticsGet"));
+ netfree = (NETFREE) GetProcAddress(netapi,TEXT("NetApiBufferFree"));
+ }
+
+ if (netstatget && netfree)
+ {
+ LPBYTE outbuf;
+ /* NetStatisticsGet() is a Unicode only function
+ * STAT_WORKSTATION_0 contains 45 fields and STAT_SERVER_0
+ * contains 17 fields. We treat each field as a source of
+ * one byte of entropy.
+ */
+
+ if (netstatget(NULL, L"LanmanWorkstation", 0, 0, &outbuf) == 0)
+ {
+ RAND_add(outbuf, sizeof(STAT_WORKSTATION_0), 45);
+ netfree(outbuf);
+ }
+ if (netstatget(NULL, L"LanmanServer", 0, 0, &outbuf) == 0)
+ {
+ RAND_add(outbuf, sizeof(STAT_SERVER_0), 17);
+ netfree(outbuf);
+ }
+ }
+
+ if (netapi)
+ FreeLibrary(netapi);
+#endif /* 1 */
+#endif /* !OPENSSL_SYS_WINCE */
+
+#ifndef OPENSSL_SYS_WINCE
+ /* It appears like this can cause an exception deep within ADVAPI32.DLL
+ * at random times on Windows 2000. Reported by Jeffrey Altman.
+ * Only use it on NT.
+ */
+ /* Wolfgang Marczy <WMarczy@topcall.co.at> reports that
+ * the RegQueryValueEx call below can hang on NT4.0 (SP6).
+ * So we don't use this at all for now. */
+#if 0
+ if ( osverinfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
+ osverinfo.dwMajorVersion < 5)
+ {
+ /* Read Performance Statistics from NT/2000 registry
+ * The size of the performance data can vary from call
+ * to call so we must guess the size of the buffer to use
+ * and increase its size if we get an ERROR_MORE_DATA
+ * return instead of ERROR_SUCCESS.
+ */
+ LONG rc=ERROR_MORE_DATA;
+ char * buf=NULL;
+ DWORD bufsz=0;
+ DWORD length;
+
+ while (rc == ERROR_MORE_DATA)
+ {
+ buf = realloc(buf,bufsz+8192);
+ if (!buf)
+ break;
+ bufsz += 8192;
+
+ length = bufsz;
+ rc = RegQueryValueEx(HKEY_PERFORMANCE_DATA, TEXT("Global"),
+ NULL, NULL, buf, &length);
+ }
+ if (rc == ERROR_SUCCESS)
+ {
+ /* For entropy count assume only least significant
+ * byte of each DWORD is random.
+ */
+ RAND_add(&length, sizeof(length), 0);
+ RAND_add(buf, length, length / 4.0);
+
+ /* Close the Registry Key to allow Windows to cleanup/close
+ * the open handle
+ * Note: The 'HKEY_PERFORMANCE_DATA' key is implicitly opened
+ * when the RegQueryValueEx above is done. However, if
+ * it is not explicitly closed, it can cause disk
+ * partition manipulation problems.
+ */
+ RegCloseKey(HKEY_PERFORMANCE_DATA);
+ }
+ if (buf)
+ free(buf);
+ }
+#endif
+#endif /* !OPENSSL_SYS_WINCE */
if (advapi)
{
acquire = (CRYPTACQUIRECONTEXT) GetProcAddress(advapi,
- "CryptAcquireContextA");
+ TEXT("CryptAcquireContextA"));
gen = (CRYPTGENRANDOM) GetProcAddress(advapi,
- "CryptGenRandom");
+ TEXT("CryptGenRandom"));
release = (CRYPTRELEASECONTEXT) GetProcAddress(advapi,
- "CryptReleaseContext");
+ TEXT("CryptReleaseContext"));
}
if (acquire && gen && release)
{
/* poll the CryptoAPI PRNG */
+ /* The CryptoAPI returns sizeof(buf) bytes of randomness */
if (acquire(&hProvider, 0, 0, PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT))
{
if (gen(hProvider, sizeof(buf), buf) != 0)
{
RAND_add(buf, sizeof(buf), 0);
-#ifdef DEBUG
+#if 0
printf("randomness from PROV_RSA_FULL\n");
#endif
}
{
if (gen(hProvider, sizeof(buf), buf) != 0)
{
- RAND_add(buf, sizeof(buf), 0);
-#ifdef DEBUG
+ RAND_add(buf, sizeof(buf), sizeof(buf));
+#if 0
printf("randomness from PROV_INTEL_SEC\n");
#endif
}
}
}
+ if (advapi)
+ FreeLibrary(advapi);
+
/* timer data */
readtimer();
/* process ID */
w = GetCurrentProcessId();
- RAND_add(&w, sizeof(w), 0);
+ RAND_add(&w, sizeof(w), 1);
if (user)
{
GETFOREGROUNDWINDOW win;
GETQUEUESTATUS queue;
- win = (GETFOREGROUNDWINDOW) GetProcAddress(user, "GetForegroundWindow");
- cursor = (GETCURSORINFO) GetProcAddress(user, "GetCursorInfo");
- queue = (GETQUEUESTATUS) GetProcAddress(user, "GetQueueStatus");
+ win = (GETFOREGROUNDWINDOW) GetProcAddress(user, TEXT("GetForegroundWindow"));
+ cursor = (GETCURSORINFO) GetProcAddress(user, TEXT("GetCursorInfo"));
+ queue = (GETQUEUESTATUS) GetProcAddress(user, TEXT("GetQueueStatus"));
if (win)
- {
+ {
/* window handle */
h = win();
RAND_add(&h, sizeof(h), 0);
- }
-
+ }
+ if (cursor)
+ {
+ /* unfortunately, its not safe to call GetCursorInfo()
+ * on NT4 even though it exists in SP3 (or SP6) and
+ * higher.
+ */
+ if ( osverinfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
+ osverinfo.dwMajorVersion < 5)
+ cursor = 0;
+ }
if (cursor)
{
/* cursor position */
- cursor((PCURSORINFO)buf);
- RAND_add(buf, sizeof(buf), 0);
+ /* assume 2 bytes of entropy */
+ CURSORINFO ci;
+ ci.cbSize = sizeof(CURSORINFO);
+ if (cursor(&ci))
+ RAND_add(&ci, ci.cbSize, 2);
}
if (queue)
{
/* message queue status */
+ /* assume 1 byte of entropy */
w = queue(QS_ALLEVENTS);
- RAND_add(&w, sizeof(w), 0);
+ RAND_add(&w, sizeof(w), 1);
}
+
+ FreeLibrary(user);
}
/* Toolhelp32 snapshot: enumerate processes, threads, modules and heap
* http://msdn.microsoft.com/library/psdk/winbase/toolhelp_5pfd.htm
- * (Win 9x only, not available on NT)
+ * (Win 9x and 2000 only, not available on NT)
*
* This seeding method was proposed in Peter Gutmann, Software
* Generation of Practically Strong Random Numbers,
- * http://www.cs.auckland.ac.nz/~pgut001/pubs/random2.pdf
+ * http://www.usenix.org/publications/library/proceedings/sec98/gutmann.html
+ * revised version at http://www.cryptoengines.com/~peter/06_random.pdf
* (The assignment of entropy estimates below is arbitrary, but based
* on Peter's analysis the full poll appears to be safe. Additional
* interactive seeding is encouraged.)
MODULEENTRY32 m;
snap = (CREATETOOLHELP32SNAPSHOT)
- GetProcAddress(kernel, "CreateToolhelp32Snapshot");
- heap_first = (HEAP32FIRST) GetProcAddress(kernel, "Heap32First");
- heap_next = (HEAP32NEXT) GetProcAddress(kernel, "Heap32Next");
- heaplist_first = (HEAP32LIST) GetProcAddress(kernel, "Heap32ListFirst");
- heaplist_next = (HEAP32LIST) GetProcAddress(kernel, "Heap32ListNext");
- process_first = (PROCESS32) GetProcAddress(kernel, "Process32First");
- process_next = (PROCESS32) GetProcAddress(kernel, "Process32Next");
- thread_first = (THREAD32) GetProcAddress(kernel, "Thread32First");
- thread_next = (THREAD32) GetProcAddress(kernel, "Thread32Next");
- module_first = (MODULE32) GetProcAddress(kernel, "Module32First");
- module_next = (MODULE32) GetProcAddress(kernel, "Module32Next");
+ GetProcAddress(kernel, TEXT("CreateToolhelp32Snapshot"));
+ heap_first = (HEAP32FIRST) GetProcAddress(kernel, TEXT("Heap32First"));
+ heap_next = (HEAP32NEXT) GetProcAddress(kernel, TEXT("Heap32Next"));
+ heaplist_first = (HEAP32LIST) GetProcAddress(kernel, TEXT("Heap32ListFirst"));
+ heaplist_next = (HEAP32LIST) GetProcAddress(kernel, TEXT("Heap32ListNext"));
+ process_first = (PROCESS32) GetProcAddress(kernel, TEXT("Process32First"));
+ process_next = (PROCESS32) GetProcAddress(kernel, TEXT("Process32Next"));
+ thread_first = (THREAD32) GetProcAddress(kernel, TEXT("Thread32First"));
+ thread_next = (THREAD32) GetProcAddress(kernel, TEXT("Thread32Next"));
+ module_first = (MODULE32) GetProcAddress(kernel, TEXT("Module32First"));
+ module_next = (MODULE32) GetProcAddress(kernel, TEXT("Module32Next"));
if (snap && heap_first && heap_next && heaplist_first &&
heaplist_next && process_first && process_next &&
!= NULL)
{
/* heap list and heap walking */
+ /* HEAPLIST32 contains 3 fields that will change with
+ * each entry. Consider each field a source of 1 byte
+ * of entropy.
+ * HEAPENTRY32 contains 5 fields that will change with
+ * each entry. Consider each field a source of 1 byte
+ * of entropy.
+ */
hlist.dwSize = sizeof(HEAPLIST32);
if (heaplist_first(handle, &hlist))
do
{
- RAND_add(&hlist, hlist.dwSize, 0);
+ RAND_add(&hlist, hlist.dwSize, 3);
hentry.dwSize = sizeof(HEAPENTRY32);
if (heap_first(&hentry,
hlist.th32ProcessID,
hlist.th32HeapID))
+ {
+ int entrycnt = 80;
do
RAND_add(&hentry,
- hentry.dwSize, 0);
- while (heap_next(&hentry));
+ hentry.dwSize, 5);
+ while (heap_next(&hentry)
+ && --entrycnt > 0);
+ }
} while (heaplist_next(handle,
&hlist));
-
+
/* process walking */
+ /* PROCESSENTRY32 contains 9 fields that will change
+ * with each entry. Consider each field a source of
+ * 1 byte of entropy.
+ */
p.dwSize = sizeof(PROCESSENTRY32);
if (process_first(handle, &p))
do
- RAND_add(&p, p.dwSize, 0);
+ RAND_add(&p, p.dwSize, 9);
while (process_next(handle, &p));
-
+
/* thread walking */
+ /* THREADENTRY32 contains 6 fields that will change
+ * with each entry. Consider each field a source of
+ * 1 byte of entropy.
+ */
t.dwSize = sizeof(THREADENTRY32);
if (thread_first(handle, &t))
do
- RAND_add(&t, t.dwSize, 0);
+ RAND_add(&t, t.dwSize, 6);
while (thread_next(handle, &t));
-
+
/* module walking */
+ /* MODULEENTRY32 contains 9 fields that will change
+ * with each entry. Consider each field a source of
+ * 1 byte of entropy.
+ */
m.dwSize = sizeof(MODULEENTRY32);
if (module_first(handle, &m))
do
- RAND_add(&m, m.dwSize, 1);
+ RAND_add(&m, m.dwSize, 9);
while (module_next(handle, &m));
-
+
CloseHandle(handle);
}
+
+ FreeLibrary(kernel);
}
-#ifdef DEBUG
+#if 0
printf("Exiting RAND_poll\n");
#endif
/* feed timing information to the PRNG */
static void readtimer(void)
{
- DWORD w, cyclecount;
+ DWORD w;
LARGE_INTEGER l;
static int have_perfc = 1;
-#ifndef __GNUC__
+#if defined(_MSC_VER) && !defined(OPENSSL_SYS_WINCE)
static int have_tsc = 1;
+ DWORD cyclecount;
if (have_tsc) {
__try {
__asm {
- rdtsc
+ _emit 0x0f
+ _emit 0x31
mov cyclecount, eax
}
RAND_add(&cyclecount, sizeof(cyclecount), 1);
static void readscreen(void)
{
+#ifndef OPENSSL_SYS_WINCE
HDC hScrDC; /* screen DC */
HDC hMemDC; /* memory DC */
HBITMAP hBitmap; /* handle for our bitmap */
int n = 16; /* number of screen lines to grab at a time */
/* Create a screen DC and a memory DC compatible to screen DC */
- hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);
+ hScrDC = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
hMemDC = CreateCompatibleDC(hScrDC);
/* Get screen resolution */
DeleteObject(hBitmap);
DeleteDC(hMemDC);
DeleteDC(hScrDC);
-}
-
-#else /* Unix version */
-
-#include <time.h>
-
-int RAND_poll(void)
-{
- unsigned long l;
- pid_t curr_pid = getpid();
-#ifdef DEVRANDOM
- FILE *fh;
-#endif
-
-#ifdef DEVRANDOM
- /* Use a random entropy pool device. Linux, FreeBSD and OpenBSD
- * have this. Use /dev/urandom if you can as /dev/random may block
- * if it runs out of random entries. */
-
- if ((fh = fopen(DEVRANDOM, "r")) != NULL)
- {
- unsigned char tmpbuf[ENTROPY_NEEDED];
- int n;
-
- setvbuf(fh, NULL, _IONBF, 0);
- n=fread((unsigned char *)tmpbuf,1,ENTROPY_NEEDED,fh);
- fclose(fh);
- RAND_add(tmpbuf,sizeof tmpbuf,n);
- memset(tmpbuf,0,n);
- }
-#endif
-
- /* put in some default random data, we need more than just this */
- l=curr_pid;
- RAND_add(&l,sizeof(l),0);
- l=getuid();
- RAND_add(&l,sizeof(l),0);
-
- l=time(NULL);
- RAND_add(&l,sizeof(l),0);
-
-#ifdef DEVRANDOM
- return 1;
-#endif
- return 0;
+#endif /* !OPENSSL_SYS_WINCE */
}
#endif