blob: e12ba107eac3e97b57e6364f97cf5a56d27e5e4c [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>
19#elif defined(SSL_USE_NSS_RNG)
kjellander979e0b32015-06-16 07:13:35 -070020// Hack: Define+undefine int64 and uint64 to avoid typedef conflict with NSS.
21// TODO(kjellander): Remove when webrtc:4497 is completed.
22#define uint64 foo_uint64
23#define int64 foo_int64
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000024#include "pk11func.h"
kjellander979e0b32015-06-16 07:13:35 -070025#undef uint64
26#undef int64
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000027#else
28#if defined(WEBRTC_WIN)
29#define WIN32_LEAN_AND_MEAN
30#include <windows.h>
31#include <ntsecapi.h>
kjellander979e0b32015-06-16 07:13:35 -070032#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000033#endif // else
34#endif // FEATURE_ENABLED_SSL
35
36#include "webrtc/base/base64.h"
37#include "webrtc/base/basictypes.h"
38#include "webrtc/base/logging.h"
39#include "webrtc/base/scoped_ptr.h"
40#include "webrtc/base/timeutils.h"
41
42// Protect against max macro inclusion.
43#undef max
44
45namespace rtc {
46
47// Base class for RNG implementations.
48class RandomGenerator {
49 public:
50 virtual ~RandomGenerator() {}
51 virtual bool Init(const void* seed, size_t len) = 0;
52 virtual bool Generate(void* buf, size_t len) = 0;
53};
54
55#if defined(SSL_USE_OPENSSL)
henrike@webrtc.orgd89b69a2014-11-06 17:23:09 +000056// The OpenSSL RNG.
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000057class SecureRandomGenerator : public RandomGenerator {
58 public:
henrike@webrtc.orgd89b69a2014-11-06 17:23:09 +000059 SecureRandomGenerator() {}
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000060 ~SecureRandomGenerator() override {}
61 bool Init(const void* seed, size_t len) override { return true; }
62 bool Generate(void* buf, size_t len) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000063 return (RAND_bytes(reinterpret_cast<unsigned char*>(buf), len) > 0);
64 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000065};
66
67#elif defined(SSL_USE_NSS_RNG)
68// The NSS RNG.
69class SecureRandomGenerator : public RandomGenerator {
70 public:
71 SecureRandomGenerator() {}
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000072 ~SecureRandomGenerator() override {}
73 bool Init(const void* seed, size_t len) override { return true; }
74 bool Generate(void* buf, size_t len) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000075 return (PK11_GenerateRandom(reinterpret_cast<unsigned char*>(buf),
76 static_cast<int>(len)) == SECSuccess);
77 }
78};
79
80#else
81#if defined(WEBRTC_WIN)
82class SecureRandomGenerator : public RandomGenerator {
83 public:
84 SecureRandomGenerator() : advapi32_(NULL), rtl_gen_random_(NULL) {}
85 ~SecureRandomGenerator() {
86 FreeLibrary(advapi32_);
87 }
88
89 virtual bool Init(const void* seed, size_t seed_len) {
90 // We don't do any additional seeding on Win32, we just use the CryptoAPI
91 // RNG (which is exposed as a hidden function off of ADVAPI32 so that we
92 // don't need to drag in all of CryptoAPI)
93 if (rtl_gen_random_) {
94 return true;
95 }
96
97 advapi32_ = LoadLibrary(L"advapi32.dll");
98 if (!advapi32_) {
99 return false;
100 }
101
102 rtl_gen_random_ = reinterpret_cast<RtlGenRandomProc>(
103 GetProcAddress(advapi32_, "SystemFunction036"));
104 if (!rtl_gen_random_) {
105 FreeLibrary(advapi32_);
106 return false;
107 }
108
109 return true;
110 }
111 virtual bool Generate(void* buf, size_t len) {
112 if (!rtl_gen_random_ && !Init(NULL, 0)) {
113 return false;
114 }
115 return (rtl_gen_random_(buf, static_cast<int>(len)) != FALSE);
116 }
117
118 private:
119 typedef BOOL (WINAPI *RtlGenRandomProc)(PVOID, ULONG);
120 HINSTANCE advapi32_;
121 RtlGenRandomProc rtl_gen_random_;
122};
123
124#elif !defined(FEATURE_ENABLE_SSL)
125
126// No SSL implementation -- use rand()
127class SecureRandomGenerator : public RandomGenerator {
128 public:
129 virtual bool Init(const void* seed, size_t len) {
130 if (len >= 4) {
131 srand(*reinterpret_cast<const int*>(seed));
132 } else {
133 srand(*reinterpret_cast<const char*>(seed));
134 }
135 return true;
136 }
137 virtual bool Generate(void* buf, size_t len) {
138 char* bytes = reinterpret_cast<char*>(buf);
139 for (size_t i = 0; i < len; ++i) {
140 bytes[i] = static_cast<char>(rand());
141 }
142 return true;
143 }
144};
145
146#else
147
148#error No SSL implementation has been selected!
149
kjellander979e0b32015-06-16 07:13:35 -0700150#endif // WEBRTC_WIN
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000151#endif
152
153// A test random generator, for predictable output.
154class TestRandomGenerator : public RandomGenerator {
155 public:
156 TestRandomGenerator() : seed_(7) {
157 }
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000158 ~TestRandomGenerator() override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000159 }
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000160 bool Init(const void* seed, size_t len) override { return true; }
161 bool Generate(void* buf, size_t len) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000162 for (size_t i = 0; i < len; ++i) {
163 static_cast<uint8*>(buf)[i] = static_cast<uint8>(GetRandom());
164 }
165 return true;
166 }
167
168 private:
169 int GetRandom() {
170 return ((seed_ = seed_ * 214013L + 2531011L) >> 16) & 0x7fff;
171 }
172 int seed_;
173};
174
175// TODO: Use Base64::Base64Table instead.
176static const char BASE64[64] = {
177 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
178 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
179 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
180 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
181 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
182};
183
184namespace {
185
186// This round about way of creating a global RNG is to safe-guard against
187// indeterminant static initialization order.
188scoped_ptr<RandomGenerator>& GetGlobalRng() {
Andrew MacDonald469c2c02015-05-22 17:50:26 -0700189 RTC_DEFINE_STATIC_LOCAL(scoped_ptr<RandomGenerator>, global_rng,
190 (new SecureRandomGenerator()));
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000191 return global_rng;
192}
193
194RandomGenerator& Rng() {
195 return *GetGlobalRng();
196}
197
198} // namespace
199
200void SetRandomTestMode(bool test) {
201 if (!test) {
202 GetGlobalRng().reset(new SecureRandomGenerator());
203 } else {
204 GetGlobalRng().reset(new TestRandomGenerator());
205 }
206}
207
208bool InitRandom(int seed) {
209 return InitRandom(reinterpret_cast<const char*>(&seed), sizeof(seed));
210}
211
212bool InitRandom(const char* seed, size_t len) {
213 if (!Rng().Init(seed, len)) {
214 LOG(LS_ERROR) << "Failed to init random generator!";
215 return false;
216 }
217 return true;
218}
219
220std::string CreateRandomString(size_t len) {
221 std::string str;
222 CreateRandomString(len, &str);
223 return str;
224}
225
226bool CreateRandomString(size_t len,
227 const char* table, int table_size,
228 std::string* str) {
229 str->clear();
230 scoped_ptr<uint8[]> bytes(new uint8[len]);
231 if (!Rng().Generate(bytes.get(), len)) {
232 LOG(LS_ERROR) << "Failed to generate random string!";
233 return false;
234 }
235 str->reserve(len);
236 for (size_t i = 0; i < len; ++i) {
237 str->push_back(table[bytes[i] % table_size]);
238 }
239 return true;
240}
241
242bool CreateRandomString(size_t len, std::string* str) {
243 return CreateRandomString(len, BASE64, 64, str);
244}
245
246bool CreateRandomString(size_t len, const std::string& table,
247 std::string* str) {
248 return CreateRandomString(len, table.c_str(),
249 static_cast<int>(table.size()), str);
250}
251
252uint32 CreateRandomId() {
253 uint32 id;
254 if (!Rng().Generate(&id, sizeof(id))) {
255 LOG(LS_ERROR) << "Failed to generate random id!";
256 }
257 return id;
258}
259
260uint64 CreateRandomId64() {
261 return static_cast<uint64>(CreateRandomId()) << 32 | CreateRandomId();
262}
263
264uint32 CreateRandomNonZeroId() {
265 uint32 id;
266 do {
267 id = CreateRandomId();
268 } while (id == 0);
269 return id;
270}
271
272double CreateRandomDouble() {
273 return CreateRandomId() / (std::numeric_limits<uint32>::max() +
274 std::numeric_limits<double>::epsilon());
275}
276
277} // namespace rtc