21cc9b6bcb982d088ba579af7e3558f6907f9576
[openssl.git] / crypto / rand / rand_win.c
1 /*
2  * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 #include "internal/cryptlib.h"
11 #include <openssl/rand.h>
12 #include "rand_lcl.h"
13
14 #if defined(OPENSSL_SYS_WINDOWS) || defined(OPENSSL_SYS_WIN32)
15 # include <windows.h>
16 /* On Windows 7 or higher use BCrypt instead of the legacy CryptoAPI */
17 # if defined(_MSC_VER) && defined(_WIN32_WINNT) && _WIN32_WINNT>=0x0601
18 #  define USE_BCRYPT 1
19 # endif
20
21 # ifdef USE_BCRYPT
22 #  include <bcrypt.h>
23 #  pragma comment(lib, "bcrypt.lib")
24 # else
25 #  include <wincrypt.h>
26 /*
27  * Intel hardware RNG CSP -- available from
28  * http://developer.intel.com/design/security/rng/redist_license.htm
29  */
30 #  define PROV_INTEL_SEC 22
31 #  define INTEL_DEF_PROV L"Intel Hardware Cryptographic Service Provider"
32 # endif
33
34 static void readtimer(void);
35
36 int RAND_poll(void)
37 {
38     MEMORYSTATUS mst;
39 # ifndef USE_BCRYPT
40     HCRYPTPROV hProvider = 0;
41 # endif
42     DWORD w;
43     BYTE buf[64];
44
45 # ifdef USE_BCRYPT
46     if (BCryptGenRandom(NULL, buf, (ULONG)sizeof(buf), BCRYPT_USE_SYSTEM_PREFERRED_RNG) == 0) {
47         RAND_add(buf, sizeof(buf), sizeof(buf));
48     }
49 # else
50     /* poll the CryptoAPI PRNG */
51     /* The CryptoAPI returns sizeof(buf) bytes of randomness */
52     if (CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
53         if (CryptGenRandom(hProvider, sizeof(buf), buf) != 0) {
54             RAND_add(buf, sizeof(buf), sizeof(buf));
55         }
56         CryptReleaseContext(hProvider, 0);
57     }
58
59     /* poll the Pentium PRG with CryptoAPI */
60     if (CryptAcquireContextW(&hProvider, NULL, INTEL_DEF_PROV, PROV_INTEL_SEC, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
61         if (CryptGenRandom(hProvider, sizeof(buf), buf) != 0) {
62             RAND_add(buf, sizeof(buf), sizeof(buf));
63         }
64         CryptReleaseContext(hProvider, 0);
65     }
66 # endif
67
68     /* timer data */
69     readtimer();
70
71     /* memory usage statistics */
72     GlobalMemoryStatus(&mst);
73     RAND_add(&mst, sizeof(mst), 1);
74
75     /* process ID */
76     w = GetCurrentProcessId();
77     RAND_add(&w, sizeof(w), 1);
78
79     return (1);
80 }
81
82 #if OPENSSL_API_COMPAT < 0x00101000L
83 int RAND_event(UINT iMsg, WPARAM wParam, LPARAM lParam)
84 {
85     RAND_poll();
86     return RAND_status();
87 }
88
89 void RAND_screen(void)
90 {
91     RAND_poll();
92 }
93 #endif
94
95 /* feed timing information to the PRNG */
96 static void readtimer(void)
97 {
98     DWORD w;
99     LARGE_INTEGER l;
100     static int have_perfc = 1;
101 # if defined(_MSC_VER) && defined(_M_X86)
102     static int have_tsc = 1;
103     DWORD cyclecount;
104
105     if (have_tsc) {
106         __try {
107             __asm {
108             _emit 0x0f _emit 0x31 mov cyclecount, eax}
109             RAND_add(&cyclecount, sizeof(cyclecount), 1);
110         }
111         __except(EXCEPTION_EXECUTE_HANDLER) {
112             have_tsc = 0;
113         }
114     }
115 # else
116 #  define have_tsc 0
117 # endif
118
119     if (have_perfc) {
120         if (QueryPerformanceCounter(&l) == 0)
121             have_perfc = 0;
122         else
123             RAND_add(&l, sizeof(l), 0);
124     }
125
126     if (!have_tsc && !have_perfc) {
127         w = GetTickCount();
128         RAND_add(&w, sizeof(w), 0);
129     }
130 }
131
132 #endif