/src/libtorrent/src/random.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | |
3 | | Copyright (c) 2011-2012, 2014-2015, 2017-2021, Arvid Norberg |
4 | | Copyright (c) 2016, 2019, Alden Torres |
5 | | Copyright (c) 2017, 2019, Andrei Kurushin |
6 | | All rights reserved. |
7 | | |
8 | | Redistribution and use in source and binary forms, with or without |
9 | | modification, are permitted provided that the following conditions |
10 | | are met: |
11 | | |
12 | | * Redistributions of source code must retain the above copyright |
13 | | notice, this list of conditions and the following disclaimer. |
14 | | * Redistributions in binary form must reproduce the above copyright |
15 | | notice, this list of conditions and the following disclaimer in |
16 | | the documentation and/or other materials provided with the distribution. |
17 | | * Neither the name of the author nor the names of its |
18 | | contributors may be used to endorse or promote products derived |
19 | | from this software without specific prior written permission. |
20 | | |
21 | | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
22 | | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
23 | | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
24 | | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
25 | | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
26 | | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
27 | | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
28 | | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
29 | | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
30 | | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
31 | | POSSIBILITY OF SUCH DAMAGE. |
32 | | |
33 | | */ |
34 | | |
35 | | #include "libtorrent/config.hpp" |
36 | | #include "libtorrent/random.hpp" |
37 | | #include "libtorrent/error_code.hpp" |
38 | | #include "libtorrent/aux_/throw.hpp" |
39 | | |
40 | | #if defined BOOST_NO_CXX11_THREAD_LOCAL |
41 | | #include <mutex> |
42 | | #endif |
43 | | |
44 | | #if TORRENT_BROKEN_RANDOM_DEVICE |
45 | | #include "libtorrent/time.hpp" |
46 | | #include <atomic> |
47 | | #endif |
48 | | |
49 | | #if TORRENT_USE_CNG |
50 | | #include "libtorrent/aux_/win_cng.hpp" |
51 | | |
52 | | #elif TORRENT_USE_CRYPTOAPI |
53 | | #include "libtorrent/aux_/win_crypto_provider.hpp" |
54 | | |
55 | | #elif defined TORRENT_USE_LIBCRYPTO && !defined TORRENT_USE_WOLFSSL |
56 | | |
57 | | #include "libtorrent/aux_/disable_warnings_push.hpp" |
58 | | extern "C" { |
59 | | #include <openssl/rand.h> |
60 | | #include <openssl/err.h> |
61 | | } |
62 | | #include "libtorrent/aux_/disable_warnings_pop.hpp" |
63 | | |
64 | | #elif TORRENT_USE_GETRANDOM |
65 | | |
66 | | #include <sys/random.h> |
67 | | // this is the fall-back in case getrandom() fails |
68 | | #include "libtorrent/aux_/dev_random.hpp" |
69 | | |
70 | | #elif TORRENT_USE_DEV_RANDOM |
71 | | #include "libtorrent/aux_/dev_random.hpp" |
72 | | #endif |
73 | | |
74 | | #ifdef BOOST_NO_CXX11_THREAD_LOCAL |
75 | | namespace { |
76 | | // if the random number generator can't be thread local, just protect it with |
77 | | // a mutex. Not ideal, but hopefully not too many people are affected by old |
78 | | // systems |
79 | | std::mutex rng_mutex; |
80 | | } |
81 | | #endif |
82 | | |
83 | | namespace libtorrent { |
84 | | namespace aux { |
85 | | |
86 | | std::mt19937& random_engine() |
87 | 0 | { |
88 | | #ifdef TORRENT_BUILD_SIMULATOR |
89 | | // make sure random numbers are deterministic. Seed with a fixed number |
90 | | static std::mt19937 rng(0x82daf973); |
91 | | #else |
92 | |
|
93 | | #if TORRENT_BROKEN_RANDOM_DEVICE |
94 | | struct { |
95 | | std::uint32_t operator()() const |
96 | | { |
97 | | std::uint32_t ret; |
98 | | crypto_random_bytes({reinterpret_cast<char*>(&ret), sizeof(ret)}); |
99 | | return ret; |
100 | | } |
101 | | } dev; |
102 | | #else |
103 | 0 | static std::random_device dev; |
104 | 0 | #endif |
105 | | #ifdef BOOST_NO_CXX11_THREAD_LOCAL |
106 | | static std::seed_seq seed({dev(), dev(), dev(), dev()}); |
107 | | static std::mt19937 rng(seed); |
108 | | #else |
109 | 0 | thread_local static std::seed_seq seed({dev(), dev(), dev(), dev()}); |
110 | 0 | thread_local static std::mt19937 rng(seed); |
111 | 0 | #endif |
112 | 0 | #endif |
113 | 0 | return rng; |
114 | 0 | } |
115 | | |
116 | | void random_bytes(span<char> buffer) |
117 | 0 | { |
118 | | #ifdef TORRENT_BUILD_SIMULATOR |
119 | | // simulator |
120 | | for (auto& b : buffer) b = char(random(0xff)); |
121 | | #else |
122 | 0 | std::generate(buffer.begin(), buffer.end(), [] { return char(random(0xff)); }); |
123 | 0 | #endif |
124 | 0 | } |
125 | | |
126 | | void crypto_random_bytes(span<char> buffer) |
127 | 0 | { |
128 | | #ifdef TORRENT_BUILD_SIMULATOR |
129 | | // In the simulator we want deterministic random numbers |
130 | | std::generate(buffer.begin(), buffer.end(), [] { return char(random(0xff)); }); |
131 | | #elif TORRENT_USE_CNG |
132 | | aux::cng_gen_random(buffer); |
133 | | #elif TORRENT_USE_CRYPTOAPI |
134 | | // windows |
135 | | aux::crypt_gen_random(buffer); |
136 | | #elif defined TORRENT_USE_LIBCRYPTO && !defined TORRENT_USE_WOLFSSL |
137 | | // wolfSSL uses wc_RNG_GenerateBlock as the internal function for the |
138 | | // openssl compatibility layer. This function API does not support |
139 | | // an arbitrary buffer size (openssl does), it is limited by the |
140 | | // constant RNG_MAX_BLOCK_LEN. |
141 | | // TODO: improve calling RAND_bytes multiple times, using fallback for now |
142 | | |
143 | | // openssl |
144 | 0 | int r = RAND_bytes(reinterpret_cast<unsigned char*>(buffer.data()) |
145 | 0 | , int(buffer.size())); |
146 | 0 | if (r != 1) aux::throw_ex<system_error>(errors::no_entropy); |
147 | | #elif TORRENT_USE_GETRANDOM |
148 | | ssize_t const r = ::getrandom(buffer.data(), static_cast<std::size_t>(buffer.size()), 0); |
149 | | if (r == ssize_t(buffer.size())) return; |
150 | | if (r == -1 && errno != ENOSYS) aux::throw_ex<system_error>(error_code(errno, generic_category())); |
151 | | static dev_random dev; |
152 | | dev.read(buffer); |
153 | | #elif TORRENT_USE_DEV_RANDOM |
154 | | static dev_random dev; |
155 | | dev.read(buffer); |
156 | | #else |
157 | | |
158 | | #if TORRENT_BROKEN_RANDOM_DEVICE |
159 | | // even pseudo random numbers rely on being able to seed the random |
160 | | // generator |
161 | | #error "no entropy source available" |
162 | | #else |
163 | | #ifdef TORRENT_I_WANT_INSECURE_RANDOM_NUMBERS |
164 | | std::generate(buffer.begin(), buffer.end(), [] { return char(random(0xff)); }); |
165 | | #else |
166 | | #error "no secure entropy source available. If you really want insecure random numbers, define TORRENT_I_WANT_INSECURE_RANDOM_NUMBERS" |
167 | | #endif |
168 | | #endif |
169 | | |
170 | | #endif |
171 | 0 | } |
172 | | } |
173 | | |
174 | | std::uint32_t random(std::uint32_t const max) |
175 | 0 | { |
176 | 0 | if (max == 0) return 0; |
177 | | #ifdef BOOST_NO_CXX11_THREAD_LOCAL |
178 | | std::lock_guard<std::mutex> l(rng_mutex); |
179 | | #endif |
180 | | #ifdef TORRENT_BUILD_SIMULATOR |
181 | | std::uint32_t mask = max | (max >> 16); |
182 | | mask |= mask >> 8; |
183 | | mask |= mask >> 4; |
184 | | mask |= mask >> 2; |
185 | | mask |= mask >> 1; |
186 | | auto& rng = aux::random_engine(); |
187 | | std::uint32_t ret; |
188 | | do |
189 | | { |
190 | | ret = rng() & mask; |
191 | | } while (ret > max); |
192 | | #else |
193 | 0 | auto const ret = std::uniform_int_distribution<std::uint32_t>(0, max)(aux::random_engine()); |
194 | 0 | #endif |
195 | 0 | return ret; |
196 | 0 | } |
197 | | |
198 | | } |