blob: 84d1c93b37bc470fca0e32d2db3d3958145545fb [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)
20#include "pk11func.h"
21#else
22#if defined(WEBRTC_WIN)
23#define WIN32_LEAN_AND_MEAN
24#include <windows.h>
25#include <ntsecapi.h>
26#endif // WEBRTC_WIN
27#endif // else
28#endif // FEATURE_ENABLED_SSL
29
30#include "webrtc/base/base64.h"
31#include "webrtc/base/basictypes.h"
32#include "webrtc/base/logging.h"
33#include "webrtc/base/scoped_ptr.h"
34#include "webrtc/base/timeutils.h"
35
36// Protect against max macro inclusion.
37#undef max
38
39namespace rtc {
40
41// Base class for RNG implementations.
42class RandomGenerator {
43 public:
44 virtual ~RandomGenerator() {}
45 virtual bool Init(const void* seed, size_t len) = 0;
46 virtual bool Generate(void* buf, size_t len) = 0;
47};
48
49#if defined(SSL_USE_OPENSSL)
henrike@webrtc.orgd89b69a2014-11-06 17:23:09 +000050// The OpenSSL RNG.
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000051class SecureRandomGenerator : public RandomGenerator {
52 public:
henrike@webrtc.orgd89b69a2014-11-06 17:23:09 +000053 SecureRandomGenerator() {}
54 ~SecureRandomGenerator() {}
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000055 virtual bool Init(const void* seed, size_t len) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000056 return true;
57 }
58 virtual bool Generate(void* buf, size_t len) {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000059 return (RAND_bytes(reinterpret_cast<unsigned char*>(buf), len) > 0);
60 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000061};
62
63#elif defined(SSL_USE_NSS_RNG)
64// The NSS RNG.
65class SecureRandomGenerator : public RandomGenerator {
66 public:
67 SecureRandomGenerator() {}
68 ~SecureRandomGenerator() {}
69 virtual bool Init(const void* seed, size_t len) {
70 return true;
71 }
72 virtual bool Generate(void* buf, size_t len) {
73 return (PK11_GenerateRandom(reinterpret_cast<unsigned char*>(buf),
74 static_cast<int>(len)) == SECSuccess);
75 }
76};
77
78#else
79#if defined(WEBRTC_WIN)
80class SecureRandomGenerator : public RandomGenerator {
81 public:
82 SecureRandomGenerator() : advapi32_(NULL), rtl_gen_random_(NULL) {}
83 ~SecureRandomGenerator() {
84 FreeLibrary(advapi32_);
85 }
86
87 virtual bool Init(const void* seed, size_t seed_len) {
88 // We don't do any additional seeding on Win32, we just use the CryptoAPI
89 // RNG (which is exposed as a hidden function off of ADVAPI32 so that we
90 // don't need to drag in all of CryptoAPI)
91 if (rtl_gen_random_) {
92 return true;
93 }
94
95 advapi32_ = LoadLibrary(L"advapi32.dll");
96 if (!advapi32_) {
97 return false;
98 }
99
100 rtl_gen_random_ = reinterpret_cast<RtlGenRandomProc>(
101 GetProcAddress(advapi32_, "SystemFunction036"));
102 if (!rtl_gen_random_) {
103 FreeLibrary(advapi32_);
104 return false;
105 }
106
107 return true;
108 }
109 virtual bool Generate(void* buf, size_t len) {
110 if (!rtl_gen_random_ && !Init(NULL, 0)) {
111 return false;
112 }
113 return (rtl_gen_random_(buf, static_cast<int>(len)) != FALSE);
114 }
115
116 private:
117 typedef BOOL (WINAPI *RtlGenRandomProc)(PVOID, ULONG);
118 HINSTANCE advapi32_;
119 RtlGenRandomProc rtl_gen_random_;
120};
121
122#elif !defined(FEATURE_ENABLE_SSL)
123
124// No SSL implementation -- use rand()
125class SecureRandomGenerator : public RandomGenerator {
126 public:
127 virtual bool Init(const void* seed, size_t len) {
128 if (len >= 4) {
129 srand(*reinterpret_cast<const int*>(seed));
130 } else {
131 srand(*reinterpret_cast<const char*>(seed));
132 }
133 return true;
134 }
135 virtual bool Generate(void* buf, size_t len) {
136 char* bytes = reinterpret_cast<char*>(buf);
137 for (size_t i = 0; i < len; ++i) {
138 bytes[i] = static_cast<char>(rand());
139 }
140 return true;
141 }
142};
143
144#else
145
146#error No SSL implementation has been selected!
147
148#endif // WEBRTC_WIN
149#endif
150
151// A test random generator, for predictable output.
152class TestRandomGenerator : public RandomGenerator {
153 public:
154 TestRandomGenerator() : seed_(7) {
155 }
156 ~TestRandomGenerator() {
157 }
158 virtual bool Init(const void* seed, size_t len) {
159 return true;
160 }
161 virtual bool Generate(void* buf, size_t len) {
162 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() {
189 LIBJINGLE_DEFINE_STATIC_LOCAL(scoped_ptr<RandomGenerator>, global_rng,
190 (new SecureRandomGenerator()));
191 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