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 <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 :
48 : static int _fd = -1;
49 :
50 3 : void _exit()
51 : {
52 3 : if( _fd >= 0 )
53 : {
54 3 : ::close( _fd );
55 3 : _fd = -1;
56 : }
57 3 : }
58 :
59 3 : int _init()
60 : {
61 3 : const int fd = ::open( "/dev/urandom", O_RDONLY );
62 3 : if( fd >= 0 )
63 3 : ::atexit( _exit );
64 : else
65 : {
66 0 : LBERROR << "Failed to open /dev/urandom: " << sysError << std::endl;
67 0 : return -1;
68 : }
69 3 : _fd = fd;
70 3 : return fd;
71 : }
72 :
73 : #elif defined _MSC_VER
74 : static HCRYPTPROV _provider = 0;
75 :
76 : void _exit()
77 : {
78 : if( _provider && !CryptReleaseContext( _provider, 0 ))
79 : LBERROR << "Failed to release crypto context: " << sysError
80 : << std::endl;
81 : _provider = 0;
82 : }
83 :
84 : HCRYPTPROV _init()
85 : {
86 : HCRYPTPROV provider = 0;
87 : if( CryptAcquireContext( &provider, 0, 0, PROV_RSA_FULL,
88 : CRYPT_VERIFYCONTEXT ) || !provider )
89 : {
90 : ::atexit( _exit );
91 : }
92 : else
93 : {
94 : LBERROR << "Failed to acquire crypto context: " << sysError <<std::endl;
95 : return 0;
96 : }
97 :
98 : _provider = provider;
99 : return provider;
100 : }
101 : #endif
102 : }
103 :
104 1031 : RNG::RNG()
105 : {
106 : #ifdef __APPLE__
107 : srandomdev();
108 : #endif
109 1031 : }
110 :
111 1031 : RNG::~RNG()
112 1031 : {}
113 :
114 510401 : bool RNG::_get( void* data, const size_t size )
115 : {
116 : #ifdef __linux__
117 510401 : static int fd = _init();
118 510401 : int read = ::read( fd, data, size );
119 510401 : LBASSERTINFO( read == ssize_t( size ),
120 : read << " != " << size << ": " << sysError );
121 510401 : if( read != ssize_t( size ))
122 : {
123 0 : LBERROR << "random number generator not working" << std::endl;
124 0 : return false;
125 : }
126 :
127 : #elif defined _MSC_VER
128 : static HCRYPTPROV provider = _init();
129 : if( !CryptGenRandom( provider, (DWORD)size, (BYTE*)data ))
130 : {
131 : LBERROR << "random number generator not working" << std::endl;
132 : return false;
133 : }
134 : #else // __APPLE__
135 : uint8_t* ptr = reinterpret_cast< uint8_t* >( data );
136 : for( size_t i=0; i < size; ++i )
137 : ptr[i] = ( random() & 0xff );
138 : #endif
139 510401 : return true;
140 : }
141 :
142 72 : }
|