Line data Source code
1 :
2 : /* Copyright (c) 2010-2015, Stefan Eilemann <eile@equalizergraphics.com>
3 : * Daniel Nachbaur <danielnachbaur@gmail.com>
4 : *
5 : * This library is free software; you can redistribute it and/or modify it under
6 : * the terms of the GNU Lesser General Public License version 2.1 as published
7 : * by the Free Software Foundation.
8 : *
9 : * This library is distributed in the hope that it will be useful, but WITHOUT
10 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12 : * details.
13 : *
14 : * You should have received a copy of the GNU Lesser General Public License
15 : * along with this library; if not, write to the Free Software Foundation, Inc.,
16 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 : */
18 :
19 : #include "rng.h"
20 :
21 : #pragma warning(push)
22 : #pragma warning(disable : 4985) // inconsistent decl of ceil
23 :
24 : #ifdef _WIN32
25 : #ifndef NOMINMAX
26 : #define NOMINMAX
27 : #endif
28 : #include <wincrypt.h>
29 : #include <wtypes.h>
30 : #pragma comment(lib, "advapi32.lib")
31 : #else
32 : #include <unistd.h>
33 : #endif
34 :
35 : #include <cstdlib>
36 : #include <fcntl.h>
37 : #include <limits>
38 : #include <stdio.h>
39 : #pragma warning(pop)
40 :
41 : namespace lunchbox
42 : {
43 : namespace
44 : {
45 : #ifdef __linux__
46 :
47 : static int _fd = -1;
48 :
49 2 : void _exit()
50 : {
51 2 : if (_fd >= 0)
52 : {
53 2 : ::close(_fd);
54 2 : _fd = -1;
55 : }
56 2 : }
57 :
58 2 : int _init()
59 : {
60 2 : const int fd = ::open("/dev/urandom", O_RDONLY);
61 2 : if (fd >= 0)
62 2 : ::atexit(_exit);
63 : else
64 : {
65 0 : LBERROR << "Failed to open /dev/urandom: " << sysError << std::endl;
66 0 : return -1;
67 : }
68 2 : _fd = fd;
69 2 : return fd;
70 : }
71 :
72 : #elif defined _MSC_VER
73 : static HCRYPTPROV _provider = 0;
74 :
75 : void _exit()
76 : {
77 : if (_provider && !CryptReleaseContext(_provider, 0))
78 : LBERROR << "Failed to release crypto context: " << sysError
79 : << std::endl;
80 : _provider = 0;
81 : }
82 :
83 : HCRYPTPROV _init()
84 : {
85 : HCRYPTPROV provider = 0;
86 : if (CryptAcquireContext(&provider, 0, 0, PROV_RSA_FULL,
87 : CRYPT_VERIFYCONTEXT) ||
88 : !provider)
89 : {
90 : ::atexit(_exit);
91 : }
92 : else
93 : {
94 : LBERROR << "Failed to acquire crypto context: " << sysError
95 : << std::endl;
96 : return 0;
97 : }
98 :
99 : _provider = provider;
100 : return provider;
101 : }
102 : #endif
103 : }
104 :
105 1030 : RNG::RNG()
106 : {
107 : #ifdef __APPLE__
108 : srandomdev();
109 : #endif
110 1030 : }
111 :
112 1030 : RNG::~RNG()
113 : {
114 1030 : }
115 :
116 525080 : bool RNG::_get(void* data, const size_t size)
117 : {
118 : #ifdef __linux__
119 525080 : static int fd = _init();
120 525080 : int read = ::read(fd, data, size);
121 525080 : LBASSERTINFO(read == ssize_t(size), read << " != " << size << ": "
122 : << sysError);
123 525080 : if (read != ssize_t(size))
124 : {
125 0 : LBERROR << "random number generator not working" << std::endl;
126 0 : return false;
127 : }
128 :
129 : #elif defined _MSC_VER
130 : static HCRYPTPROV provider = _init();
131 : if (!CryptGenRandom(provider, (DWORD)size, (BYTE*)data))
132 : {
133 : LBERROR << "random number generator not working" << std::endl;
134 : return false;
135 : }
136 : #else // __APPLE__
137 : uint8_t* ptr = reinterpret_cast<uint8_t*>(data);
138 : for (size_t i = 0; i < size; ++i)
139 : ptr[i] = (random() & 0xff);
140 : #endif
141 525080 : return true;
142 : }
143 75 : }
|