blob: be71fee0f3dbf2344de077b0fa41fec0ef44fd86 [file] [log] [blame]
henrike@webrtc.orgf0488722014-05-13 18:00:26 +00001/*
2 * Copyright 2004 The WebRTC Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/base/helpers.h"
12
13#include <limits>
jbauch555604a2016-04-26 03:13:22 -070014#include <memory>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000015
16#if defined(FEATURE_ENABLE_SSL)
17#include "webrtc/base/sslconfig.h"
18#if defined(SSL_USE_OPENSSL)
19#include <openssl/rand.h>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000020#else
21#if defined(WEBRTC_WIN)
22#define WIN32_LEAN_AND_MEAN
23#include <windows.h>
24#include <ntsecapi.h>
kjellander979e0b32015-06-16 07:13:35 -070025#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000026#endif // else
27#endif // FEATURE_ENABLED_SSL
28
29#include "webrtc/base/base64.h"
30#include "webrtc/base/basictypes.h"
31#include "webrtc/base/logging.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000032#include "webrtc/base/timeutils.h"
33
34// Protect against max macro inclusion.
35#undef max
36
37namespace rtc {
38
39// Base class for RNG implementations.
40class RandomGenerator {
41 public:
42 virtual ~RandomGenerator() {}
43 virtual bool Init(const void* seed, size_t len) = 0;
44 virtual bool Generate(void* buf, size_t len) = 0;
45};
46
47#if defined(SSL_USE_OPENSSL)
henrike@webrtc.orgd89b69a2014-11-06 17:23:09 +000048// The OpenSSL RNG.
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000049class SecureRandomGenerator : public RandomGenerator {
50 public:
henrike@webrtc.orgd89b69a2014-11-06 17:23:09 +000051 SecureRandomGenerator() {}
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000052 ~SecureRandomGenerator() override {}
53 bool Init(const void* seed, size_t len) override { return true; }
54 bool Generate(void* buf, size_t len) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000055 return (RAND_bytes(reinterpret_cast<unsigned char*>(buf), len) > 0);
56 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000057};
58
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000059#else
60#if defined(WEBRTC_WIN)
61class SecureRandomGenerator : public RandomGenerator {
62 public:
63 SecureRandomGenerator() : advapi32_(NULL), rtl_gen_random_(NULL) {}
64 ~SecureRandomGenerator() {
65 FreeLibrary(advapi32_);
66 }
67
68 virtual bool Init(const void* seed, size_t seed_len) {
69 // We don't do any additional seeding on Win32, we just use the CryptoAPI
70 // RNG (which is exposed as a hidden function off of ADVAPI32 so that we
71 // don't need to drag in all of CryptoAPI)
72 if (rtl_gen_random_) {
73 return true;
74 }
75
76 advapi32_ = LoadLibrary(L"advapi32.dll");
77 if (!advapi32_) {
78 return false;
79 }
80
81 rtl_gen_random_ = reinterpret_cast<RtlGenRandomProc>(
82 GetProcAddress(advapi32_, "SystemFunction036"));
83 if (!rtl_gen_random_) {
84 FreeLibrary(advapi32_);
85 return false;
86 }
87
88 return true;
89 }
90 virtual bool Generate(void* buf, size_t len) {
91 if (!rtl_gen_random_ && !Init(NULL, 0)) {
92 return false;
93 }
94 return (rtl_gen_random_(buf, static_cast<int>(len)) != FALSE);
95 }
96
97 private:
98 typedef BOOL (WINAPI *RtlGenRandomProc)(PVOID, ULONG);
99 HINSTANCE advapi32_;
100 RtlGenRandomProc rtl_gen_random_;
101};
102
103#elif !defined(FEATURE_ENABLE_SSL)
104
105// No SSL implementation -- use rand()
106class SecureRandomGenerator : public RandomGenerator {
107 public:
108 virtual bool Init(const void* seed, size_t len) {
109 if (len >= 4) {
110 srand(*reinterpret_cast<const int*>(seed));
111 } else {
112 srand(*reinterpret_cast<const char*>(seed));
113 }
114 return true;
115 }
116 virtual bool Generate(void* buf, size_t len) {
117 char* bytes = reinterpret_cast<char*>(buf);
118 for (size_t i = 0; i < len; ++i) {
119 bytes[i] = static_cast<char>(rand());
120 }
121 return true;
122 }
123};
124
125#else
126
127#error No SSL implementation has been selected!
128
kjellander979e0b32015-06-16 07:13:35 -0700129#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000130#endif
131
132// A test random generator, for predictable output.
133class TestRandomGenerator : public RandomGenerator {
134 public:
135 TestRandomGenerator() : seed_(7) {
136 }
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000137 ~TestRandomGenerator() override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000138 }
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000139 bool Init(const void* seed, size_t len) override { return true; }
140 bool Generate(void* buf, size_t len) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000141 for (size_t i = 0; i < len; ++i) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200142 static_cast<uint8_t*>(buf)[i] = static_cast<uint8_t>(GetRandom());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000143 }
144 return true;
145 }
146
147 private:
148 int GetRandom() {
149 return ((seed_ = seed_ * 214013L + 2531011L) >> 16) & 0x7fff;
150 }
151 int seed_;
152};
153
deadbeef5def7b92015-11-20 11:43:22 -0800154namespace {
deadbeef6834fa12015-11-20 09:49:59 -0800155
deadbeeffac06552015-11-25 11:26:01 -0800156// TODO: Use Base64::Base64Table instead.
157static const char kBase64[64] = {
158 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
159 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
160 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
161 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
162 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
163
164static const char kHex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
165 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
166
167static const char kUuidDigit17[4] = {'8', '9', 'a', 'b'};
168
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000169// This round about way of creating a global RNG is to safe-guard against
170// indeterminant static initialization order.
jbauch555604a2016-04-26 03:13:22 -0700171std::unique_ptr<RandomGenerator>& GetGlobalRng() {
172 RTC_DEFINE_STATIC_LOCAL(std::unique_ptr<RandomGenerator>, global_rng,
Andrew MacDonald469c2c02015-05-22 17:50:26 -0700173 (new SecureRandomGenerator()));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000174 return global_rng;
175}
176
177RandomGenerator& Rng() {
178 return *GetGlobalRng();
179}
180
181} // namespace
182
183void SetRandomTestMode(bool test) {
184 if (!test) {
185 GetGlobalRng().reset(new SecureRandomGenerator());
186 } else {
187 GetGlobalRng().reset(new TestRandomGenerator());
188 }
189}
190
191bool InitRandom(int seed) {
192 return InitRandom(reinterpret_cast<const char*>(&seed), sizeof(seed));
193}
194
195bool InitRandom(const char* seed, size_t len) {
196 if (!Rng().Init(seed, len)) {
197 LOG(LS_ERROR) << "Failed to init random generator!";
198 return false;
199 }
200 return true;
201}
202
203std::string CreateRandomString(size_t len) {
204 std::string str;
205 CreateRandomString(len, &str);
206 return str;
207}
208
209bool CreateRandomString(size_t len,
210 const char* table, int table_size,
211 std::string* str) {
212 str->clear();
jbauch555604a2016-04-26 03:13:22 -0700213 std::unique_ptr<uint8_t[]> bytes(new uint8_t[len]);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000214 if (!Rng().Generate(bytes.get(), len)) {
215 LOG(LS_ERROR) << "Failed to generate random string!";
216 return false;
217 }
218 str->reserve(len);
219 for (size_t i = 0; i < len; ++i) {
220 str->push_back(table[bytes[i] % table_size]);
221 }
222 return true;
223}
224
225bool CreateRandomString(size_t len, std::string* str) {
deadbeeffac06552015-11-25 11:26:01 -0800226 return CreateRandomString(len, kBase64, 64, str);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000227}
228
229bool CreateRandomString(size_t len, const std::string& table,
230 std::string* str) {
231 return CreateRandomString(len, table.c_str(),
232 static_cast<int>(table.size()), str);
233}
234
jbauchcb560652016-08-04 05:20:32 -0700235bool CreateRandomData(size_t length, std::string* data) {
236 data->resize(length);
237 // std::string is guaranteed to use contiguous memory in c++11 so we can
238 // safely write directly to it.
239 return Rng().Generate(&data->at(0), length);
240}
241
deadbeeffac06552015-11-25 11:26:01 -0800242// Version 4 UUID is of the form:
243// xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
244// Where 'x' is a hex digit, and 'y' is 8, 9, a or b.
245std::string CreateRandomUuid() {
246 std::string str;
jbauch555604a2016-04-26 03:13:22 -0700247 std::unique_ptr<uint8_t[]> bytes(new uint8_t[31]);
deadbeeffac06552015-11-25 11:26:01 -0800248 if (!Rng().Generate(bytes.get(), 31)) {
249 LOG(LS_ERROR) << "Failed to generate random string!";
250 return str;
251 }
252 str.reserve(36);
253 for (size_t i = 0; i < 8; ++i) {
254 str.push_back(kHex[bytes[i] % 16]);
255 }
256 str.push_back('-');
257 for (size_t i = 8; i < 12; ++i) {
258 str.push_back(kHex[bytes[i] % 16]);
259 }
260 str.push_back('-');
261 str.push_back('4');
262 for (size_t i = 12; i < 15; ++i) {
263 str.push_back(kHex[bytes[i] % 16]);
264 }
265 str.push_back('-');
266 str.push_back(kUuidDigit17[bytes[15] % 4]);
267 for (size_t i = 16; i < 19; ++i) {
268 str.push_back(kHex[bytes[i] % 16]);
269 }
270 str.push_back('-');
271 for (size_t i = 19; i < 31; ++i) {
272 str.push_back(kHex[bytes[i] % 16]);
273 }
274 return str;
275}
276
Peter Boström0c4e06b2015-10-07 12:23:21 +0200277uint32_t CreateRandomId() {
278 uint32_t id;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000279 if (!Rng().Generate(&id, sizeof(id))) {
280 LOG(LS_ERROR) << "Failed to generate random id!";
281 }
282 return id;
283}
284
Peter Boström0c4e06b2015-10-07 12:23:21 +0200285uint64_t CreateRandomId64() {
286 return static_cast<uint64_t>(CreateRandomId()) << 32 | CreateRandomId();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000287}
288
Peter Boström0c4e06b2015-10-07 12:23:21 +0200289uint32_t CreateRandomNonZeroId() {
290 uint32_t id;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000291 do {
292 id = CreateRandomId();
293 } while (id == 0);
294 return id;
295}
296
297double CreateRandomDouble() {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200298 return CreateRandomId() / (std::numeric_limits<uint32_t>::max() +
299 std::numeric_limits<double>::epsilon());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000300}
301
302} // namespace rtc