1be0ed3c9a58b3d1b04f2b41f885416aedefe49a
[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 RAND_WINDOWS_USE_BCRYPT
19 # endif
20
21 # ifdef RAND_WINDOWS_USE_BCRYPT
22 #  include <bcrypt.h>
23 #  pragma comment(lib, "bcrypt.lib")
24 #  ifndef STATUS_SUCCESS
25 #   define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
26 #  endif
27 # else
28 #  include <wincrypt.h>
29 /*
30  * Intel hardware RNG CSP -- available from
31  * http://developer.intel.com/design/security/rng/redist_license.htm
32  */
33 #  define PROV_INTEL_SEC 22
34 #  define INTEL_DEF_PROV L"Intel Hardware Cryptographic Service Provider"
35 # endif
36
37 static void readtimer(void);
38
39 int RAND_poll(void)
40 {
41     MEMORYSTATUS mst;
42 # ifndef RAND_WINDOWS_USE_BCRYPT
43     HCRYPTPROV hProvider;
44 # endif
45     DWORD w;
46     BYTE buf[64];
47
48 # ifdef RAND_WINDOWS_USE_BCRYPT
49     if (BCryptGenRandom(NULL, buf, (ULONG)sizeof(buf), BCRYPT_USE_SYSTEM_PREFERRED_RNG) == STATUS_SUCCESS) {
50         RAND_add(buf, sizeof(buf), sizeof(buf));
51     }
52 # else
53     /* poll the CryptoAPI PRNG */
54     /* The CryptoAPI returns sizeof(buf) bytes of randomness */
55     if (CryptAcquireContextW(&hProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
56         if (CryptGenRandom(hProvider, (DWORD)sizeof(buf), buf) != 0) {
57             RAND_add(buf, sizeof(buf), sizeof(buf));
58         }
59         CryptReleaseContext(hProvider, 0);
60     }
61
62     /* poll the Pentium PRG with CryptoAPI */
63     if (CryptAcquireContextW(&hProvider, NULL, INTEL_DEF_PROV, PROV_INTEL_SEC, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
64         if (CryptGenRandom(hProvider, (DWORD)sizeof(buf), buf) != 0) {
65             RAND_add(buf, sizeof(buf), sizeof(buf));
66         }
67         CryptReleaseContext(hProvider, 0);
68     }
69 # endif
70
71     /* timer data */
72     readtimer();
73
74     /* memory usage statistics */
75     GlobalMemoryStatus(&mst);
76     RAND_add(&mst, sizeof(mst), 1);
77
78     /* process ID */
79     w = GetCurrentProcessId();
80     RAND_add(&w, sizeof(w), 1);
81
82     return (1);
83 }
84
85 #if OPENSSL_API_COMPAT < 0x10100000L
86 int RAND_event(UINT iMsg, WPARAM wParam, LPARAM lParam)
87 {
88     RAND_poll();
89     return RAND_status();
90 }
91
92 void RAND_screen(void)
93 {
94     RAND_poll();
95 }
96 #endif
97
98 /* feed timing information to the PRNG */
99 static void readtimer(void)
100 {
101     DWORD w;
102     LARGE_INTEGER l;
103     static int have_perfc = 1;
104 # if defined(_MSC_VER) && defined(_M_X86)
105     static int have_tsc = 1;
106     DWORD cyclecount;
107
108     if (have_tsc) {
109         __try {
110             __asm {
111             _emit 0x0f _emit 0x31 mov cyclecount, eax}
112             RAND_add(&cyclecount, sizeof(cyclecount), 1);
113         }
114         __except(EXCEPTION_EXECUTE_HANDLER) {
115             have_tsc = 0;
116         }
117     }
118 # else
119 #  define have_tsc 0
120 # endif
121
122     if (have_perfc) {
123         if (QueryPerformanceCounter(&l) == 0)
124             have_perfc = 0;
125         else
126             RAND_add(&l, sizeof(l), 0);
127     }
128
129     if (!have_tsc && !have_perfc) {
130         w = GetTickCount();
131         RAND_add(&w, sizeof(w), 0);
132     }
133 }
134
135 #endif