blob: 691a8131f840c4593904af3821460fbcd4363c10 [file] [log] [blame]
henrike@webrtc.org0e118e72013-07-10 00:45:36 +00001/*
2 * libjingle
3 * Copyright 2004--2005, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright notice,
11 * this list of conditions and the following disclaimer in the documentation
12 * and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#include "talk/base/helpers.h"
29
30#include <limits>
31
wu@webrtc.org2a81a382014-01-03 22:08:47 +000032#if defined(FEATURE_ENABLE_SSL)
henrike@webrtc.org0e118e72013-07-10 00:45:36 +000033#include "talk/base/sslconfig.h"
34#if defined(SSL_USE_OPENSSL)
35#include <openssl/rand.h>
36#elif defined(SSL_USE_NSS_RNG)
37#include "pk11func.h"
38#else
39#ifdef WIN32
40#define WIN32_LEAN_AND_MEAN
41#include <windows.h>
42#include <ntsecapi.h>
43#endif // WIN32
wu@webrtc.org2a81a382014-01-03 22:08:47 +000044#endif // else
45#endif // FEATURE_ENABLED_SSL
henrike@webrtc.org0e118e72013-07-10 00:45:36 +000046
47#include "talk/base/base64.h"
48#include "talk/base/basictypes.h"
49#include "talk/base/logging.h"
50#include "talk/base/scoped_ptr.h"
51#include "talk/base/timeutils.h"
52
53// Protect against max macro inclusion.
54#undef max
55
56namespace talk_base {
57
58// Base class for RNG implementations.
59class RandomGenerator {
60 public:
61 virtual ~RandomGenerator() {}
62 virtual bool Init(const void* seed, size_t len) = 0;
63 virtual bool Generate(void* buf, size_t len) = 0;
64};
65
66#if defined(SSL_USE_OPENSSL)
67// The OpenSSL RNG. Need to make sure it doesn't run out of entropy.
68class SecureRandomGenerator : public RandomGenerator {
69 public:
70 SecureRandomGenerator() : inited_(false) {
71 }
72 ~SecureRandomGenerator() {
73 }
74 virtual bool Init(const void* seed, size_t len) {
75 // By default, seed from the system state.
76 if (!inited_) {
77 if (RAND_poll() <= 0) {
78 return false;
79 }
80 inited_ = true;
81 }
82 // Allow app data to be mixed in, if provided.
83 if (seed) {
84 RAND_seed(seed, len);
85 }
86 return true;
87 }
88 virtual bool Generate(void* buf, size_t len) {
89 if (!inited_ && !Init(NULL, 0)) {
90 return false;
91 }
92 return (RAND_bytes(reinterpret_cast<unsigned char*>(buf), len) > 0);
93 }
94
95 private:
96 bool inited_;
97};
98
99#elif defined(SSL_USE_NSS_RNG)
100// The NSS RNG.
101class SecureRandomGenerator : public RandomGenerator {
102 public:
103 SecureRandomGenerator() {}
104 ~SecureRandomGenerator() {}
105 virtual bool Init(const void* seed, size_t len) {
106 return true;
107 }
108 virtual bool Generate(void* buf, size_t len) {
109 return (PK11_GenerateRandom(reinterpret_cast<unsigned char*>(buf),
110 static_cast<int>(len)) == SECSuccess);
111 }
112};
113
114#else
115#ifdef WIN32
116class SecureRandomGenerator : public RandomGenerator {
117 public:
118 SecureRandomGenerator() : advapi32_(NULL), rtl_gen_random_(NULL) {}
119 ~SecureRandomGenerator() {
120 FreeLibrary(advapi32_);
121 }
122
123 virtual bool Init(const void* seed, size_t seed_len) {
124 // We don't do any additional seeding on Win32, we just use the CryptoAPI
125 // RNG (which is exposed as a hidden function off of ADVAPI32 so that we
126 // don't need to drag in all of CryptoAPI)
127 if (rtl_gen_random_) {
128 return true;
129 }
130
131 advapi32_ = LoadLibrary(L"advapi32.dll");
132 if (!advapi32_) {
133 return false;
134 }
135
136 rtl_gen_random_ = reinterpret_cast<RtlGenRandomProc>(
137 GetProcAddress(advapi32_, "SystemFunction036"));
138 if (!rtl_gen_random_) {
139 FreeLibrary(advapi32_);
140 return false;
141 }
142
143 return true;
144 }
145 virtual bool Generate(void* buf, size_t len) {
146 if (!rtl_gen_random_ && !Init(NULL, 0)) {
147 return false;
148 }
149 return (rtl_gen_random_(buf, static_cast<int>(len)) != FALSE);
150 }
151
152 private:
153 typedef BOOL (WINAPI *RtlGenRandomProc)(PVOID, ULONG);
154 HINSTANCE advapi32_;
155 RtlGenRandomProc rtl_gen_random_;
156};
157
wu@webrtc.org2a81a382014-01-03 22:08:47 +0000158#elif !defined(FEATURE_ENABLE_SSL)
159
160// No SSL implementation -- use rand()
161class SecureRandomGenerator : public RandomGenerator {
162 public:
163 virtual bool Init(const void* seed, size_t len) {
164 if (len >= 4) {
165 srand(*reinterpret_cast<const int*>(seed));
166 } else {
167 srand(*reinterpret_cast<const char*>(seed));
168 }
169 return true;
170 }
171 virtual bool Generate(void* buf, size_t len) {
172 char* bytes = reinterpret_cast<char*>(buf);
173 for (size_t i = 0; i < len; ++i) {
174 bytes[i] = static_cast<char>(rand());
175 }
176 return true;
177 }
178};
179
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000180#else
181
182#error No SSL implementation has been selected!
183
184#endif // WIN32
185#endif
186
187// A test random generator, for predictable output.
188class TestRandomGenerator : public RandomGenerator {
189 public:
190 TestRandomGenerator() : seed_(7) {
191 }
192 ~TestRandomGenerator() {
193 }
194 virtual bool Init(const void* seed, size_t len) {
195 return true;
196 }
197 virtual bool Generate(void* buf, size_t len) {
198 for (size_t i = 0; i < len; ++i) {
199 static_cast<uint8*>(buf)[i] = static_cast<uint8>(GetRandom());
200 }
201 return true;
202 }
203
204 private:
205 int GetRandom() {
206 return ((seed_ = seed_ * 214013L + 2531011L) >> 16) & 0x7fff;
207 }
208 int seed_;
209};
210
211// TODO: Use Base64::Base64Table instead.
212static const char BASE64[64] = {
213 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
214 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
215 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
216 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
217 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
218};
219
220namespace {
221
222// This round about way of creating a global RNG is to safe-guard against
223// indeterminant static initialization order.
224scoped_ptr<RandomGenerator>& GetGlobalRng() {
225 LIBJINGLE_DEFINE_STATIC_LOCAL(scoped_ptr<RandomGenerator>, global_rng,
226 (new SecureRandomGenerator()));
227 return global_rng;
228}
229
230RandomGenerator& Rng() {
231 return *GetGlobalRng();
232}
233
234} // namespace
235
236void SetRandomTestMode(bool test) {
237 if (!test) {
238 GetGlobalRng().reset(new SecureRandomGenerator());
239 } else {
240 GetGlobalRng().reset(new TestRandomGenerator());
241 }
242}
243
244bool InitRandom(int seed) {
245 return InitRandom(reinterpret_cast<const char*>(&seed), sizeof(seed));
246}
247
248bool InitRandom(const char* seed, size_t len) {
249 if (!Rng().Init(seed, len)) {
250 LOG(LS_ERROR) << "Failed to init random generator!";
251 return false;
252 }
253 return true;
254}
255
256std::string CreateRandomString(size_t len) {
257 std::string str;
258 CreateRandomString(len, &str);
259 return str;
260}
261
262bool CreateRandomString(size_t len,
263 const char* table, int table_size,
264 std::string* str) {
265 str->clear();
wu@webrtc.org5c9dd592013-10-25 21:18:33 +0000266 scoped_ptr<uint8[]> bytes(new uint8[len]);
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000267 if (!Rng().Generate(bytes.get(), len)) {
268 LOG(LS_ERROR) << "Failed to generate random string!";
269 return false;
270 }
271 str->reserve(len);
272 for (size_t i = 0; i < len; ++i) {
273 str->push_back(table[bytes[i] % table_size]);
274 }
275 return true;
276}
277
278bool CreateRandomString(size_t len, std::string* str) {
279 return CreateRandomString(len, BASE64, 64, str);
280}
281
282bool CreateRandomString(size_t len, const std::string& table,
283 std::string* str) {
284 return CreateRandomString(len, table.c_str(),
285 static_cast<int>(table.size()), str);
286}
287
288uint32 CreateRandomId() {
289 uint32 id;
290 if (!Rng().Generate(&id, sizeof(id))) {
291 LOG(LS_ERROR) << "Failed to generate random id!";
292 }
293 return id;
294}
295
296uint64 CreateRandomId64() {
henrike@webrtc.org1a04b882013-07-22 21:07:49 +0000297 return static_cast<uint64>(CreateRandomId()) << 32 | CreateRandomId();
henrike@webrtc.org0e118e72013-07-10 00:45:36 +0000298}
299
300uint32 CreateRandomNonZeroId() {
301 uint32 id;
302 do {
303 id = CreateRandomId();
304 } while (id == 0);
305 return id;
306}
307
308double CreateRandomDouble() {
309 return CreateRandomId() / (std::numeric_limits<uint32>::max() +
310 std::numeric_limits<double>::epsilon());
311}
312
313} // namespace talk_base