blob: 8b14cdfd6ba1b04fda690b1fc6e400128f3edbd1 [file] [log] [blame]
henrike@webrtc.org47be73b2014-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)
50// The OpenSSL RNG. Need to make sure it doesn't run out of entropy.
51class SecureRandomGenerator : public RandomGenerator {
52 public:
53 SecureRandomGenerator() : inited_(false) {
54 }
55 ~SecureRandomGenerator() {
56 }
57 virtual bool Init(const void* seed, size_t len) {
58 // By default, seed from the system state.
59 if (!inited_) {
60 if (RAND_poll() <= 0) {
61 return false;
62 }
63 inited_ = true;
64 }
65 // Allow app data to be mixed in, if provided.
66 if (seed) {
67 RAND_seed(seed, len);
68 }
69 return true;
70 }
71 virtual bool Generate(void* buf, size_t len) {
72 if (!inited_ && !Init(NULL, 0)) {
73 return false;
74 }
75 return (RAND_bytes(reinterpret_cast<unsigned char*>(buf), len) > 0);
76 }
77
78 private:
79 bool inited_;
80};
81
82#elif defined(SSL_USE_NSS_RNG)
83// The NSS RNG.
84class SecureRandomGenerator : public RandomGenerator {
85 public:
86 SecureRandomGenerator() {}
87 ~SecureRandomGenerator() {}
88 virtual bool Init(const void* seed, size_t len) {
89 return true;
90 }
91 virtual bool Generate(void* buf, size_t len) {
92 return (PK11_GenerateRandom(reinterpret_cast<unsigned char*>(buf),
93 static_cast<int>(len)) == SECSuccess);
94 }
95};
96
97#else
98#if defined(WEBRTC_WIN)
99class SecureRandomGenerator : public RandomGenerator {
100 public:
101 SecureRandomGenerator() : advapi32_(NULL), rtl_gen_random_(NULL) {}
102 ~SecureRandomGenerator() {
103 FreeLibrary(advapi32_);
104 }
105
106 virtual bool Init(const void* seed, size_t seed_len) {
107 // We don't do any additional seeding on Win32, we just use the CryptoAPI
108 // RNG (which is exposed as a hidden function off of ADVAPI32 so that we
109 // don't need to drag in all of CryptoAPI)
110 if (rtl_gen_random_) {
111 return true;
112 }
113
114 advapi32_ = LoadLibrary(L"advapi32.dll");
115 if (!advapi32_) {
116 return false;
117 }
118
119 rtl_gen_random_ = reinterpret_cast<RtlGenRandomProc>(
120 GetProcAddress(advapi32_, "SystemFunction036"));
121 if (!rtl_gen_random_) {
122 FreeLibrary(advapi32_);
123 return false;
124 }
125
126 return true;
127 }
128 virtual bool Generate(void* buf, size_t len) {
129 if (!rtl_gen_random_ && !Init(NULL, 0)) {
130 return false;
131 }
132 return (rtl_gen_random_(buf, static_cast<int>(len)) != FALSE);
133 }
134
135 private:
136 typedef BOOL (WINAPI *RtlGenRandomProc)(PVOID, ULONG);
137 HINSTANCE advapi32_;
138 RtlGenRandomProc rtl_gen_random_;
139};
140
141#elif !defined(FEATURE_ENABLE_SSL)
142
143// No SSL implementation -- use rand()
144class SecureRandomGenerator : public RandomGenerator {
145 public:
146 virtual bool Init(const void* seed, size_t len) {
147 if (len >= 4) {
148 srand(*reinterpret_cast<const int*>(seed));
149 } else {
150 srand(*reinterpret_cast<const char*>(seed));
151 }
152 return true;
153 }
154 virtual bool Generate(void* buf, size_t len) {
155 char* bytes = reinterpret_cast<char*>(buf);
156 for (size_t i = 0; i < len; ++i) {
157 bytes[i] = static_cast<char>(rand());
158 }
159 return true;
160 }
161};
162
163#else
164
165#error No SSL implementation has been selected!
166
167#endif // WEBRTC_WIN
168#endif
169
170// A test random generator, for predictable output.
171class TestRandomGenerator : public RandomGenerator {
172 public:
173 TestRandomGenerator() : seed_(7) {
174 }
175 ~TestRandomGenerator() {
176 }
177 virtual bool Init(const void* seed, size_t len) {
178 return true;
179 }
180 virtual bool Generate(void* buf, size_t len) {
181 for (size_t i = 0; i < len; ++i) {
182 static_cast<uint8*>(buf)[i] = static_cast<uint8>(GetRandom());
183 }
184 return true;
185 }
186
187 private:
188 int GetRandom() {
189 return ((seed_ = seed_ * 214013L + 2531011L) >> 16) & 0x7fff;
190 }
191 int seed_;
192};
193
194// TODO: Use Base64::Base64Table instead.
195static const char BASE64[64] = {
196 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
197 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
198 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
199 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
200 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
201};
202
203namespace {
204
205// This round about way of creating a global RNG is to safe-guard against
206// indeterminant static initialization order.
207scoped_ptr<RandomGenerator>& GetGlobalRng() {
208 LIBJINGLE_DEFINE_STATIC_LOCAL(scoped_ptr<RandomGenerator>, global_rng,
209 (new SecureRandomGenerator()));
210 return global_rng;
211}
212
213RandomGenerator& Rng() {
214 return *GetGlobalRng();
215}
216
217} // namespace
218
219void SetRandomTestMode(bool test) {
220 if (!test) {
221 GetGlobalRng().reset(new SecureRandomGenerator());
222 } else {
223 GetGlobalRng().reset(new TestRandomGenerator());
224 }
225}
226
227bool InitRandom(int seed) {
228 return InitRandom(reinterpret_cast<const char*>(&seed), sizeof(seed));
229}
230
231bool InitRandom(const char* seed, size_t len) {
232 if (!Rng().Init(seed, len)) {
233 LOG(LS_ERROR) << "Failed to init random generator!";
234 return false;
235 }
236 return true;
237}
238
239std::string CreateRandomString(size_t len) {
240 std::string str;
241 CreateRandomString(len, &str);
242 return str;
243}
244
245bool CreateRandomString(size_t len,
246 const char* table, int table_size,
247 std::string* str) {
248 str->clear();
249 scoped_ptr<uint8[]> bytes(new uint8[len]);
250 if (!Rng().Generate(bytes.get(), len)) {
251 LOG(LS_ERROR) << "Failed to generate random string!";
252 return false;
253 }
254 str->reserve(len);
255 for (size_t i = 0; i < len; ++i) {
256 str->push_back(table[bytes[i] % table_size]);
257 }
258 return true;
259}
260
261bool CreateRandomString(size_t len, std::string* str) {
262 return CreateRandomString(len, BASE64, 64, str);
263}
264
265bool CreateRandomString(size_t len, const std::string& table,
266 std::string* str) {
267 return CreateRandomString(len, table.c_str(),
268 static_cast<int>(table.size()), str);
269}
270
271uint32 CreateRandomId() {
272 uint32 id;
273 if (!Rng().Generate(&id, sizeof(id))) {
274 LOG(LS_ERROR) << "Failed to generate random id!";
275 }
276 return id;
277}
278
279uint64 CreateRandomId64() {
280 return static_cast<uint64>(CreateRandomId()) << 32 | CreateRandomId();
281}
282
283uint32 CreateRandomNonZeroId() {
284 uint32 id;
285 do {
286 id = CreateRandomId();
287 } while (id == 0);
288 return id;
289}
290
291double CreateRandomDouble() {
292 return CreateRandomId() / (std::numeric_limits<uint32>::max() +
293 std::numeric_limits<double>::epsilon());
294}
295
296} // namespace rtc