rand_win.c 24.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
/* crypto/rand/rand_win.c */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
 * All rights reserved.
 *
 * This package is an SSL implementation written
 * by Eric Young (eay@cryptsoft.com).
 * The implementation was written so as to conform with Netscapes SSL.
 * 
 * This library is free for commercial and non-commercial use as long as
 * the following conditions are aheared to.  The following conditions
 * apply to all code found in this distribution, be it the RC4, RSA,
 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
 * included with this distribution is covered by the same copyright terms
 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
 * 
 * Copyright remains Eric Young's, and as such any Copyright notices in
 * the code are not to be removed.
 * If this package is used in a product, Eric Young should be given attribution
 * as the author of the parts of the library used.
 * This can be in the form of a textual message at program startup or
 * in documentation (online or textual) provided with the package.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *    "This product includes cryptographic software written by
 *     Eric Young (eay@cryptsoft.com)"
 *    The word 'cryptographic' can be left out if the rouines from the library
 *    being used are not cryptographic related :-).
 * 4. If you include any Windows specific code (or a derivative thereof) from 
 *    the apps directory (application code) you must include an acknowledgement:
 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
 * 
 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * 
 * The licence and distribution terms for any publically available version or
 * derivative of this code cannot be changed.  i.e. this code cannot simply be
 * copied and put under another distribution licence
 * [including the GNU Public Licence.]
 */
/* ====================================================================
 * Copyright (c) 1998-2000 The OpenSSL Project.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer. 
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. All advertising materials mentioning features or use of this
 *    software must display the following acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
 *
 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
 *    endorse or promote products derived from this software without
 *    prior written permission. For written permission, please contact
 *    openssl-core@openssl.org.
 *
 * 5. Products derived from this software may not be called "OpenSSL"
 *    nor may "OpenSSL" appear in their names without prior written
 *    permission of the OpenSSL Project.
 *
 * 6. Redistributions of any form whatsoever must retain the following
 *    acknowledgment:
 *    "This product includes software developed by the OpenSSL Project
 *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
 *
 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 * ====================================================================
 *
 * This product includes cryptographic software written by Eric Young
 * (eay@cryptsoft.com).  This product includes software written by Tim
 * Hudson (tjh@cryptsoft.com).
 *
 */

D
Dr. Stephen Henson 已提交
112

113

114 115 116
#include "cryptlib.h"
#include <openssl/rand.h>
#include "rand_lcl.h"
117

U
Ulf Möller 已提交
118
#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
119
#include <windows.h>
120 121
#ifndef _WIN32_WINNT
# define _WIN32_WINNT 0x0400
122
#endif
123 124 125
#include <wincrypt.h>
#include <tlhelp32.h>

U
Ulf Möller 已提交
126 127 128 129
/* 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

130 131 132 133
/* Intel hardware RNG CSP -- available from
 * http://developer.intel.com/design/security/rng/redist_license.htm
 */
#define PROV_INTEL_SEC 22
A
Andy Polyakov 已提交
134
#define INTEL_DEF_PROV L"Intel Hardware Cryptographic Service Provider"
135 136 137 138

static void readtimer(void);
static void readscreen(void);

139 140 141 142 143 144 145
/* 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. */

R
Richard Levitte 已提交
146
#ifndef CURSOR_SHOWING
147 148 149 150 151 152 153 154 155 156 157 158 159
/*
 * 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 */
R
Richard Levitte 已提交
160

A
Andy Polyakov 已提交
161
#if !defined(OPENSSL_SYS_WINCE)
A
Andy Polyakov 已提交
162
typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTW)(HCRYPTPROV *, LPCWSTR, LPCWSTR,
163 164 165 166 167 168 169 170 171
				    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);
172
typedef BOOL (WINAPI *CLOSETOOLHELP32SNAPSHOT)(HANDLE);
173
typedef BOOL (WINAPI *HEAP32FIRST)(LPHEAPENTRY32, DWORD, size_t);
174 175 176 177 178 179
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);

180 181
#include <lmcons.h>
#include <lmstats.h>
182 183 184 185 186
#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.
187
       */
188
typedef NET_API_STATUS (NET_API_FUNCTION * NETSTATGET)
189
        (LPWSTR, LPWSTR, DWORD, DWORD, LPBYTE*);
190
typedef NET_API_STATUS (NET_API_FUNCTION * NETFREE)(LPBYTE);
191
#endif /* 1 */
A
Andy Polyakov 已提交
192
#endif /* !OPENSSL_SYS_WINCE */
193

194 195 196 197 198
int RAND_poll(void)
{
	MEMORYSTATUS m;
	HCRYPTPROV hProvider = 0;
	DWORD w;
U
Ulf Möller 已提交
199
	int good = 0;
200 201


202
#if defined(OPENSSL_SYS_WINCE)
A
Andy Polyakov 已提交
203 204 205
# 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... */
A
Andy Polyakov 已提交
206 207
	{
	BYTE buf[64];
R
Richard Levitte 已提交
208 209
	/* poll the CryptoAPI PRNG */
	/* The CryptoAPI returns sizeof(buf) bytes of randomness */
A
Andy Polyakov 已提交
210 211
	if (CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL,
				CRYPT_VERIFYCONTEXT))
R
Richard Levitte 已提交
212 213 214 215 216
		{
		if (CryptGenRandom(hProvider, sizeof(buf), buf))
			RAND_add(buf, sizeof(buf), sizeof(buf));
		CryptReleaseContext(hProvider, 0); 
		}
A
Andy Polyakov 已提交
217
	}
218 219
# endif
#else	/* OPENSSL_SYS_WINCE */
A
Andy Polyakov 已提交
220 221 222 223 224 225 226 227 228 229 230 231 232
	/*
	 * 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.
	 */
233
	{
234
	/* load functions dynamically - not available on all systems */
235 236 237 238 239 240 241 242 243
	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;
A
Andy Polyakov 已提交
244
	BYTE buf[64];
245

246 247
	if (netapi)
		{
A
Andy Polyakov 已提交
248 249
		netstatget = (NETSTATGET) GetProcAddress(netapi,"NetStatisticsGet");
		netfree = (NETFREE) GetProcAddress(netapi,"NetApiBufferFree");
250 251 252 253 254
		}

	if (netstatget && netfree)
		{
		LPBYTE outbuf;
255 256 257 258 259 260
		/* 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.
                 */

261 262
		if (netstatget(NULL, L"LanmanWorkstation", 0, 0, &outbuf) == 0)
			{
263
			RAND_add(outbuf, sizeof(STAT_WORKSTATION_0), 45);
264 265 266 267
			netfree(outbuf);
			}
		if (netstatget(NULL, L"LanmanServer", 0, 0, &outbuf) == 0)
			{
268
			RAND_add(outbuf, sizeof(STAT_SERVER_0), 17);
269 270 271 272
			netfree(outbuf);
			}
		}

273 274
	if (netapi)
		FreeLibrary(netapi);
A
Andy Polyakov 已提交
275

276 277 278 279
        /* 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.
	 */
280 281 282

	if (advapi)
		{
A
Andy Polyakov 已提交
283 284 285 286 287 288 289
		/*
		 * 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");
290
		gen = (CRYPTGENRANDOM) GetProcAddress(advapi,
A
Andy Polyakov 已提交
291
			"CryptGenRandom");
292
		release = (CRYPTRELEASECONTEXT) GetProcAddress(advapi,
A
Andy Polyakov 已提交
293
			"CryptReleaseContext");
294 295 296 297 298
		}

	if (acquire && gen && release)
		{
		/* poll the CryptoAPI PRNG */
299
                /* The CryptoAPI returns sizeof(buf) bytes of randomness */
300
		if (acquire(&hProvider, NULL, NULL, PROV_RSA_FULL,
301 302 303 304
			CRYPT_VERIFYCONTEXT))
			{
			if (gen(hProvider, sizeof(buf), buf) != 0)
				{
305
				RAND_add(buf, sizeof(buf), 0);
U
Ulf Möller 已提交
306
				good = 1;
B
Bodo Möller 已提交
307
#if 0
308
				printf("randomness from PROV_RSA_FULL\n");
309
#endif
310 311 312 313 314 315 316 317 318
				}
			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)
				{
319
				RAND_add(buf, sizeof(buf), sizeof(buf));
U
Ulf Möller 已提交
320
				good = 1;
B
Bodo Möller 已提交
321
#if 0
322 323 324 325 326 327 328
				printf("randomness from PROV_INTEL_SEC\n");
#endif
				}
			release(hProvider, 0);
			}
		}

329 330 331
        if (advapi)
		FreeLibrary(advapi);

332
	if ((!check_winnt() ||
333 334
	     !OPENSSL_isservice()) &&
	    (user = LoadLibrary(TEXT("USER32.DLL"))))
335 336 337
		{
		GETCURSORINFO cursor;
		GETFOREGROUNDWINDOW win;
338
		GETQUEUESTATUS queue;
339

A
Andy Polyakov 已提交
340 341 342
		win = (GETFOREGROUNDWINDOW) GetProcAddress(user, "GetForegroundWindow");
		cursor = (GETCURSORINFO) GetProcAddress(user, "GetCursorInfo");
		queue = (GETQUEUESTATUS) GetProcAddress(user, "GetQueueStatus");
343 344

		if (win)
345
			{
346
			/* window handle */
347
			HWND h = win();
348
			RAND_add(&h, sizeof(h), 0);
349
			}
350 351 352 353 354 355
		if (cursor)
			{
			/* unfortunately, its not safe to call GetCursorInfo()
			 * on NT4 even though it exists in SP3 (or SP6) and
			 * higher.
			 */
356
			if (check_winnt() && !check_win_minplat(5))
357 358
				cursor = 0;
			}
359 360 361
		if (cursor)
			{
			/* cursor position */
362
                        /* assume 2 bytes of entropy */
363 364 365
			CURSORINFO ci;
			ci.cbSize = sizeof(CURSORINFO);
			if (cursor(&ci))
366
				RAND_add(&ci, ci.cbSize, 2);
367 368 369 370 371
			}

		if (queue)
			{
			/* message queue status */
372
                        /* assume 1 byte of entropy */
373
			w = queue(QS_ALLEVENTS);
374
			RAND_add(&w, sizeof(w), 1);
375
			}
376 377

		FreeLibrary(user);
378 379
		}

380 381
	/*-
	 * Toolhelp32 snapshot: enumerate processes, threads, modules and heap
382
	 * http://msdn.microsoft.com/library/psdk/winbase/toolhelp_5pfd.htm
383
	 * (Win 9x and 2000 only, not available on NT)
384 385 386
	 *
	 * This seeding method was proposed in Peter Gutmann, Software
	 * Generation of Practically Strong Random Numbers,
R
Richard Levitte 已提交
387
	 * http://www.usenix.org/publications/library/proceedings/sec98/gutmann.html
388
	 * revised version at http://www.cryptoengines.com/~peter/06_random.pdf
389 390 391 392 393 394 395 396
	 * (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;
397
		CLOSETOOLHELP32SNAPSHOT close_snap;
398 399 400 401 402 403 404 405 406 407 408 409 410 411
		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;
412
		DWORD starttime = 0;
413 414

		snap = (CREATETOOLHELP32SNAPSHOT)
A
Andy Polyakov 已提交
415
			GetProcAddress(kernel, "CreateToolhelp32Snapshot");
416
		close_snap = (CLOSETOOLHELP32SNAPSHOT)
A
Andy Polyakov 已提交
417 418 419 420 421 422 423 424 425 426 427
			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");
428 429 430 431 432

		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))
433
			!= INVALID_HANDLE_VALUE)
434 435
			{
			/* heap list and heap walking */
436 437 438 439 440 441 442
                        /* 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.
                         */
D
Dr. Stephen Henson 已提交
443
			ZeroMemory(&hlist, sizeof(HEAPLIST32));
444
			hlist.dwSize = sizeof(HEAPLIST32);		
445
			if (good) starttime = GetTickCount();
446
#ifdef _MSC_VER
447
			if (heaplist_first(handle, &hlist))
D
Dr. Stephen Henson 已提交
448 449 450 451 452 453 454 455 456 457 458 459
				{
				/*
				   following discussion on dev ML, exception on WinCE (or other Win
				   platform) is theoretically of unknown origin; prevent infinite
				   loop here when this theoretical case occurs; otherwise cope with
				   the expected (MSDN documented) exception-throwing behaviour of
				   Heap32Next() on WinCE.

				   based on patch in original message by Tanguy Fautré (2009/03/02)
			           Subject: RAND_poll() and CreateToolhelp32Snapshot() stability
			     */
				int ex_cnt_limit = 42; 
460 461
				do
					{
462
					RAND_add(&hlist, hlist.dwSize, 3);
D
Dr. Stephen Henson 已提交
463 464 465
					__try
						{
						ZeroMemory(&hentry, sizeof(HEAPENTRY32));
466 467 468 469
					hentry.dwSize = sizeof(HEAPENTRY32);
					if (heap_first(&hentry,
						hlist.th32ProcessID,
						hlist.th32HeapID))
R
Richard Levitte 已提交
470
						{
U
Ulf Möller 已提交
471
						int entrycnt = 80;
472 473
						do
							RAND_add(&hentry,
474
								hentry.dwSize, 5);
R
Richard Levitte 已提交
475
						while (heap_next(&hentry)
D
Dr. Stephen Henson 已提交
476
						&& (!good || (GetTickCount()-starttime)<MAXDELAY)
R
Richard Levitte 已提交
477 478
							&& --entrycnt > 0);
						}
D
Dr. Stephen Henson 已提交
479 480 481 482 483 484 485
						}
					__except (EXCEPTION_EXECUTE_HANDLER)
						{
							/* ignore access violations when walking the heap list */
							ex_cnt_limit--;
						}
					} while (heaplist_next(handle, &hlist) 
486
						&& (!good || (GetTickCount()-starttime)<MAXDELAY)
D
Dr. Stephen Henson 已提交
487 488
						&& ex_cnt_limit > 0);
				}
U
Ulf Möller 已提交
489

490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
#else
			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) 
509
						&& (!good || (GetTickCount()-starttime)<MAXDELAY));
510 511 512
				}
#endif

513
			/* process walking */
514 515 516 517
                        /* PROCESSENTRY32 contains 9 fields that will change
                         * with each entry.  Consider each field a source of
                         * 1 byte of entropy.
                         */
518
			p.dwSize = sizeof(PROCESSENTRY32);
U
Ulf Möller 已提交
519
		
520
			if (good) starttime = GetTickCount();
521 522
			if (process_first(handle, &p))
				do
523
					RAND_add(&p, p.dwSize, 9);
524
				while (process_next(handle, &p) && (!good || (GetTickCount()-starttime)<MAXDELAY));
525

526
			/* thread walking */
527 528 529 530
                        /* THREADENTRY32 contains 6 fields that will change
                         * with each entry.  Consider each field a source of
                         * 1 byte of entropy.
                         */
531
			t.dwSize = sizeof(THREADENTRY32);
532
			if (good) starttime = GetTickCount();
533 534
			if (thread_first(handle, &t))
				do
535
					RAND_add(&t, t.dwSize, 6);
536
				while (thread_next(handle, &t) && (!good || (GetTickCount()-starttime)<MAXDELAY));
537

538
			/* module walking */
539 540 541 542
                        /* MODULEENTRY32 contains 9 fields that will change
                         * with each entry.  Consider each field a source of
                         * 1 byte of entropy.
                         */
543
			m.dwSize = sizeof(MODULEENTRY32);
544
			if (good) starttime = GetTickCount();
545 546
			if (module_first(handle, &m))
				do
547
					RAND_add(&m, m.dwSize, 9);
548
				while (module_next(handle, &m)
549
					       	&& (!good || (GetTickCount()-starttime)<MAXDELAY));
550 551 552 553
			if (close_snap)
				close_snap(handle);
			else
				CloseHandle(handle);
U
Ulf Möller 已提交
554

555
			}
556 557

		FreeLibrary(kernel);
558
		}
559
	}
A
Andy Polyakov 已提交
560 561 562 563 564 565 566 567 568 569 570 571
#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);
572

B
Bodo Möller 已提交
573
#if 0
574
	printf("Exiting RAND_poll\n");
575 576
#endif

577 578
	return(1);
}
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610

int RAND_event(UINT iMsg, WPARAM wParam, LPARAM lParam)
        {
        double add_entropy=0;

        switch (iMsg)
                {
        case WM_KEYDOWN:
                        {
                        static WPARAM key;
                        if (key != wParam)
                                add_entropy = 0.05;
                        key = wParam;
                        }
                        break;
	case WM_MOUSEMOVE:
                        {
                        static int lastx,lasty,lastdx,lastdy;
                        int x,y,dx,dy;

                        x=LOWORD(lParam);
                        y=HIWORD(lParam);
                        dx=lastx-x;
                        dy=lasty-y;
                        if (dx != 0 && dy != 0 && dx-lastdx != 0 && dy-lastdy != 0)
                                add_entropy=.2;
                        lastx=x, lasty=y;
                        lastdx=dx, lastdy=dy;
                        }
		break;
		}

611
	readtimer();
612 613 614
        RAND_add(&iMsg, sizeof(iMsg), add_entropy);
	RAND_add(&wParam, sizeof(wParam), 0);
	RAND_add(&lParam, sizeof(lParam), 0);
615
 
616 617 618 619
	return (RAND_status());
	}


620 621 622
void RAND_screen(void) /* function available for backward compatibility */
{
	RAND_poll();
623
	readscreen();
624 625 626 627 628 629
}


/* feed timing information to the PRNG */
static void readtimer(void)
{
630
	DWORD w;
631 632
	LARGE_INTEGER l;
	static int have_perfc = 1;
A
Andy Polyakov 已提交
633
#if defined(_MSC_VER) && defined(_M_X86)
634
	static int have_tsc = 1;
635
	DWORD cyclecount;
636 637 638 639

	if (have_tsc) {
	  __try {
	    __asm {
U
Ulf Möller 已提交
640
	      _emit 0x0f
D
Typo.  
Dr. Stephen Henson 已提交
641
	      _emit 0x31
642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666
	      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 */
667 668 669 670 671
/*****************************************************************************
 *
 * Created 960901 by Gertjan van Oosten, gertjan@West.NL, West Consulting B.V.
 *
 * Code adapted from
L
Lutz Jänicke 已提交
672
 * <URL:http://support.microsoft.com/default.aspx?scid=kb;[LN];97193>;
673 674 675 676 677 678 679 680 681 682
 * the original copyright message is:
 *
 *   (C) Copyright Microsoft Corp. 1993.  All rights reserved.
 *
 *   You have a royalty-free right to use, modify, reproduce and
 *   distribute the Sample Files (and/or any modified version) in
 *   any way you find useful, provided that you agree that
 *   Microsoft has no warranty obligations or liability for any
 *   Sample Application Files which are modified.
 */
683 684

static void readscreen(void)
685
{
686
#if !defined(OPENSSL_SYS_WINCE) && !defined(OPENSSL_SYS_WIN32_CYGWIN)
687 688 689 690 691 692 693 694 695
  HDC		hScrDC;		/* screen DC */
  HBITMAP	hBitmap;	/* handle for our bitmap */
  BITMAP	bm;		/* bitmap properties */
  unsigned int	size;		/* size of bitmap */
  char		*bmbits;	/* contents of bitmap */
  int		w;		/* screen width */
  int		h;		/* screen height */
  int		y;		/* y-coordinate of screen lines to grab */
  int		n = 16;		/* number of screen lines to grab at a time */
696
  BITMAPINFOHEADER bi;		/* info about the bitmap */
697

698
  if (check_winnt() && OPENSSL_isservice()>0)
699 700
    return;

701 702
  /* Get a reference to the screen DC */
  hScrDC = GetDC(NULL);
703 704 705 706 707 708 709 710 711 712 713 714

  /* Get screen resolution */
  w = GetDeviceCaps(hScrDC, HORZRES);
  h = GetDeviceCaps(hScrDC, VERTRES);

  /* Create a bitmap compatible with the screen DC */
  hBitmap = CreateCompatibleBitmap(hScrDC, w, n);

  /* Get bitmap properties */
  GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bm);
  size = (unsigned int)bm.bmWidthBytes * bm.bmHeight * bm.bmPlanes;

715 716 717 718 719 720 721 722 723 724 725 726
  bi.biSize = sizeof(BITMAPINFOHEADER);
  bi.biWidth = bm.bmWidth;
  bi.biHeight = bm.bmHeight;
  bi.biPlanes = bm.bmPlanes;
  bi.biBitCount = bm.bmBitsPixel;
  bi.biCompression = BI_RGB;
  bi.biSizeImage = 0;
  bi.biXPelsPerMeter = 0;
  bi.biYPelsPerMeter = 0;
  bi.biClrUsed = 0;
  bi.biClrImportant = 0;

727
  bmbits = OPENSSL_malloc(size);
728 729 730 731 732 733
  if (bmbits) {
    /* Now go through the whole screen, repeatedly grabbing n lines */
    for (y = 0; y < h-n; y += n)
    	{
	unsigned char md[MD_DIGEST_LENGTH];

734 735 736
	/* Copy the bits of the current line range into the buffer */
	GetDIBits(hScrDC, hBitmap, y, n,
		  bmbits, (BITMAPINFO *)&bi, DIB_RGB_COLORS);
737

738
	/* Get the hash of the bitmap */
739 740
	MD(bmbits,size,md);

741 742
	/* Seed the random generator with the hash value */
	RAND_add(md, MD_DIGEST_LENGTH, 0);
743 744
	}

745
    OPENSSL_free(bmbits);
746 747 748 749
  }

  /* Clean up */
  DeleteObject(hBitmap);
750
  ReleaseDC(NULL, hScrDC);
R
Richard Levitte 已提交
751
#endif /* !OPENSSL_SYS_WINCE */
752 753 754
}

#endif