blob: bd7ff96ac4fd2a46ca74a242fd98b04a5c832196 [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() {}
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000054 ~SecureRandomGenerator() override {}
55 bool Init(const void* seed, size_t len) override { return true; }
56 bool Generate(void* buf, size_t len) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000057 return (RAND_bytes(reinterpret_cast<unsigned char*>(buf), len) > 0);
58 }
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000059};
60
61#elif defined(SSL_USE_NSS_RNG)
62// The NSS RNG.
63class SecureRandomGenerator : public RandomGenerator {
64 public:
65 SecureRandomGenerator() {}
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +000066 ~SecureRandomGenerator() override {}
67 bool Init(const void* seed, size_t len) override { return true; }
68 bool Generate(void* buf, size_t len) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +000069 return (PK11_GenerateRandom(reinterpret_cast<unsigned char*>(buf),
70 static_cast<int>(len)) == SECSuccess);
71 }
72};
73
74#else
75#if defined(WEBRTC_WIN)
76class SecureRandomGenerator : public RandomGenerator {
77 public:
78 SecureRandomGenerator() : advapi32_(NULL), rtl_gen_random_(NULL) {}
79 ~SecureRandomGenerator() {
80 FreeLibrary(advapi32_);
81 }
82
83 virtual bool Init(const void* seed, size_t seed_len) {
84 // We don't do any additional seeding on Win32, we just use the CryptoAPI
85 // RNG (which is exposed as a hidden function off of ADVAPI32 so that we
86 // don't need to drag in all of CryptoAPI)
87 if (rtl_gen_random_) {
88 return true;
89 }
90
91 advapi32_ = LoadLibrary(L"advapi32.dll");
92 if (!advapi32_) {
93 return false;
94 }
95
96 rtl_gen_random_ = reinterpret_cast<RtlGenRandomProc>(
97 GetProcAddress(advapi32_, "SystemFunction036"));
98 if (!rtl_gen_random_) {
99 FreeLibrary(advapi32_);
100 return false;
101 }
102
103 return true;
104 }
105 virtual bool Generate(void* buf, size_t len) {
106 if (!rtl_gen_random_ && !Init(NULL, 0)) {
107 return false;
108 }
109 return (rtl_gen_random_(buf, static_cast<int>(len)) != FALSE);
110 }
111
112 private:
113 typedef BOOL (WINAPI *RtlGenRandomProc)(PVOID, ULONG);
114 HINSTANCE advapi32_;
115 RtlGenRandomProc rtl_gen_random_;
116};
117
118#elif !defined(FEATURE_ENABLE_SSL)
119
120// No SSL implementation -- use rand()
121class SecureRandomGenerator : public RandomGenerator {
122 public:
123 virtual bool Init(const void* seed, size_t len) {
124 if (len >= 4) {
125 srand(*reinterpret_cast<const int*>(seed));
126 } else {
127 srand(*reinterpret_cast<const char*>(seed));
128 }
129 return true;
130 }
131 virtual bool Generate(void* buf, size_t len) {
132 char* bytes = reinterpret_cast<char*>(buf);
133 for (size_t i = 0; i < len; ++i) {
134 bytes[i] = static_cast<char>(rand());
135 }
136 return true;
137 }
138};
139
140#else
141
142#error No SSL implementation has been selected!
143
144#endif // WEBRTC_WIN
145#endif
146
147// A test random generator, for predictable output.
148class TestRandomGenerator : public RandomGenerator {
149 public:
150 TestRandomGenerator() : seed_(7) {
151 }
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000152 ~TestRandomGenerator() override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000153 }
kwiberg@webrtc.org67186fe2015-03-09 22:21:53 +0000154 bool Init(const void* seed, size_t len) override { return true; }
155 bool Generate(void* buf, size_t len) override {
henrike@webrtc.orgf0488722014-05-13 18:00:26 +0000156 for (size_t i = 0; i < len; ++i) {
157 static_cast<uint8*>(buf)[i] = static_cast<uint8>(GetRandom());
158 }
159 return true;
160 }
161
162 private:
163 int GetRandom() {
164 return ((seed_ = seed_ * 214013L + 2531011L) >> 16) & 0x7fff;
165 }
166 int seed_;
167};
168
169// TODO: Use Base64::Base64Table instead.
170static const char BASE64[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};
177
178namespace {
179
180// This round about way of creating a global RNG is to safe-guard against
181// indeterminant static initialization order.
182scoped_ptr<RandomGenerator>& GetGlobalRng() {
183 LIBJINGLE_DEFINE_STATIC_LOCAL(scoped_ptr<RandomGenerator>, global_rng,
184 (new SecureRandomGenerator()));
185 return global_rng;
186}
187
188RandomGenerator& Rng() {
189 return *GetGlobalRng();
190}
191
192} // namespace
193
194void SetRandomTestMode(bool test) {
195 if (!test) {
196 GetGlobalRng().reset(new SecureRandomGenerator());
197 } else {
198 GetGlobalRng().reset(new TestRandomGenerator());
199 }
200}
201
202bool InitRandom(int seed) {
203 return InitRandom(reinterpret_cast<const char*>(&seed), sizeof(seed));
204}
205
206bool InitRandom(const char* seed, size_t len) {
207 if (!Rng().Init(seed, len)) {
208 LOG(LS_ERROR) << "Failed to init random generator!";
209 return false;
210 }
211 return true;
212}
213
214std::string CreateRandomString(size_t len) {
215 std::string str;
216 CreateRandomString(len, &str);
217 return str;
218}
219
220bool CreateRandomString(size_t len,
221 const char* table, int table_size,
222 std::string* str) {
223 str->clear();
224 scoped_ptr<uint8[]> bytes(new uint8[len]);
225 if (!Rng().Generate(bytes.get(), len)) {
226 LOG(LS_ERROR) << "Failed to generate random string!";
227 return false;
228 }
229 str->reserve(len);
230 for (size_t i = 0; i < len; ++i) {
231 str->push_back(table[bytes[i] % table_size]);
232 }
233 return true;
234}
235
236bool CreateRandomString(size_t len, std::string* str) {
237 return CreateRandomString(len, BASE64, 64, str);
238}
239
240bool CreateRandomString(size_t len, const std::string& table,
241 std::string* str) {
242 return CreateRandomString(len, table.c_str(),
243 static_cast<int>(table.size()), str);
244}
245
246uint32 CreateRandomId() {
247 uint32 id;
248 if (!Rng().Generate(&id, sizeof(id))) {
249 LOG(LS_ERROR) << "Failed to generate random id!";
250 }
251 return id;
252}
253
254uint64 CreateRandomId64() {
255 return static_cast<uint64>(CreateRandomId()) << 32 | CreateRandomId();
256}
257
258uint32 CreateRandomNonZeroId() {
259 uint32 id;
260 do {
261 id = CreateRandomId();
262 } while (id == 0);
263 return id;
264}
265
266double CreateRandomDouble() {
267 return CreateRandomId() / (std::numeric_limits<uint32>::max() +
268 std::numeric_limits<double>::epsilon());
269}
270
271} // namespace rtc