blob: a8389d462e9c08b8db56f130d59109fcb0ccf877 [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"
jbauch912f46a2016-08-08 16:33:06 -070031#include "webrtc/base/checks.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000032#include "webrtc/base/logging.h"
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000033#include "webrtc/base/timeutils.h"
34
35// Protect against max macro inclusion.
36#undef max
37
38namespace rtc {
39
40// Base class for RNG implementations.
41class RandomGenerator {
42 public:
43 virtual ~RandomGenerator() {}
44 virtual bool Init(const void* seed, size_t len) = 0;
45 virtual bool Generate(void* buf, size_t len) = 0;
46};
47
48#if defined(SSL_USE_OPENSSL)
henrike@webrtc.orgd89b69a2014-11-06 17:23:09 +000049// The OpenSSL RNG.
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000050class SecureRandomGenerator : public RandomGenerator {
51 public:
henrike@webrtc.orgd89b69a2014-11-06 17:23:09 +000052 SecureRandomGenerator() {}
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000053 ~SecureRandomGenerator() override {}
54 bool Init(const void* seed, size_t len) override { return true; }
55 bool Generate(void* buf, size_t len) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000056 return (RAND_bytes(reinterpret_cast<unsigned char*>(buf), len) > 0);
57 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000058};
59
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000060#else
61#if defined(WEBRTC_WIN)
62class SecureRandomGenerator : public RandomGenerator {
63 public:
64 SecureRandomGenerator() : advapi32_(NULL), rtl_gen_random_(NULL) {}
65 ~SecureRandomGenerator() {
66 FreeLibrary(advapi32_);
67 }
68
69 virtual bool Init(const void* seed, size_t seed_len) {
70 // We don't do any additional seeding on Win32, we just use the CryptoAPI
71 // RNG (which is exposed as a hidden function off of ADVAPI32 so that we
72 // don't need to drag in all of CryptoAPI)
73 if (rtl_gen_random_) {
74 return true;
75 }
76
77 advapi32_ = LoadLibrary(L"advapi32.dll");
78 if (!advapi32_) {
79 return false;
80 }
81
82 rtl_gen_random_ = reinterpret_cast<RtlGenRandomProc>(
83 GetProcAddress(advapi32_, "SystemFunction036"));
84 if (!rtl_gen_random_) {
85 FreeLibrary(advapi32_);
86 return false;
87 }
88
89 return true;
90 }
91 virtual bool Generate(void* buf, size_t len) {
92 if (!rtl_gen_random_ && !Init(NULL, 0)) {
93 return false;
94 }
95 return (rtl_gen_random_(buf, static_cast<int>(len)) != FALSE);
96 }
97
98 private:
99 typedef BOOL (WINAPI *RtlGenRandomProc)(PVOID, ULONG);
100 HINSTANCE advapi32_;
101 RtlGenRandomProc rtl_gen_random_;
102};
103
104#elif !defined(FEATURE_ENABLE_SSL)
105
106// No SSL implementation -- use rand()
107class SecureRandomGenerator : public RandomGenerator {
108 public:
109 virtual bool Init(const void* seed, size_t len) {
110 if (len >= 4) {
111 srand(*reinterpret_cast<const int*>(seed));
112 } else {
113 srand(*reinterpret_cast<const char*>(seed));
114 }
115 return true;
116 }
117 virtual bool Generate(void* buf, size_t len) {
118 char* bytes = reinterpret_cast<char*>(buf);
119 for (size_t i = 0; i < len; ++i) {
120 bytes[i] = static_cast<char>(rand());
121 }
122 return true;
123 }
124};
125
126#else
127
128#error No SSL implementation has been selected!
129
kjellander979e0b32015-06-16 07:13:35 -0700130#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000131#endif
132
133// A test random generator, for predictable output.
134class TestRandomGenerator : public RandomGenerator {
135 public:
136 TestRandomGenerator() : seed_(7) {
137 }
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000138 ~TestRandomGenerator() override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000139 }
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000140 bool Init(const void* seed, size_t len) override { return true; }
141 bool Generate(void* buf, size_t len) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000142 for (size_t i = 0; i < len; ++i) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200143 static_cast<uint8_t*>(buf)[i] = static_cast<uint8_t>(GetRandom());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000144 }
145 return true;
146 }
147
148 private:
149 int GetRandom() {
150 return ((seed_ = seed_ * 214013L + 2531011L) >> 16) & 0x7fff;
151 }
152 int seed_;
153};
154
deadbeef5def7b92015-11-20 11:43:22 -0800155namespace {
deadbeef6834fa12015-11-20 09:49:59 -0800156
deadbeeffac06552015-11-25 11:26:01 -0800157// TODO: Use Base64::Base64Table instead.
158static const char kBase64[64] = {
159 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
160 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
161 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
162 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
163 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
164
165static const char kHex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
166 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
167
168static const char kUuidDigit17[4] = {'8', '9', 'a', 'b'};
169
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000170// This round about way of creating a global RNG is to safe-guard against
171// indeterminant static initialization order.
jbauch555604a2016-04-26 03:13:22 -0700172std::unique_ptr<RandomGenerator>& GetGlobalRng() {
173 RTC_DEFINE_STATIC_LOCAL(std::unique_ptr<RandomGenerator>, global_rng,
Andrew MacDonald469c2c02015-05-22 17:50:26 -0700174 (new SecureRandomGenerator()));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000175 return global_rng;
176}
177
178RandomGenerator& Rng() {
179 return *GetGlobalRng();
180}
181
182} // namespace
183
184void SetRandomTestMode(bool test) {
185 if (!test) {
186 GetGlobalRng().reset(new SecureRandomGenerator());
187 } else {
188 GetGlobalRng().reset(new TestRandomGenerator());
189 }
190}
191
192bool InitRandom(int seed) {
193 return InitRandom(reinterpret_cast<const char*>(&seed), sizeof(seed));
194}
195
196bool InitRandom(const char* seed, size_t len) {
197 if (!Rng().Init(seed, len)) {
198 LOG(LS_ERROR) << "Failed to init random generator!";
199 return false;
200 }
201 return true;
202}
203
204std::string CreateRandomString(size_t len) {
205 std::string str;
jbauch912f46a2016-08-08 16:33:06 -0700206 RTC_CHECK(CreateRandomString(len, &str));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000207 return str;
208}
209
jbauche3eff7c2016-08-08 17:13:33 -0700210static bool CreateRandomString(size_t len,
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000211 const char* table, int table_size,
212 std::string* str) {
213 str->clear();
jbauche3eff7c2016-08-08 17:13:33 -0700214 // Avoid biased modulo division below.
215 if (256 % table_size) {
216 LOG(LS_ERROR) << "Table size must divide 256 evenly!";
217 return false;
218 }
jbauch555604a2016-04-26 03:13:22 -0700219 std::unique_ptr<uint8_t[]> bytes(new uint8_t[len]);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000220 if (!Rng().Generate(bytes.get(), len)) {
221 LOG(LS_ERROR) << "Failed to generate random string!";
222 return false;
223 }
224 str->reserve(len);
225 for (size_t i = 0; i < len; ++i) {
226 str->push_back(table[bytes[i] % table_size]);
227 }
228 return true;
229}
230
231bool CreateRandomString(size_t len, std::string* str) {
deadbeeffac06552015-11-25 11:26:01 -0800232 return CreateRandomString(len, kBase64, 64, str);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000233}
234
235bool CreateRandomString(size_t len, const std::string& table,
236 std::string* str) {
237 return CreateRandomString(len, table.c_str(),
238 static_cast<int>(table.size()), str);
239}
240
jbauchcb560652016-08-04 05:20:32 -0700241bool CreateRandomData(size_t length, std::string* data) {
242 data->resize(length);
243 // std::string is guaranteed to use contiguous memory in c++11 so we can
244 // safely write directly to it.
245 return Rng().Generate(&data->at(0), length);
246}
247
deadbeeffac06552015-11-25 11:26:01 -0800248// Version 4 UUID is of the form:
249// xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
250// Where 'x' is a hex digit, and 'y' is 8, 9, a or b.
251std::string CreateRandomUuid() {
252 std::string str;
jbauch555604a2016-04-26 03:13:22 -0700253 std::unique_ptr<uint8_t[]> bytes(new uint8_t[31]);
jbauch912f46a2016-08-08 16:33:06 -0700254 RTC_CHECK(Rng().Generate(bytes.get(), 31));
deadbeeffac06552015-11-25 11:26:01 -0800255 str.reserve(36);
256 for (size_t i = 0; i < 8; ++i) {
257 str.push_back(kHex[bytes[i] % 16]);
258 }
259 str.push_back('-');
260 for (size_t i = 8; i < 12; ++i) {
261 str.push_back(kHex[bytes[i] % 16]);
262 }
263 str.push_back('-');
264 str.push_back('4');
265 for (size_t i = 12; i < 15; ++i) {
266 str.push_back(kHex[bytes[i] % 16]);
267 }
268 str.push_back('-');
269 str.push_back(kUuidDigit17[bytes[15] % 4]);
270 for (size_t i = 16; i < 19; ++i) {
271 str.push_back(kHex[bytes[i] % 16]);
272 }
273 str.push_back('-');
274 for (size_t i = 19; i < 31; ++i) {
275 str.push_back(kHex[bytes[i] % 16]);
276 }
277 return str;
278}
279
Peter Boström0c4e06b2015-10-07 12:23:21 +0200280uint32_t CreateRandomId() {
281 uint32_t id;
jbauch912f46a2016-08-08 16:33:06 -0700282 RTC_CHECK(Rng().Generate(&id, sizeof(id)));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000283 return id;
284}
285
Peter Boström0c4e06b2015-10-07 12:23:21 +0200286uint64_t CreateRandomId64() {
287 return static_cast<uint64_t>(CreateRandomId()) << 32 | CreateRandomId();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000288}
289
Peter Boström0c4e06b2015-10-07 12:23:21 +0200290uint32_t CreateRandomNonZeroId() {
291 uint32_t id;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000292 do {
293 id = CreateRandomId();
294 } while (id == 0);
295 return id;
296}
297
298double CreateRandomDouble() {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200299 return CreateRandomId() / (std::numeric_limits<uint32_t>::max() +
300 std::numeric_limits<double>::epsilon());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000301}
302
303} // namespace rtc