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