blob: 9674eb985955be683d6678005053b5768f112b2f [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
210bool CreateRandomString(size_t len,
211 const char* table, int table_size,
212 std::string* str) {
213 str->clear();
jbauch555604a2016-04-26 03:13:22 -0700214 std::unique_ptr<uint8_t[]> bytes(new uint8_t[len]);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000215 if (!Rng().Generate(bytes.get(), len)) {
216 LOG(LS_ERROR) << "Failed to generate random string!";
217 return false;
218 }
219 str->reserve(len);
220 for (size_t i = 0; i < len; ++i) {
221 str->push_back(table[bytes[i] % table_size]);
222 }
223 return true;
224}
225
226bool CreateRandomString(size_t len, std::string* str) {
deadbeeffac06552015-11-25 11:26:01 -0800227 return CreateRandomString(len, kBase64, 64, str);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000228}
229
230bool CreateRandomString(size_t len, const std::string& table,
231 std::string* str) {
232 return CreateRandomString(len, table.c_str(),
233 static_cast<int>(table.size()), str);
234}
235
jbauchcb560652016-08-04 05:20:32 -0700236bool CreateRandomData(size_t length, std::string* data) {
237 data->resize(length);
238 // std::string is guaranteed to use contiguous memory in c++11 so we can
239 // safely write directly to it.
240 return Rng().Generate(&data->at(0), length);
241}
242
deadbeeffac06552015-11-25 11:26:01 -0800243// Version 4 UUID is of the form:
244// xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
245// Where 'x' is a hex digit, and 'y' is 8, 9, a or b.
246std::string CreateRandomUuid() {
247 std::string str;
jbauch555604a2016-04-26 03:13:22 -0700248 std::unique_ptr<uint8_t[]> bytes(new uint8_t[31]);
jbauch912f46a2016-08-08 16:33:06 -0700249 RTC_CHECK(Rng().Generate(bytes.get(), 31));
deadbeeffac06552015-11-25 11:26:01 -0800250 str.reserve(36);
251 for (size_t i = 0; i < 8; ++i) {
252 str.push_back(kHex[bytes[i] % 16]);
253 }
254 str.push_back('-');
255 for (size_t i = 8; i < 12; ++i) {
256 str.push_back(kHex[bytes[i] % 16]);
257 }
258 str.push_back('-');
259 str.push_back('4');
260 for (size_t i = 12; i < 15; ++i) {
261 str.push_back(kHex[bytes[i] % 16]);
262 }
263 str.push_back('-');
264 str.push_back(kUuidDigit17[bytes[15] % 4]);
265 for (size_t i = 16; i < 19; ++i) {
266 str.push_back(kHex[bytes[i] % 16]);
267 }
268 str.push_back('-');
269 for (size_t i = 19; i < 31; ++i) {
270 str.push_back(kHex[bytes[i] % 16]);
271 }
272 return str;
273}
274
Peter Boström0c4e06b2015-10-07 12:23:21 +0200275uint32_t CreateRandomId() {
276 uint32_t id;
jbauch912f46a2016-08-08 16:33:06 -0700277 RTC_CHECK(Rng().Generate(&id, sizeof(id)));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000278 return id;
279}
280
Peter Boström0c4e06b2015-10-07 12:23:21 +0200281uint64_t CreateRandomId64() {
282 return static_cast<uint64_t>(CreateRandomId()) << 32 | CreateRandomId();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000283}
284
Peter Boström0c4e06b2015-10-07 12:23:21 +0200285uint32_t CreateRandomNonZeroId() {
286 uint32_t id;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000287 do {
288 id = CreateRandomId();
289 } while (id == 0);
290 return id;
291}
292
293double CreateRandomDouble() {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200294 return CreateRandomId() / (std::numeric_limits<uint32_t>::max() +
295 std::numeric_limits<double>::epsilon());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000296}
297
298} // namespace rtc