*
*/
+#include "cryptlib.h"
+#include <openssl/rand.h>
+#include "rand_lcl.h"
-#ifdef WINDOWS
+#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
#include <windows.h>
-#include <openssl/rand.h>
-/* XXX There are probably other includes missing here ... */
-
-
-#if !defined(USE_MD5_RAND) && !defined(USE_SHA1_RAND) && !defined(USE_MDC2_RAND) && !defined(USE_MD2_RAND)
-#if !defined(NO_SHA) && !defined(NO_SHA1)
-#define USE_SHA1_RAND
-#elif !defined(NO_MD5)
-#define USE_MD5_RAND
-#elif !defined(NO_MDC2) && !defined(NO_DES)
-#define USE_MDC2_RAND
-#elif !defined(NO_MD2)
-#define USE_MD2_RAND
-#else
-#error No message digest algorithm available
+#ifndef _WIN32_WINNT
+# define _WIN32_WINNT 0x0400
+#endif
+#include <wincrypt.h>
+#include <tlhelp32.h>
+
+/* Limit the time spent walking through the heap, processes, threads and modules to
+ a maximum of 1000 miliseconds each, unless CryptoGenRandom failed */
+#define MAXDELAY 1000
+
+/* Intel hardware RNG CSP -- available from
+ * http://developer.intel.com/design/security/rng/redist_license.htm
+ */
+#define PROV_INTEL_SEC 22
+#define INTEL_DEF_PROV L"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 */
+
+#if !defined(OPENSSL_SYS_WINCE)
+typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTW)(HCRYPTPROV *, LPCWSTR, LPCWSTR,
+ DWORD, DWORD);
+typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV, DWORD, BYTE *);
+typedef BOOL (WINAPI *CRYPTRELEASECONTEXT)(HCRYPTPROV, DWORD);
+
+typedef HWND (WINAPI *GETFOREGROUNDWINDOW)(VOID);
+typedef BOOL (WINAPI *GETCURSORINFO)(PCURSORINFO);
+typedef DWORD (WINAPI *GETQUEUESTATUS)(UINT);
+
+typedef HANDLE (WINAPI *CREATETOOLHELP32SNAPSHOT)(DWORD, DWORD);
+typedef BOOL (WINAPI *CLOSETOOLHELP32SNAPSHOT)(HANDLE);
+typedef BOOL (WINAPI *HEAP32FIRST)(LPHEAPENTRY32, DWORD, size_t);
+typedef BOOL (WINAPI *HEAP32NEXT)(LPHEAPENTRY32);
+typedef BOOL (WINAPI *HEAP32LIST)(HANDLE, LPHEAPLIST32);
+typedef BOOL (WINAPI *PROCESS32)(HANDLE, LPPROCESSENTRY32);
+typedef BOOL (WINAPI *THREAD32)(HANDLE, LPTHREADENTRY32);
+typedef BOOL (WINAPI *MODULE32)(HANDLE, LPMODULEENTRY32);
+
+#include <lmcons.h>
+#include <lmstats.h>
+#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 */
+#endif /* !OPENSSL_SYS_WINCE */
+
+int RAND_poll(void)
+{
+ MEMORYSTATUS m;
+ HCRYPTPROV hProvider = 0;
+ DWORD w;
+ int good = 0;
+
+ /* 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 ) ;
+
+#if defined(OPENSSL_SYS_WINCE)
+# if defined(_WIN32_WCE) && _WIN32_WCE>=300
+/* Even though MSDN says _WIN32_WCE>=210, it doesn't seem to be available
+ * in commonly available implementations prior 300... */
+ {
+ BYTE buf[64];
+ /* poll the CryptoAPI PRNG */
+ /* The CryptoAPI returns sizeof(buf) bytes of randomness */
+ if (CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT))
+ {
+ if (CryptGenRandom(hProvider, sizeof(buf), buf))
+ RAND_add(buf, sizeof(buf), sizeof(buf));
+ CryptReleaseContext(hProvider, 0);
+ }
+ }
+# endif
+#else /* OPENSSL_SYS_WINCE */
+ /*
+ * None of below libraries are present on Windows CE, which is
+ * why we #ifndef the whole section. This also excuses us from
+ * handling the GetProcAddress issue. The trouble is that in
+ * real Win32 API GetProcAddress is available in ANSI flavor
+ * only. In WinCE on the other hand GetProcAddress is a macro
+ * most commonly defined as GetProcAddressW, which accepts
+ * Unicode argument. If we were to call GetProcAddress under
+ * WinCE, I'd recommend to either redefine GetProcAddress as
+ * GetProcAddressA (there seem to be one in common CE spec) or
+ * implement own shim routine, which would accept ANSI argument
+ * and expand it to Unicode.
+ */
+ {
+ /* load functions dynamically - not available on all systems */
+ HMODULE advapi = LoadLibrary(TEXT("ADVAPI32.DLL"));
+ HMODULE kernel = LoadLibrary(TEXT("KERNEL32.DLL"));
+ HMODULE user = NULL;
+ HMODULE netapi = LoadLibrary(TEXT("NETAPI32.DLL"));
+ CRYPTACQUIRECONTEXTW acquire = NULL;
+ CRYPTGENRANDOM gen = NULL;
+ CRYPTRELEASECONTEXT release = NULL;
+ NETSTATGET netstatget = NULL;
+ NETFREE netfree = NULL;
+ BYTE buf[64];
+
+ if (netapi)
+ {
+ netstatget = (NETSTATGET) GetProcAddress(netapi,"NetStatisticsGet");
+ netfree = (NETFREE) GetProcAddress(netapi,"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);
+
+ /* 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
+
+ if (advapi)
+ {
+ /*
+ * If it's available, then it's available in both ANSI
+ * and UNICODE flavors even in Win9x, documentation says.
+ * We favor Unicode...
+ */
+ acquire = (CRYPTACQUIRECONTEXTW) GetProcAddress(advapi,
+ "CryptAcquireContextW");
+ gen = (CRYPTGENRANDOM) GetProcAddress(advapi,
+ "CryptGenRandom");
+ release = (CRYPTRELEASECONTEXT) GetProcAddress(advapi,
+ "CryptReleaseContext");
+ }
+
+ if (acquire && gen && release)
+ {
+ /* poll the CryptoAPI PRNG */
+ /* The CryptoAPI returns sizeof(buf) bytes of randomness */
+ if (acquire(&hProvider, NULL, NULL, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT))
+ {
+ if (gen(hProvider, sizeof(buf), buf) != 0)
+ {
+ RAND_add(buf, sizeof(buf), 0);
+ good = 1;
+#if 0
+ printf("randomness from PROV_RSA_FULL\n");
#endif
+ }
+ release(hProvider, 0);
+ }
+
+ /* poll the Pentium PRG with CryptoAPI */
+ if (acquire(&hProvider, 0, INTEL_DEF_PROV, PROV_INTEL_SEC, 0))
+ {
+ if (gen(hProvider, sizeof(buf), buf) != 0)
+ {
+ RAND_add(buf, sizeof(buf), sizeof(buf));
+ good = 1;
+#if 0
+ printf("randomness from PROV_INTEL_SEC\n");
+#endif
+ }
+ release(hProvider, 0);
+ }
+ }
+
+ if (advapi)
+ FreeLibrary(advapi);
+
+ if ((osverinfo.dwPlatformId != VER_PLATFORM_WIN32_NT ||
+ !OPENSSL_isservice()) &&
+ (user = LoadLibrary(TEXT("USER32.DLL"))))
+ {
+ GETCURSORINFO cursor;
+ GETFOREGROUNDWINDOW win;
+ GETQUEUESTATUS queue;
+
+ win = (GETFOREGROUNDWINDOW) GetProcAddress(user, "GetForegroundWindow");
+ cursor = (GETCURSORINFO) GetProcAddress(user, "GetCursorInfo");
+ queue = (GETQUEUESTATUS) GetProcAddress(user, "GetQueueStatus");
-#if defined(USE_MD5_RAND)
-#include <openssl/md5.h>
-#define MD_DIGEST_LENGTH MD5_DIGEST_LENGTH
-#define MD(a,b,c) MD5(a,b,c)
-#elif defined(USE_SHA1_RAND)
-#include <openssl/sha.h>
-#define MD_DIGEST_LENGTH SHA_DIGEST_LENGTH
-#define MD(a,b,c) SHA1(a,b,c)
-#elif defined(USE_MDC2_RAND)
-#include <openssl/mdc2.h>
-#define MD_DIGEST_LENGTH MDC2_DIGEST_LENGTH
-#define MD(a,b,c) MDC2(a,b,c)
-#elif defined(USE_MD2_RAND)
-#include <openssl/md2.h>
-#define MD_DIGEST_LENGTH MD2_DIGEST_LENGTH
-#define MD(a,b,c) MD2(a,b,c)
+ if (win)
+ {
+ /* window handle */
+ HWND 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 */
+ /* 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), 1);
+ }
+
+ FreeLibrary(user);
+ }
+
+ /* Toolhelp32 snapshot: enumerate processes, threads, modules and heap
+ * http://msdn.microsoft.com/library/psdk/winbase/toolhelp_5pfd.htm
+ * (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.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.)
+ */
+
+ if (kernel)
+ {
+ CREATETOOLHELP32SNAPSHOT snap;
+ CLOSETOOLHELP32SNAPSHOT close_snap;
+ HANDLE handle;
+
+ HEAP32FIRST heap_first;
+ HEAP32NEXT heap_next;
+ HEAP32LIST heaplist_first, heaplist_next;
+ PROCESS32 process_first, process_next;
+ THREAD32 thread_first, thread_next;
+ MODULE32 module_first, module_next;
+
+ HEAPLIST32 hlist;
+ HEAPENTRY32 hentry;
+ PROCESSENTRY32 p;
+ THREADENTRY32 t;
+ MODULEENTRY32 m;
+ DWORD stoptime = 0;
+
+ snap = (CREATETOOLHELP32SNAPSHOT)
+ GetProcAddress(kernel, "CreateToolhelp32Snapshot");
+ close_snap = (CLOSETOOLHELP32SNAPSHOT)
+ GetProcAddress(kernel, "CloseToolhelp32Snapshot");
+ 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");
+
+ if (snap && heap_first && heap_next && heaplist_first &&
+ heaplist_next && process_first && process_next &&
+ thread_first && thread_next && module_first &&
+ module_next && (handle = snap(TH32CS_SNAPALL,0))
+ != INVALID_HANDLE_VALUE)
+ {
+ /* 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 (good) stoptime = GetTickCount() + MAXDELAY;
+ if (heaplist_first(handle, &hlist))
+ do
+ {
+ 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, 5);
+ while (heap_next(&hentry)
+ && --entrycnt > 0);
+ }
+ } while (heaplist_next(handle,
+ &hlist) && GetTickCount() < stoptime);
+
+ /* 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 (good) stoptime = GetTickCount() + MAXDELAY;
+ if (process_first(handle, &p))
+ do
+ RAND_add(&p, p.dwSize, 9);
+ while (process_next(handle, &p) && GetTickCount() < stoptime);
+
+ /* 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 (good) stoptime = GetTickCount() + MAXDELAY;
+ if (thread_first(handle, &t))
+ do
+ RAND_add(&t, t.dwSize, 6);
+ while (thread_next(handle, &t) && GetTickCount() < stoptime);
+
+ /* 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 (good) stoptime = GetTickCount() + MAXDELAY;
+ if (module_first(handle, &m))
+ do
+ RAND_add(&m, m.dwSize, 9);
+ while (module_next(handle, &m)
+ && (GetTickCount() < stoptime));
+ if (close_snap)
+ close_snap(handle);
+ else
+ CloseHandle(handle);
+
+ }
+
+ FreeLibrary(kernel);
+ }
+ }
+#endif /* !OPENSSL_SYS_WINCE */
+
+ /* timer data */
+ readtimer();
+
+ /* memory usage statistics */
+ GlobalMemoryStatus(&m);
+ RAND_add(&m, sizeof(m), 1);
+
+ /* process ID */
+ w = GetCurrentProcessId();
+ RAND_add(&w, sizeof(w), 1);
+
+#if 0
+ printf("Exiting RAND_poll\n");
#endif
+ return(1);
+}
int RAND_event(UINT iMsg, WPARAM wParam, LPARAM lParam)
{
double add_entropy=0;
- SYSTEMTIME t;
switch (iMsg)
{
break;
}
- GetSystemTime(&t);
+ readtimer();
RAND_add(&iMsg, sizeof(iMsg), add_entropy);
RAND_add(&wParam, sizeof(wParam), 0);
RAND_add(&lParam, sizeof(lParam), 0);
- RAND_add(&t, sizeof(t), 0);
-
+
return (RAND_status());
}
+void RAND_screen(void) /* function available for backward compatibility */
+{
+ RAND_poll();
+ readscreen();
+}
+
+
+/* feed timing information to the PRNG */
+static void readtimer(void)
+{
+ DWORD w;
+ LARGE_INTEGER l;
+ static int have_perfc = 1;
+#if defined(_MSC_VER) && defined(_M_X86)
+ static int have_tsc = 1;
+ DWORD cyclecount;
+
+ if (have_tsc) {
+ __try {
+ __asm {
+ _emit 0x0f
+ _emit 0x31
+ mov cyclecount, eax
+ }
+ RAND_add(&cyclecount, sizeof(cyclecount), 1);
+ } __except(EXCEPTION_EXECUTE_HANDLER) {
+ have_tsc = 0;
+ }
+ }
+#else
+# define have_tsc 0
+#endif
+
+ if (have_perfc) {
+ if (QueryPerformanceCounter(&l) == 0)
+ have_perfc = 0;
+ else
+ RAND_add(&l, sizeof(l), 0);
+ }
+
+ if (!have_tsc && !have_perfc) {
+ w = GetTickCount();
+ RAND_add(&w, sizeof(w), 0);
+ }
+}
+
+/* feed screen contents to PRNG */
/*****************************************************************************
- * Initialisation function for the SSL random generator. Takes the contents
- * of the screen as random seed.
*
* Created 960901 by Gertjan van Oosten, gertjan@West.NL, West Consulting B.V.
*
* Code adapted from
- * <URL:http://www.microsoft.com/kb/developr/win_dk/q97193.htm>;
+ * <URL:http://support.microsoft.com/default.aspx?scid=kb;[LN];97193>;
* the original copyright message is:
*
* (C) Copyright Microsoft Corp. 1993. All rights reserved.
* Microsoft has no warranty obligations or liability for any
* Sample Application Files which are modified.
*/
-/*
- * I have modified the loading of bytes via RAND_seed() mechanism since
- * the original would have been very very CPU intensive since RAND_seed()
- * does an MD5 per 16 bytes of input. The cost to digest 16 bytes is the same
- * as that to digest 56 bytes. So under the old system, a screen of
- * 1024*768*256 would have been CPU cost of approximately 49,000 56 byte MD5
- * digests or digesting 2.7 mbytes. What I have put in place would
- * be 48 16k MD5 digests, or effectively 48*16+48 MD5 bytes or 816 kbytes
- * or about 3.5 times as much.
- * - eric
- */
-void RAND_screen(void)
+
+static void readscreen(void)
{
+#if !defined(OPENSSL_SYS_WINCE) && !defined(OPENSSL_SYS_WIN32_CYGWIN)
HDC hScrDC; /* screen DC */
HDC hMemDC; /* memory DC */
HBITMAP hBitmap; /* handle for our bitmap */
int y; /* y-coordinate of screen lines to grab */
int n = 16; /* number of screen lines to grab at a time */
+ if (GetVersion() >= 0x80000000 || !OPENSSL_isservice())
+ return;
+
/* 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 */
/* Copy bitmap bits from memory DC to bmbits */
GetBitmapBits(hBitmap, size, bmbits);
- /* Get the MD5 of the bitmap */
+ /* Get the hash of the bitmap */
MD(bmbits,size,md);
- /* Seed the random generator with the MD5 digest */
- RAND_seed(md, MD_DIGEST_LENGTH);
+ /* Seed the random generator with the hash value */
+ RAND_add(md, MD_DIGEST_LENGTH, 0);
}
OPENSSL_free(bmbits);
DeleteObject(hBitmap);
DeleteDC(hMemDC);
DeleteDC(hScrDC);
+#endif /* !OPENSSL_SYS_WINCE */
}
-#else
-
-# if PEDANTIC
-static void *dummy=&dummy;
-# endif
-
#endif