blob: 1ad5d0e12ba9ae55ba302e3965f790e08744e050 [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>
14
15#if defined(FEATURE_ENABLE_SSL)
16#include "webrtc/base/sslconfig.h"
17#if defined(SSL_USE_OPENSSL)
18#include <openssl/rand.h>
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000019#else
20#if defined(WEBRTC_WIN)
21#define WIN32_LEAN_AND_MEAN
22#include <windows.h>
23#include <ntsecapi.h>
kjellander979e0b32015-06-16 07:13:35 -070024#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000025#endif // else
26#endif // FEATURE_ENABLED_SSL
27
28#include "webrtc/base/base64.h"
29#include "webrtc/base/basictypes.h"
30#include "webrtc/base/logging.h"
31#include "webrtc/base/scoped_ptr.h"
32#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
59#elif defined(SSL_USE_NSS_RNG)
60// The NSS RNG.
61class SecureRandomGenerator : public RandomGenerator {
62 public:
63 SecureRandomGenerator() {}
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000064 ~SecureRandomGenerator() override {}
65 bool Init(const void* seed, size_t len) override { return true; }
66 bool Generate(void* buf, size_t len) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000067 return (PK11_GenerateRandom(reinterpret_cast<unsigned char*>(buf),
68 static_cast<int>(len)) == SECSuccess);
69 }
70};
71
72#else
73#if defined(WEBRTC_WIN)
74class SecureRandomGenerator : public RandomGenerator {
75 public:
76 SecureRandomGenerator() : advapi32_(NULL), rtl_gen_random_(NULL) {}
77 ~SecureRandomGenerator() {
78 FreeLibrary(advapi32_);
79 }
80
81 virtual bool Init(const void* seed, size_t seed_len) {
82 // We don't do any additional seeding on Win32, we just use the CryptoAPI
83 // RNG (which is exposed as a hidden function off of ADVAPI32 so that we
84 // don't need to drag in all of CryptoAPI)
85 if (rtl_gen_random_) {
86 return true;
87 }
88
89 advapi32_ = LoadLibrary(L"advapi32.dll");
90 if (!advapi32_) {
91 return false;
92 }
93
94 rtl_gen_random_ = reinterpret_cast<RtlGenRandomProc>(
95 GetProcAddress(advapi32_, "SystemFunction036"));
96 if (!rtl_gen_random_) {
97 FreeLibrary(advapi32_);
98 return false;
99 }
100
101 return true;
102 }
103 virtual bool Generate(void* buf, size_t len) {
104 if (!rtl_gen_random_ && !Init(NULL, 0)) {
105 return false;
106 }
107 return (rtl_gen_random_(buf, static_cast<int>(len)) != FALSE);
108 }
109
110 private:
111 typedef BOOL (WINAPI *RtlGenRandomProc)(PVOID, ULONG);
112 HINSTANCE advapi32_;
113 RtlGenRandomProc rtl_gen_random_;
114};
115
116#elif !defined(FEATURE_ENABLE_SSL)
117
118// No SSL implementation -- use rand()
119class SecureRandomGenerator : public RandomGenerator {
120 public:
121 virtual bool Init(const void* seed, size_t len) {
122 if (len >= 4) {
123 srand(*reinterpret_cast<const int*>(seed));
124 } else {
125 srand(*reinterpret_cast<const char*>(seed));
126 }
127 return true;
128 }
129 virtual bool Generate(void* buf, size_t len) {
130 char* bytes = reinterpret_cast<char*>(buf);
131 for (size_t i = 0; i < len; ++i) {
132 bytes[i] = static_cast<char>(rand());
133 }
134 return true;
135 }
136};
137
138#else
139
140#error No SSL implementation has been selected!
141
kjellander979e0b32015-06-16 07:13:35 -0700142#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000143#endif
144
145// A test random generator, for predictable output.
146class TestRandomGenerator : public RandomGenerator {
147 public:
148 TestRandomGenerator() : seed_(7) {
149 }
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000150 ~TestRandomGenerator() override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000151 }
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000152 bool Init(const void* seed, size_t len) override { return true; }
153 bool Generate(void* buf, size_t len) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000154 for (size_t i = 0; i < len; ++i) {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200155 static_cast<uint8_t*>(buf)[i] = static_cast<uint8_t>(GetRandom());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000156 }
157 return true;
158 }
159
160 private:
161 int GetRandom() {
162 return ((seed_ = seed_ * 214013L + 2531011L) >> 16) & 0x7fff;
163 }
164 int seed_;
165};
166
deadbeef5def7b92015-11-20 11:43:22 -0800167namespace {
deadbeef6834fa12015-11-20 09:49:59 -0800168
deadbeeffac06552015-11-25 11:26:01 -0800169// TODO: Use Base64::Base64Table instead.
170static const char kBase64[64] = {
171 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
172 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
173 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
174 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
175 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
176
177static const char kHex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
178 '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
179
180static const char kUuidDigit17[4] = {'8', '9', 'a', 'b'};
181
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000182// This round about way of creating a global RNG is to safe-guard against
183// indeterminant static initialization order.
184scoped_ptr<RandomGenerator>& GetGlobalRng() {
Andrew MacDonald469c2c02015-05-22 17:50:26 -0700185 RTC_DEFINE_STATIC_LOCAL(scoped_ptr<RandomGenerator>, global_rng,
186 (new SecureRandomGenerator()));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000187 return global_rng;
188}
189
190RandomGenerator& Rng() {
191 return *GetGlobalRng();
192}
193
194} // namespace
195
196void SetRandomTestMode(bool test) {
197 if (!test) {
198 GetGlobalRng().reset(new SecureRandomGenerator());
199 } else {
200 GetGlobalRng().reset(new TestRandomGenerator());
201 }
202}
203
204bool InitRandom(int seed) {
205 return InitRandom(reinterpret_cast<const char*>(&seed), sizeof(seed));
206}
207
208bool InitRandom(const char* seed, size_t len) {
209 if (!Rng().Init(seed, len)) {
210 LOG(LS_ERROR) << "Failed to init random generator!";
211 return false;
212 }
213 return true;
214}
215
216std::string CreateRandomString(size_t len) {
217 std::string str;
218 CreateRandomString(len, &str);
219 return str;
220}
221
222bool CreateRandomString(size_t len,
223 const char* table, int table_size,
224 std::string* str) {
225 str->clear();
Peter Boström0c4e06b2015-10-07 12:23:21 +0200226 scoped_ptr<uint8_t[]> bytes(new uint8_t[len]);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000227 if (!Rng().Generate(bytes.get(), len)) {
228 LOG(LS_ERROR) << "Failed to generate random string!";
229 return false;
230 }
231 str->reserve(len);
232 for (size_t i = 0; i < len; ++i) {
233 str->push_back(table[bytes[i] % table_size]);
234 }
235 return true;
236}
237
238bool CreateRandomString(size_t len, std::string* str) {
deadbeeffac06552015-11-25 11:26:01 -0800239 return CreateRandomString(len, kBase64, 64, str);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000240}
241
242bool CreateRandomString(size_t len, const std::string& table,
243 std::string* str) {
244 return CreateRandomString(len, table.c_str(),
245 static_cast<int>(table.size()), str);
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;
253 scoped_ptr<uint8_t[]> bytes(new uint8_t[31]);
254 if (!Rng().Generate(bytes.get(), 31)) {
255 LOG(LS_ERROR) << "Failed to generate random string!";
256 return str;
257 }
258 str.reserve(36);
259 for (size_t i = 0; i < 8; ++i) {
260 str.push_back(kHex[bytes[i] % 16]);
261 }
262 str.push_back('-');
263 for (size_t i = 8; i < 12; ++i) {
264 str.push_back(kHex[bytes[i] % 16]);
265 }
266 str.push_back('-');
267 str.push_back('4');
268 for (size_t i = 12; i < 15; ++i) {
269 str.push_back(kHex[bytes[i] % 16]);
270 }
271 str.push_back('-');
272 str.push_back(kUuidDigit17[bytes[15] % 4]);
273 for (size_t i = 16; i < 19; ++i) {
274 str.push_back(kHex[bytes[i] % 16]);
275 }
276 str.push_back('-');
277 for (size_t i = 19; i < 31; ++i) {
278 str.push_back(kHex[bytes[i] % 16]);
279 }
280 return str;
281}
282
Peter Boström0c4e06b2015-10-07 12:23:21 +0200283uint32_t CreateRandomId() {
284 uint32_t id;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000285 if (!Rng().Generate(&id, sizeof(id))) {
286 LOG(LS_ERROR) << "Failed to generate random id!";
287 }
288 return id;
289}
290
Peter Boström0c4e06b2015-10-07 12:23:21 +0200291uint64_t CreateRandomId64() {
292 return static_cast<uint64_t>(CreateRandomId()) << 32 | CreateRandomId();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000293}
294
Peter Boström0c4e06b2015-10-07 12:23:21 +0200295uint32_t CreateRandomNonZeroId() {
296 uint32_t id;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000297 do {
298 id = CreateRandomId();
299 } while (id == 0);
300 return id;
301}
302
303double CreateRandomDouble() {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200304 return CreateRandomId() / (std::numeric_limits<uint32_t>::max() +
305 std::numeric_limits<double>::epsilon());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000306}
307
308} // namespace rtc