Line data Source code
1 :
2 : /* Copyright (c) 2010-2012, Stefan Eilemann <eile@equalizergraphics.com>
3 : * 2012, 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 <wtypes.h>
29 : # include <wincrypt.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 :
42 : namespace lunchbox
43 : {
44 : namespace
45 : {
46 : #ifdef __linux__
47 : static int _fd = -1;
48 : #elif defined (_WIN32)
49 : static HCRYPTPROV _provider = 0;
50 : #endif
51 : }
52 :
53 100425 : RNG::RNG()
54 100425 : : _impl( 0 )
55 : {
56 100161 : _init();
57 100187 : }
58 :
59 101035 : RNG::~RNG()
60 101035 : {}
61 :
62 100175 : bool RNG::_init()
63 : {
64 : #ifdef __APPLE__
65 : srandomdev();
66 : #elif defined (__linux__)
67 : static int fd = -1; // prevent static initializer fiasco
68 100175 : if( fd >= 0 )
69 100166 : return true;
70 :
71 9 : fd = ::open( "/dev/urandom", O_RDONLY );
72 9 : if( fd >= 0 )
73 9 : ::atexit( RNG::_exit );
74 : else
75 : {
76 0 : LBERROR << "Failed to open /dev/urandom: " << sysError << std::endl;
77 0 : return false;
78 : }
79 9 : _fd = fd;
80 :
81 : #elif defined (_WIN32)
82 :
83 : static HCRYPTPROV provider = 0; // prevent static initializer fiasco
84 : if( provider )
85 : return true;
86 :
87 : if( CryptAcquireContext( &provider, 0, 0, PROV_RSA_FULL,
88 : CRYPT_VERIFYCONTEXT ) || !provider )
89 : {
90 : ::atexit( RNG::_exit );
91 : }
92 : else
93 : {
94 : LBERROR << "Failed to acquire crypto context: " << sysError <<std::endl;
95 : return false;
96 : }
97 :
98 : _provider = provider;
99 : #endif
100 9 : return true;
101 : }
102 :
103 9 : void RNG::_exit()
104 : {
105 : #ifdef __linux__
106 9 : if( _fd >= 0 )
107 : {
108 9 : ::close( _fd );
109 9 : _fd = -1;
110 : }
111 : #elif defined (_WIN32)
112 : if( _provider && !CryptReleaseContext( _provider, 0 ))
113 : LBERROR << "Failed to release crypto context: " << sysError
114 : << std::endl;
115 : _provider = 0;
116 : #endif
117 9 : }
118 :
119 0 : void RNG::reseed()
120 : {
121 : #ifdef __APPLE__
122 : srandomdev();
123 : #endif
124 0 : }
125 :
126 11197300 : bool RNG::_get( void* data, const size_t size )
127 : {
128 : #ifdef __linux__
129 11197300 : LBASSERTINFO( _fd >= 0, "init() not called?" );
130 11197500 : int read = ::read( _fd, data, size );
131 11198771 : LBASSERTINFO( read == ssize_t( size ),
132 : read << " != " << size << ": " << sysError );
133 11200423 : if( read != ssize_t( size ))
134 : {
135 0 : LBERROR << "random number generator not working" << std::endl;
136 0 : return false;
137 : }
138 :
139 : #elif defined (_WIN32)
140 : LBASSERTINFO( _provider, "init() not called?" );
141 : if( !CryptGenRandom( _provider, (DWORD)size, (BYTE*)data ))
142 : {
143 : LBERROR << "random number generator not working" << std::endl;
144 : return false;
145 : }
146 : #else // __APPLE__
147 : uint8_t* ptr = reinterpret_cast< uint8_t* >( data );
148 : for( size_t i=0; i < size; ++i )
149 : ptr[i] = ( random() & 0xff );
150 : #endif
151 11200423 : return true;
152 : }
153 :
154 90 : }
|