blob: 8e59b6410c580b1721a689aee33bc33d758983c6 [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
167// TODO: Use Base64::Base64Table instead.
168static const char BASE64[64] = {
169 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
170 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
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 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
174};
175
176namespace {
177
178// This round about way of creating a global RNG is to safe-guard against
179// indeterminant static initialization order.
180scoped_ptr<RandomGenerator>& GetGlobalRng() {
Andrew MacDonald469c2c02015-05-22 17:50:26 -0700181 RTC_DEFINE_STATIC_LOCAL(scoped_ptr<RandomGenerator>, global_rng,
182 (new SecureRandomGenerator()));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000183 return global_rng;
184}
185
186RandomGenerator& Rng() {
187 return *GetGlobalRng();
188}
189
190} // namespace
191
192void SetRandomTestMode(bool test) {
193 if (!test) {
194 GetGlobalRng().reset(new SecureRandomGenerator());
195 } else {
196 GetGlobalRng().reset(new TestRandomGenerator());
197 }
198}
199
200bool InitRandom(int seed) {
201 return InitRandom(reinterpret_cast<const char*>(&seed), sizeof(seed));
202}
203
204bool InitRandom(const char* seed, size_t len) {
205 if (!Rng().Init(seed, len)) {
206 LOG(LS_ERROR) << "Failed to init random generator!";
207 return false;
208 }
209 return true;
210}
211
212std::string CreateRandomString(size_t len) {
213 std::string str;
214 CreateRandomString(len, &str);
215 return str;
216}
217
218bool CreateRandomString(size_t len,
219 const char* table, int table_size,
220 std::string* str) {
221 str->clear();
Peter Boström0c4e06b2015-10-07 12:23:21 +0200222 scoped_ptr<uint8_t[]> bytes(new uint8_t[len]);
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000223 if (!Rng().Generate(bytes.get(), len)) {
224 LOG(LS_ERROR) << "Failed to generate random string!";
225 return false;
226 }
227 str->reserve(len);
228 for (size_t i = 0; i < len; ++i) {
229 str->push_back(table[bytes[i] % table_size]);
230 }
231 return true;
232}
233
234bool CreateRandomString(size_t len, std::string* str) {
235 return CreateRandomString(len, BASE64, 64, str);
236}
237
238bool CreateRandomString(size_t len, const std::string& table,
239 std::string* str) {
240 return CreateRandomString(len, table.c_str(),
241 static_cast<int>(table.size()), str);
242}
243
Peter Boström0c4e06b2015-10-07 12:23:21 +0200244uint32_t CreateRandomId() {
245 uint32_t id;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000246 if (!Rng().Generate(&id, sizeof(id))) {
247 LOG(LS_ERROR) << "Failed to generate random id!";
248 }
249 return id;
250}
251
Peter Boström0c4e06b2015-10-07 12:23:21 +0200252uint64_t CreateRandomId64() {
253 return static_cast<uint64_t>(CreateRandomId()) << 32 | CreateRandomId();
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000254}
255
Peter Boström0c4e06b2015-10-07 12:23:21 +0200256uint32_t CreateRandomNonZeroId() {
257 uint32_t id;
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000258 do {
259 id = CreateRandomId();
260 } while (id == 0);
261 return id;
262}
263
264double CreateRandomDouble() {
Peter Boström0c4e06b2015-10-07 12:23:21 +0200265 return CreateRandomId() / (std::numeric_limits<uint32_t>::max() +
266 std::numeric_limits<double>::epsilon());
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000267}
268
269} // namespace rtc