~ubuntu-branches/ubuntu/precise/openssl098/precise

« back to all changes in this revision

Viewing changes to crypto/rand/rand_win.c

  • Committer: Bazaar Package Importer
  • Author(s): Kurt Roeckx
  • Date: 2011-03-23 19:50:31 UTC
  • Revision ID: james.westby@ubuntu.com-20110323195031-6h9crj4bymhhr8b8
Tags: upstream-0.9.8o
ImportĀ upstreamĀ versionĀ 0.9.8o

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* crypto/rand/rand_win.c */
 
2
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
 
3
 * All rights reserved.
 
4
 *
 
5
 * This package is an SSL implementation written
 
6
 * by Eric Young (eay@cryptsoft.com).
 
7
 * The implementation was written so as to conform with Netscapes SSL.
 
8
 * 
 
9
 * This library is free for commercial and non-commercial use as long as
 
10
 * the following conditions are aheared to.  The following conditions
 
11
 * apply to all code found in this distribution, be it the RC4, RSA,
 
12
 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
 
13
 * included with this distribution is covered by the same copyright terms
 
14
 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
 
15
 * 
 
16
 * Copyright remains Eric Young's, and as such any Copyright notices in
 
17
 * the code are not to be removed.
 
18
 * If this package is used in a product, Eric Young should be given attribution
 
19
 * as the author of the parts of the library used.
 
20
 * This can be in the form of a textual message at program startup or
 
21
 * in documentation (online or textual) provided with the package.
 
22
 * 
 
23
 * Redistribution and use in source and binary forms, with or without
 
24
 * modification, are permitted provided that the following conditions
 
25
 * are met:
 
26
 * 1. Redistributions of source code must retain the copyright
 
27
 *    notice, this list of conditions and the following disclaimer.
 
28
 * 2. Redistributions in binary form must reproduce the above copyright
 
29
 *    notice, this list of conditions and the following disclaimer in the
 
30
 *    documentation and/or other materials provided with the distribution.
 
31
 * 3. All advertising materials mentioning features or use of this software
 
32
 *    must display the following acknowledgement:
 
33
 *    "This product includes cryptographic software written by
 
34
 *     Eric Young (eay@cryptsoft.com)"
 
35
 *    The word 'cryptographic' can be left out if the rouines from the library
 
36
 *    being used are not cryptographic related :-).
 
37
 * 4. If you include any Windows specific code (or a derivative thereof) from 
 
38
 *    the apps directory (application code) you must include an acknowledgement:
 
39
 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
 
40
 * 
 
41
 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
 
42
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
43
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 
44
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 
45
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 
46
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 
47
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
48
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 
49
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 
50
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 
51
 * SUCH DAMAGE.
 
52
 * 
 
53
 * The licence and distribution terms for any publically available version or
 
54
 * derivative of this code cannot be changed.  i.e. this code cannot simply be
 
55
 * copied and put under another distribution licence
 
56
 * [including the GNU Public Licence.]
 
57
 */
 
58
/* ====================================================================
 
59
 * Copyright (c) 1998-2000 The OpenSSL Project.  All rights reserved.
 
60
 *
 
61
 * Redistribution and use in source and binary forms, with or without
 
62
 * modification, are permitted provided that the following conditions
 
63
 * are met:
 
64
 *
 
65
 * 1. Redistributions of source code must retain the above copyright
 
66
 *    notice, this list of conditions and the following disclaimer. 
 
67
 *
 
68
 * 2. Redistributions in binary form must reproduce the above copyright
 
69
 *    notice, this list of conditions and the following disclaimer in
 
70
 *    the documentation and/or other materials provided with the
 
71
 *    distribution.
 
72
 *
 
73
 * 3. All advertising materials mentioning features or use of this
 
74
 *    software must display the following acknowledgment:
 
75
 *    "This product includes software developed by the OpenSSL Project
 
76
 *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
 
77
 *
 
78
 * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
 
79
 *    endorse or promote products derived from this software without
 
80
 *    prior written permission. For written permission, please contact
 
81
 *    openssl-core@openssl.org.
 
82
 *
 
83
 * 5. Products derived from this software may not be called "OpenSSL"
 
84
 *    nor may "OpenSSL" appear in their names without prior written
 
85
 *    permission of the OpenSSL Project.
 
86
 *
 
87
 * 6. Redistributions of any form whatsoever must retain the following
 
88
 *    acknowledgment:
 
89
 *    "This product includes software developed by the OpenSSL Project
 
90
 *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
 
91
 *
 
92
 * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
 
93
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 
94
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
95
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
 
96
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 
97
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
98
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 
99
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 
100
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 
101
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 
102
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 
103
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 
104
 * ====================================================================
 
105
 *
 
106
 * This product includes cryptographic software written by Eric Young
 
107
 * (eay@cryptsoft.com).  This product includes software written by Tim
 
108
 * Hudson (tjh@cryptsoft.com).
 
109
 *
 
110
 */
 
111
 
 
112
#include "cryptlib.h"
 
113
#include <openssl/rand.h>
 
114
#include "rand_lcl.h"
 
115
 
 
116
#if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
 
117
#include <windows.h>
 
118
#ifndef _WIN32_WINNT
 
119
# define _WIN32_WINNT 0x0400
 
120
#endif
 
121
#include <wincrypt.h>
 
122
#include <tlhelp32.h>
 
123
 
 
124
/* Limit the time spent walking through the heap, processes, threads and modules to
 
125
   a maximum of 1000 miliseconds each, unless CryptoGenRandom failed */
 
126
#define MAXDELAY 1000
 
127
 
 
128
/* Intel hardware RNG CSP -- available from
 
129
 * http://developer.intel.com/design/security/rng/redist_license.htm
 
130
 */
 
131
#define PROV_INTEL_SEC 22
 
132
#define INTEL_DEF_PROV L"Intel Hardware Cryptographic Service Provider"
 
133
 
 
134
static void readtimer(void);
 
135
static void readscreen(void);
 
136
 
 
137
/* It appears like CURSORINFO, PCURSORINFO and LPCURSORINFO are only defined
 
138
   when WINVER is 0x0500 and up, which currently only happens on Win2000.
 
139
   Unfortunately, those are typedefs, so they're a little bit difficult to
 
140
   detect properly.  On the other hand, the macro CURSOR_SHOWING is defined
 
141
   within the same conditional, so it can be use to detect the absence of said
 
142
   typedefs. */
 
143
 
 
144
#ifndef CURSOR_SHOWING
 
145
/*
 
146
 * Information about the global cursor.
 
147
 */
 
148
typedef struct tagCURSORINFO
 
149
{
 
150
    DWORD   cbSize;
 
151
    DWORD   flags;
 
152
    HCURSOR hCursor;
 
153
    POINT   ptScreenPos;
 
154
} CURSORINFO, *PCURSORINFO, *LPCURSORINFO;
 
155
 
 
156
#define CURSOR_SHOWING     0x00000001
 
157
#endif /* CURSOR_SHOWING */
 
158
 
 
159
#if !defined(OPENSSL_SYS_WINCE)
 
160
typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTW)(HCRYPTPROV *, LPCWSTR, LPCWSTR,
 
161
                                    DWORD, DWORD);
 
162
typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV, DWORD, BYTE *);
 
163
typedef BOOL (WINAPI *CRYPTRELEASECONTEXT)(HCRYPTPROV, DWORD);
 
164
 
 
165
typedef HWND (WINAPI *GETFOREGROUNDWINDOW)(VOID);
 
166
typedef BOOL (WINAPI *GETCURSORINFO)(PCURSORINFO);
 
167
typedef DWORD (WINAPI *GETQUEUESTATUS)(UINT);
 
168
 
 
169
typedef HANDLE (WINAPI *CREATETOOLHELP32SNAPSHOT)(DWORD, DWORD);
 
170
typedef BOOL (WINAPI *CLOSETOOLHELP32SNAPSHOT)(HANDLE);
 
171
typedef BOOL (WINAPI *HEAP32FIRST)(LPHEAPENTRY32, DWORD, size_t);
 
172
typedef BOOL (WINAPI *HEAP32NEXT)(LPHEAPENTRY32);
 
173
typedef BOOL (WINAPI *HEAP32LIST)(HANDLE, LPHEAPLIST32);
 
174
typedef BOOL (WINAPI *PROCESS32)(HANDLE, LPPROCESSENTRY32);
 
175
typedef BOOL (WINAPI *THREAD32)(HANDLE, LPTHREADENTRY32);
 
176
typedef BOOL (WINAPI *MODULE32)(HANDLE, LPMODULEENTRY32);
 
177
 
 
178
#include <lmcons.h>
 
179
#include <lmstats.h>
 
180
#if 1 /* The NET API is Unicode only.  It requires the use of the UNICODE
 
181
       * macro.  When UNICODE is defined LPTSTR becomes LPWSTR.  LMSTR was
 
182
       * was added to the Platform SDK to allow the NET API to be used in
 
183
       * non-Unicode applications provided that Unicode strings were still
 
184
       * used for input.  LMSTR is defined as LPWSTR.
 
185
       */
 
186
typedef NET_API_STATUS (NET_API_FUNCTION * NETSTATGET)
 
187
        (LPWSTR, LPWSTR, DWORD, DWORD, LPBYTE*);
 
188
typedef NET_API_STATUS (NET_API_FUNCTION * NETFREE)(LPBYTE);
 
189
#endif /* 1 */
 
190
#endif /* !OPENSSL_SYS_WINCE */
 
191
 
 
192
int RAND_poll(void)
 
193
{
 
194
        MEMORYSTATUS m;
 
195
        HCRYPTPROV hProvider = 0;
 
196
        DWORD w;
 
197
        int good = 0;
 
198
 
 
199
        /* Determine the OS version we are on so we can turn off things 
 
200
         * that do not work properly.
 
201
         */
 
202
        OSVERSIONINFO osverinfo ;
 
203
        osverinfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO) ;
 
204
        GetVersionEx( &osverinfo ) ;
 
205
 
 
206
#if defined(OPENSSL_SYS_WINCE)
 
207
# if defined(_WIN32_WCE) && _WIN32_WCE>=300
 
208
/* Even though MSDN says _WIN32_WCE>=210, it doesn't seem to be available
 
209
 * in commonly available implementations prior 300... */
 
210
        {
 
211
        BYTE buf[64];
 
212
        /* poll the CryptoAPI PRNG */
 
213
        /* The CryptoAPI returns sizeof(buf) bytes of randomness */
 
214
        if (CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL,
 
215
                                CRYPT_VERIFYCONTEXT))
 
216
                {
 
217
                if (CryptGenRandom(hProvider, sizeof(buf), buf))
 
218
                        RAND_add(buf, sizeof(buf), sizeof(buf));
 
219
                CryptReleaseContext(hProvider, 0); 
 
220
                }
 
221
        }
 
222
# endif
 
223
#else   /* OPENSSL_SYS_WINCE */
 
224
        /*
 
225
         * None of below libraries are present on Windows CE, which is
 
226
         * why we #ifndef the whole section. This also excuses us from
 
227
         * handling the GetProcAddress issue. The trouble is that in
 
228
         * real Win32 API GetProcAddress is available in ANSI flavor
 
229
         * only. In WinCE on the other hand GetProcAddress is a macro
 
230
         * most commonly defined as GetProcAddressW, which accepts
 
231
         * Unicode argument. If we were to call GetProcAddress under
 
232
         * WinCE, I'd recommend to either redefine GetProcAddress as
 
233
         * GetProcAddressA (there seem to be one in common CE spec) or
 
234
         * implement own shim routine, which would accept ANSI argument
 
235
         * and expand it to Unicode.
 
236
         */
 
237
        {
 
238
        /* load functions dynamically - not available on all systems */
 
239
        HMODULE advapi = LoadLibrary(TEXT("ADVAPI32.DLL"));
 
240
        HMODULE kernel = LoadLibrary(TEXT("KERNEL32.DLL"));
 
241
        HMODULE user = NULL;
 
242
        HMODULE netapi = LoadLibrary(TEXT("NETAPI32.DLL"));
 
243
        CRYPTACQUIRECONTEXTW acquire = NULL;
 
244
        CRYPTGENRANDOM gen = NULL;
 
245
        CRYPTRELEASECONTEXT release = NULL;
 
246
        NETSTATGET netstatget = NULL;
 
247
        NETFREE netfree = NULL;
 
248
        BYTE buf[64];
 
249
 
 
250
        if (netapi)
 
251
                {
 
252
                netstatget = (NETSTATGET) GetProcAddress(netapi,"NetStatisticsGet");
 
253
                netfree = (NETFREE) GetProcAddress(netapi,"NetApiBufferFree");
 
254
                }
 
255
 
 
256
        if (netstatget && netfree)
 
257
                {
 
258
                LPBYTE outbuf;
 
259
                /* NetStatisticsGet() is a Unicode only function
 
260
                 * STAT_WORKSTATION_0 contains 45 fields and STAT_SERVER_0
 
261
                 * contains 17 fields.  We treat each field as a source of
 
262
                 * one byte of entropy.
 
263
                 */
 
264
 
 
265
                if (netstatget(NULL, L"LanmanWorkstation", 0, 0, &outbuf) == 0)
 
266
                        {
 
267
                        RAND_add(outbuf, sizeof(STAT_WORKSTATION_0), 45);
 
268
                        netfree(outbuf);
 
269
                        }
 
270
                if (netstatget(NULL, L"LanmanServer", 0, 0, &outbuf) == 0)
 
271
                        {
 
272
                        RAND_add(outbuf, sizeof(STAT_SERVER_0), 17);
 
273
                        netfree(outbuf);
 
274
                        }
 
275
                }
 
276
 
 
277
        if (netapi)
 
278
                FreeLibrary(netapi);
 
279
 
 
280
        /* It appears like this can cause an exception deep within ADVAPI32.DLL
 
281
         * at random times on Windows 2000.  Reported by Jeffrey Altman.  
 
282
         * Only use it on NT.
 
283
         */
 
284
        /* Wolfgang Marczy <WMarczy@topcall.co.at> reports that
 
285
         * the RegQueryValueEx call below can hang on NT4.0 (SP6).
 
286
         * So we don't use this at all for now. */
 
287
#if 0
 
288
        if ( osverinfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
 
289
                osverinfo.dwMajorVersion < 5)
 
290
                {
 
291
                /* Read Performance Statistics from NT/2000 registry
 
292
                 * The size of the performance data can vary from call
 
293
                 * to call so we must guess the size of the buffer to use
 
294
                 * and increase its size if we get an ERROR_MORE_DATA
 
295
                 * return instead of ERROR_SUCCESS.
 
296
                 */
 
297
                LONG   rc=ERROR_MORE_DATA;
 
298
                char * buf=NULL;
 
299
                DWORD bufsz=0;
 
300
                DWORD length;
 
301
 
 
302
                while (rc == ERROR_MORE_DATA)
 
303
                        {
 
304
                        buf = realloc(buf,bufsz+8192);
 
305
                        if (!buf)
 
306
                                break;
 
307
                        bufsz += 8192;
 
308
 
 
309
                        length = bufsz;
 
310
                        rc = RegQueryValueEx(HKEY_PERFORMANCE_DATA, TEXT("Global"),
 
311
                                NULL, NULL, buf, &length);
 
312
                        }
 
313
                if (rc == ERROR_SUCCESS)
 
314
                        {
 
315
                        /* For entropy count assume only least significant
 
316
                         * byte of each DWORD is random.
 
317
                         */
 
318
                        RAND_add(&length, sizeof(length), 0);
 
319
                        RAND_add(buf, length, length / 4.0);
 
320
 
 
321
                        /* Close the Registry Key to allow Windows to cleanup/close
 
322
                         * the open handle
 
323
                         * Note: The 'HKEY_PERFORMANCE_DATA' key is implicitly opened
 
324
                         *       when the RegQueryValueEx above is done.  However, if
 
325
                         *       it is not explicitly closed, it can cause disk
 
326
                         *       partition manipulation problems.
 
327
                         */
 
328
                        RegCloseKey(HKEY_PERFORMANCE_DATA);
 
329
                        }
 
330
                if (buf)
 
331
                        free(buf);
 
332
                }
 
333
#endif
 
334
 
 
335
        if (advapi)
 
336
                {
 
337
                /*
 
338
                 * If it's available, then it's available in both ANSI
 
339
                 * and UNICODE flavors even in Win9x, documentation says.
 
340
                 * We favor Unicode...
 
341
                 */
 
342
                acquire = (CRYPTACQUIRECONTEXTW) GetProcAddress(advapi,
 
343
                        "CryptAcquireContextW");
 
344
                gen = (CRYPTGENRANDOM) GetProcAddress(advapi,
 
345
                        "CryptGenRandom");
 
346
                release = (CRYPTRELEASECONTEXT) GetProcAddress(advapi,
 
347
                        "CryptReleaseContext");
 
348
                }
 
349
 
 
350
        if (acquire && gen && release)
 
351
                {
 
352
                /* poll the CryptoAPI PRNG */
 
353
                /* The CryptoAPI returns sizeof(buf) bytes of randomness */
 
354
                if (acquire(&hProvider, NULL, NULL, PROV_RSA_FULL,
 
355
                        CRYPT_VERIFYCONTEXT))
 
356
                        {
 
357
                        if (gen(hProvider, sizeof(buf), buf) != 0)
 
358
                                {
 
359
                                RAND_add(buf, sizeof(buf), 0);
 
360
                                good = 1;
 
361
#if 0
 
362
                                printf("randomness from PROV_RSA_FULL\n");
 
363
#endif
 
364
                                }
 
365
                        release(hProvider, 0); 
 
366
                        }
 
367
                
 
368
                /* poll the Pentium PRG with CryptoAPI */
 
369
                if (acquire(&hProvider, 0, INTEL_DEF_PROV, PROV_INTEL_SEC, 0))
 
370
                        {
 
371
                        if (gen(hProvider, sizeof(buf), buf) != 0)
 
372
                                {
 
373
                                RAND_add(buf, sizeof(buf), sizeof(buf));
 
374
                                good = 1;
 
375
#if 0
 
376
                                printf("randomness from PROV_INTEL_SEC\n");
 
377
#endif
 
378
                                }
 
379
                        release(hProvider, 0);
 
380
                        }
 
381
                }
 
382
 
 
383
        if (advapi)
 
384
                FreeLibrary(advapi);
 
385
 
 
386
        if ((osverinfo.dwPlatformId != VER_PLATFORM_WIN32_NT ||
 
387
             !OPENSSL_isservice()) &&
 
388
            (user = LoadLibrary(TEXT("USER32.DLL"))))
 
389
                {
 
390
                GETCURSORINFO cursor;
 
391
                GETFOREGROUNDWINDOW win;
 
392
                GETQUEUESTATUS queue;
 
393
 
 
394
                win = (GETFOREGROUNDWINDOW) GetProcAddress(user, "GetForegroundWindow");
 
395
                cursor = (GETCURSORINFO) GetProcAddress(user, "GetCursorInfo");
 
396
                queue = (GETQUEUESTATUS) GetProcAddress(user, "GetQueueStatus");
 
397
 
 
398
                if (win)
 
399
                        {
 
400
                        /* window handle */
 
401
                        HWND h = win();
 
402
                        RAND_add(&h, sizeof(h), 0);
 
403
                        }
 
404
                if (cursor)
 
405
                        {
 
406
                        /* unfortunately, its not safe to call GetCursorInfo()
 
407
                         * on NT4 even though it exists in SP3 (or SP6) and
 
408
                         * higher.
 
409
                         */
 
410
                        if ( osverinfo.dwPlatformId == VER_PLATFORM_WIN32_NT &&
 
411
                                osverinfo.dwMajorVersion < 5)
 
412
                                cursor = 0;
 
413
                        }
 
414
                if (cursor)
 
415
                        {
 
416
                        /* cursor position */
 
417
                        /* assume 2 bytes of entropy */
 
418
                        CURSORINFO ci;
 
419
                        ci.cbSize = sizeof(CURSORINFO);
 
420
                        if (cursor(&ci))
 
421
                                RAND_add(&ci, ci.cbSize, 2);
 
422
                        }
 
423
 
 
424
                if (queue)
 
425
                        {
 
426
                        /* message queue status */
 
427
                        /* assume 1 byte of entropy */
 
428
                        w = queue(QS_ALLEVENTS);
 
429
                        RAND_add(&w, sizeof(w), 1);
 
430
                        }
 
431
 
 
432
                FreeLibrary(user);
 
433
                }
 
434
 
 
435
        /* Toolhelp32 snapshot: enumerate processes, threads, modules and heap
 
436
         * http://msdn.microsoft.com/library/psdk/winbase/toolhelp_5pfd.htm
 
437
         * (Win 9x and 2000 only, not available on NT)
 
438
         *
 
439
         * This seeding method was proposed in Peter Gutmann, Software
 
440
         * Generation of Practically Strong Random Numbers,
 
441
         * http://www.usenix.org/publications/library/proceedings/sec98/gutmann.html
 
442
         * revised version at http://www.cryptoengines.com/~peter/06_random.pdf
 
443
         * (The assignment of entropy estimates below is arbitrary, but based
 
444
         * on Peter's analysis the full poll appears to be safe. Additional
 
445
         * interactive seeding is encouraged.)
 
446
         */
 
447
 
 
448
        if (kernel)
 
449
                {
 
450
                CREATETOOLHELP32SNAPSHOT snap;
 
451
                CLOSETOOLHELP32SNAPSHOT close_snap;
 
452
                HANDLE handle;
 
453
 
 
454
                HEAP32FIRST heap_first;
 
455
                HEAP32NEXT heap_next;
 
456
                HEAP32LIST heaplist_first, heaplist_next;
 
457
                PROCESS32 process_first, process_next;
 
458
                THREAD32 thread_first, thread_next;
 
459
                MODULE32 module_first, module_next;
 
460
 
 
461
                HEAPLIST32 hlist;
 
462
                HEAPENTRY32 hentry;
 
463
                PROCESSENTRY32 p;
 
464
                THREADENTRY32 t;
 
465
                MODULEENTRY32 m;
 
466
                DWORD starttime = 0;
 
467
 
 
468
                snap = (CREATETOOLHELP32SNAPSHOT)
 
469
                        GetProcAddress(kernel, "CreateToolhelp32Snapshot");
 
470
                close_snap = (CLOSETOOLHELP32SNAPSHOT)
 
471
                        GetProcAddress(kernel, "CloseToolhelp32Snapshot");
 
472
                heap_first = (HEAP32FIRST) GetProcAddress(kernel, "Heap32First");
 
473
                heap_next = (HEAP32NEXT) GetProcAddress(kernel, "Heap32Next");
 
474
                heaplist_first = (HEAP32LIST) GetProcAddress(kernel, "Heap32ListFirst");
 
475
                heaplist_next = (HEAP32LIST) GetProcAddress(kernel, "Heap32ListNext");
 
476
                process_first = (PROCESS32) GetProcAddress(kernel, "Process32First");
 
477
                process_next = (PROCESS32) GetProcAddress(kernel, "Process32Next");
 
478
                thread_first = (THREAD32) GetProcAddress(kernel, "Thread32First");
 
479
                thread_next = (THREAD32) GetProcAddress(kernel, "Thread32Next");
 
480
                module_first = (MODULE32) GetProcAddress(kernel, "Module32First");
 
481
                module_next = (MODULE32) GetProcAddress(kernel, "Module32Next");
 
482
 
 
483
                if (snap && heap_first && heap_next && heaplist_first &&
 
484
                        heaplist_next && process_first && process_next &&
 
485
                        thread_first && thread_next && module_first &&
 
486
                        module_next && (handle = snap(TH32CS_SNAPALL,0))
 
487
                        != INVALID_HANDLE_VALUE)
 
488
                        {
 
489
                        /* heap list and heap walking */
 
490
                        /* HEAPLIST32 contains 3 fields that will change with
 
491
                         * each entry.  Consider each field a source of 1 byte
 
492
                         * of entropy.
 
493
                         * HEAPENTRY32 contains 5 fields that will change with 
 
494
                         * each entry.  Consider each field a source of 1 byte
 
495
                         * of entropy.
 
496
                         */
 
497
                        ZeroMemory(&hlist, sizeof(HEAPLIST32));
 
498
                        hlist.dwSize = sizeof(HEAPLIST32);              
 
499
                        if (good) starttime = GetTickCount();
 
500
#ifdef _MSC_VER
 
501
                        if (heaplist_first(handle, &hlist))
 
502
                                {
 
503
                                /*
 
504
                                   following discussion on dev ML, exception on WinCE (or other Win
 
505
                                   platform) is theoretically of unknown origin; prevent infinite
 
506
                                   loop here when this theoretical case occurs; otherwise cope with
 
507
                                   the expected (MSDN documented) exception-throwing behaviour of
 
508
                                   Heap32Next() on WinCE.
 
509
 
 
510
                                   based on patch in original message by Tanguy FautrĆ© (2009/03/02)
 
511
                                   Subject: RAND_poll() and CreateToolhelp32Snapshot() stability
 
512
                             */
 
513
                                int ex_cnt_limit = 42; 
 
514
                                do
 
515
                                        {
 
516
                                        RAND_add(&hlist, hlist.dwSize, 3);
 
517
                                        __try
 
518
                                                {
 
519
                                                ZeroMemory(&hentry, sizeof(HEAPENTRY32));
 
520
                                        hentry.dwSize = sizeof(HEAPENTRY32);
 
521
                                        if (heap_first(&hentry,
 
522
                                                hlist.th32ProcessID,
 
523
                                                hlist.th32HeapID))
 
524
                                                {
 
525
                                                int entrycnt = 80;
 
526
                                                do
 
527
                                                        RAND_add(&hentry,
 
528
                                                                hentry.dwSize, 5);
 
529
                                                while (heap_next(&hentry)
 
530
                                                && (!good || (GetTickCount()-starttime)<MAXDELAY)
 
531
                                                        && --entrycnt > 0);
 
532
                                                }
 
533
                                                }
 
534
                                        __except (EXCEPTION_EXECUTE_HANDLER)
 
535
                                                {
 
536
                                                        /* ignore access violations when walking the heap list */
 
537
                                                        ex_cnt_limit--;
 
538
                                                }
 
539
                                        } while (heaplist_next(handle, &hlist) 
 
540
                                                && (!good || (GetTickCount()-starttime)<MAXDELAY)
 
541
                                                && ex_cnt_limit > 0);
 
542
                                }
 
543
 
 
544
#else
 
545
                        if (heaplist_first(handle, &hlist))
 
546
                                {
 
547
                                do
 
548
                                        {
 
549
                                        RAND_add(&hlist, hlist.dwSize, 3);
 
550
                                        hentry.dwSize = sizeof(HEAPENTRY32);
 
551
                                        if (heap_first(&hentry,
 
552
                                                hlist.th32ProcessID,
 
553
                                                hlist.th32HeapID))
 
554
                                                {
 
555
                                                int entrycnt = 80;
 
556
                                                do
 
557
                                                        RAND_add(&hentry,
 
558
                                                                hentry.dwSize, 5);
 
559
                                                while (heap_next(&hentry)
 
560
                                                        && --entrycnt > 0);
 
561
                                                }
 
562
                                        } while (heaplist_next(handle, &hlist) 
 
563
                                                && (!good || (GetTickCount()-starttime)<MAXDELAY));
 
564
                                }
 
565
#endif
 
566
 
 
567
                        /* process walking */
 
568
                        /* PROCESSENTRY32 contains 9 fields that will change
 
569
                         * with each entry.  Consider each field a source of
 
570
                         * 1 byte of entropy.
 
571
                         */
 
572
                        p.dwSize = sizeof(PROCESSENTRY32);
 
573
                
 
574
                        if (good) starttime = GetTickCount();
 
575
                        if (process_first(handle, &p))
 
576
                                do
 
577
                                        RAND_add(&p, p.dwSize, 9);
 
578
                                while (process_next(handle, &p) && (!good || (GetTickCount()-starttime)<MAXDELAY));
 
579
 
 
580
                        /* thread walking */
 
581
                        /* THREADENTRY32 contains 6 fields that will change
 
582
                         * with each entry.  Consider each field a source of
 
583
                         * 1 byte of entropy.
 
584
                         */
 
585
                        t.dwSize = sizeof(THREADENTRY32);
 
586
                        if (good) starttime = GetTickCount();
 
587
                        if (thread_first(handle, &t))
 
588
                                do
 
589
                                        RAND_add(&t, t.dwSize, 6);
 
590
                                while (thread_next(handle, &t) && (!good || (GetTickCount()-starttime)<MAXDELAY));
 
591
 
 
592
                        /* module walking */
 
593
                        /* MODULEENTRY32 contains 9 fields that will change
 
594
                         * with each entry.  Consider each field a source of
 
595
                         * 1 byte of entropy.
 
596
                         */
 
597
                        m.dwSize = sizeof(MODULEENTRY32);
 
598
                        if (good) starttime = GetTickCount();
 
599
                        if (module_first(handle, &m))
 
600
                                do
 
601
                                        RAND_add(&m, m.dwSize, 9);
 
602
                                while (module_next(handle, &m)
 
603
                                                && (!good || (GetTickCount()-starttime)<MAXDELAY));
 
604
                        if (close_snap)
 
605
                                close_snap(handle);
 
606
                        else
 
607
                                CloseHandle(handle);
 
608
 
 
609
                        }
 
610
 
 
611
                FreeLibrary(kernel);
 
612
                }
 
613
        }
 
614
#endif /* !OPENSSL_SYS_WINCE */
 
615
 
 
616
        /* timer data */
 
617
        readtimer();
 
618
        
 
619
        /* memory usage statistics */
 
620
        GlobalMemoryStatus(&m);
 
621
        RAND_add(&m, sizeof(m), 1);
 
622
 
 
623
        /* process ID */
 
624
        w = GetCurrentProcessId();
 
625
        RAND_add(&w, sizeof(w), 1);
 
626
 
 
627
#if 0
 
628
        printf("Exiting RAND_poll\n");
 
629
#endif
 
630
 
 
631
        return(1);
 
632
}
 
633
 
 
634
int RAND_event(UINT iMsg, WPARAM wParam, LPARAM lParam)
 
635
        {
 
636
        double add_entropy=0;
 
637
 
 
638
        switch (iMsg)
 
639
                {
 
640
        case WM_KEYDOWN:
 
641
                        {
 
642
                        static WPARAM key;
 
643
                        if (key != wParam)
 
644
                                add_entropy = 0.05;
 
645
                        key = wParam;
 
646
                        }
 
647
                        break;
 
648
        case WM_MOUSEMOVE:
 
649
                        {
 
650
                        static int lastx,lasty,lastdx,lastdy;
 
651
                        int x,y,dx,dy;
 
652
 
 
653
                        x=LOWORD(lParam);
 
654
                        y=HIWORD(lParam);
 
655
                        dx=lastx-x;
 
656
                        dy=lasty-y;
 
657
                        if (dx != 0 && dy != 0 && dx-lastdx != 0 && dy-lastdy != 0)
 
658
                                add_entropy=.2;
 
659
                        lastx=x, lasty=y;
 
660
                        lastdx=dx, lastdy=dy;
 
661
                        }
 
662
                break;
 
663
                }
 
664
 
 
665
        readtimer();
 
666
        RAND_add(&iMsg, sizeof(iMsg), add_entropy);
 
667
        RAND_add(&wParam, sizeof(wParam), 0);
 
668
        RAND_add(&lParam, sizeof(lParam), 0);
 
669
 
 
670
        return (RAND_status());
 
671
        }
 
672
 
 
673
 
 
674
void RAND_screen(void) /* function available for backward compatibility */
 
675
{
 
676
        RAND_poll();
 
677
        readscreen();
 
678
}
 
679
 
 
680
 
 
681
/* feed timing information to the PRNG */
 
682
static void readtimer(void)
 
683
{
 
684
        DWORD w;
 
685
        LARGE_INTEGER l;
 
686
        static int have_perfc = 1;
 
687
#if defined(_MSC_VER) && defined(_M_X86)
 
688
        static int have_tsc = 1;
 
689
        DWORD cyclecount;
 
690
 
 
691
        if (have_tsc) {
 
692
          __try {
 
693
            __asm {
 
694
              _emit 0x0f
 
695
              _emit 0x31
 
696
              mov cyclecount, eax
 
697
              }
 
698
            RAND_add(&cyclecount, sizeof(cyclecount), 1);
 
699
          } __except(EXCEPTION_EXECUTE_HANDLER) {
 
700
            have_tsc = 0;
 
701
          }
 
702
        }
 
703
#else
 
704
# define have_tsc 0
 
705
#endif
 
706
 
 
707
        if (have_perfc) {
 
708
          if (QueryPerformanceCounter(&l) == 0)
 
709
            have_perfc = 0;
 
710
          else
 
711
            RAND_add(&l, sizeof(l), 0);
 
712
        }
 
713
 
 
714
        if (!have_tsc && !have_perfc) {
 
715
          w = GetTickCount();
 
716
          RAND_add(&w, sizeof(w), 0);
 
717
        }
 
718
}
 
719
 
 
720
/* feed screen contents to PRNG */
 
721
/*****************************************************************************
 
722
 *
 
723
 * Created 960901 by Gertjan van Oosten, gertjan@West.NL, West Consulting B.V.
 
724
 *
 
725
 * Code adapted from
 
726
 * <URL:http://support.microsoft.com/default.aspx?scid=kb;[LN];97193>;
 
727
 * the original copyright message is:
 
728
 *
 
729
 *   (C) Copyright Microsoft Corp. 1993.  All rights reserved.
 
730
 *
 
731
 *   You have a royalty-free right to use, modify, reproduce and
 
732
 *   distribute the Sample Files (and/or any modified version) in
 
733
 *   any way you find useful, provided that you agree that
 
734
 *   Microsoft has no warranty obligations or liability for any
 
735
 *   Sample Application Files which are modified.
 
736
 */
 
737
 
 
738
static void readscreen(void)
 
739
{
 
740
#if !defined(OPENSSL_SYS_WINCE) && !defined(OPENSSL_SYS_WIN32_CYGWIN)
 
741
  HDC           hScrDC;         /* screen DC */
 
742
  HDC           hMemDC;         /* memory DC */
 
743
  HBITMAP       hBitmap;        /* handle for our bitmap */
 
744
  HBITMAP       hOldBitmap;     /* handle for previous bitmap */
 
745
  BITMAP        bm;             /* bitmap properties */
 
746
  unsigned int  size;           /* size of bitmap */
 
747
  char          *bmbits;        /* contents of bitmap */
 
748
  int           w;              /* screen width */
 
749
  int           h;              /* screen height */
 
750
  int           y;              /* y-coordinate of screen lines to grab */
 
751
  int           n = 16;         /* number of screen lines to grab at a time */
 
752
 
 
753
  if (GetVersion() < 0x80000000 && OPENSSL_isservice()>0)
 
754
    return;
 
755
 
 
756
  /* Create a screen DC and a memory DC compatible to screen DC */
 
757
  hScrDC = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
 
758
  hMemDC = CreateCompatibleDC(hScrDC);
 
759
 
 
760
  /* Get screen resolution */
 
761
  w = GetDeviceCaps(hScrDC, HORZRES);
 
762
  h = GetDeviceCaps(hScrDC, VERTRES);
 
763
 
 
764
  /* Create a bitmap compatible with the screen DC */
 
765
  hBitmap = CreateCompatibleBitmap(hScrDC, w, n);
 
766
 
 
767
  /* Select new bitmap into memory DC */
 
768
  hOldBitmap = SelectObject(hMemDC, hBitmap);
 
769
 
 
770
  /* Get bitmap properties */
 
771
  GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bm);
 
772
  size = (unsigned int)bm.bmWidthBytes * bm.bmHeight * bm.bmPlanes;
 
773
 
 
774
  bmbits = OPENSSL_malloc(size);
 
775
  if (bmbits) {
 
776
    /* Now go through the whole screen, repeatedly grabbing n lines */
 
777
    for (y = 0; y < h-n; y += n)
 
778
        {
 
779
        unsigned char md[MD_DIGEST_LENGTH];
 
780
 
 
781
        /* Bitblt screen DC to memory DC */
 
782
        BitBlt(hMemDC, 0, 0, w, n, hScrDC, 0, y, SRCCOPY);
 
783
 
 
784
        /* Copy bitmap bits from memory DC to bmbits */
 
785
        GetBitmapBits(hBitmap, size, bmbits);
 
786
 
 
787
        /* Get the hash of the bitmap */
 
788
        MD(bmbits,size,md);
 
789
 
 
790
        /* Seed the random generator with the hash value */
 
791
        RAND_add(md, MD_DIGEST_LENGTH, 0);
 
792
        }
 
793
 
 
794
    OPENSSL_free(bmbits);
 
795
  }
 
796
 
 
797
  /* Select old bitmap back into memory DC */
 
798
  hBitmap = SelectObject(hMemDC, hOldBitmap);
 
799
 
 
800
  /* Clean up */
 
801
  DeleteObject(hBitmap);
 
802
  DeleteDC(hMemDC);
 
803
  DeleteDC(hScrDC);
 
804
#endif /* !OPENSSL_SYS_WINCE */
 
805
}
 
806
 
 
807
#endif