1 /*
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
39 namespace rtc {
40
41 // Base class for RNG implementations.
42 class RandomGenerator {
43 public:
~RandomGenerator()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.
51 class SecureRandomGenerator : public RandomGenerator {
52 public:
SecureRandomGenerator()53 SecureRandomGenerator() : inited_(false) {
54 }
~SecureRandomGenerator()55 ~SecureRandomGenerator() {
56 }
Init(const void * seed,size_t len)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 }
Generate(void * buf,size_t len)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.
84 class SecureRandomGenerator : public RandomGenerator {
85 public:
SecureRandomGenerator()86 SecureRandomGenerator() {}
~SecureRandomGenerator()87 ~SecureRandomGenerator() {}
Init(const void * seed,size_t len)88 virtual bool Init(const void* seed, size_t len) {
89 return true;
90 }
Generate(void * buf,size_t len)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)
99 class SecureRandomGenerator : public RandomGenerator {
100 public:
SecureRandomGenerator()101 SecureRandomGenerator() : advapi32_(NULL), rtl_gen_random_(NULL) {}
~SecureRandomGenerator()102 ~SecureRandomGenerator() {
103 FreeLibrary(advapi32_);
104 }
105
Init(const void * seed,size_t seed_len)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 }
Generate(void * buf,size_t len)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()
144 class SecureRandomGenerator : public RandomGenerator {
145 public:
Init(const void * seed,size_t len)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 }
Generate(void * buf,size_t len)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.
171 class TestRandomGenerator : public RandomGenerator {
172 public:
TestRandomGenerator()173 TestRandomGenerator() : seed_(7) {
174 }
~TestRandomGenerator()175 ~TestRandomGenerator() {
176 }
Init(const void * seed,size_t len)177 virtual bool Init(const void* seed, size_t len) {
178 return true;
179 }
Generate(void * buf,size_t len)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:
GetRandom()188 int GetRandom() {
189 return ((seed_ = seed_ * 214013L + 2531011L) >> 16) & 0x7fff;
190 }
191 int seed_;
192 };
193
194 // TODO: Use Base64::Base64Table instead.
195 static 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
203 namespace {
204
205 // This round about way of creating a global RNG is to safe-guard against
206 // indeterminant static initialization order.
GetGlobalRng()207 scoped_ptr<RandomGenerator>& GetGlobalRng() {
208 LIBJINGLE_DEFINE_STATIC_LOCAL(scoped_ptr<RandomGenerator>, global_rng,
209 (new SecureRandomGenerator()));
210 return global_rng;
211 }
212
Rng()213 RandomGenerator& Rng() {
214 return *GetGlobalRng();
215 }
216
217 } // namespace
218
SetRandomTestMode(bool test)219 void SetRandomTestMode(bool test) {
220 if (!test) {
221 GetGlobalRng().reset(new SecureRandomGenerator());
222 } else {
223 GetGlobalRng().reset(new TestRandomGenerator());
224 }
225 }
226
InitRandom(int seed)227 bool InitRandom(int seed) {
228 return InitRandom(reinterpret_cast<const char*>(&seed), sizeof(seed));
229 }
230
InitRandom(const char * seed,size_t len)231 bool 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
CreateRandomString(size_t len)239 std::string CreateRandomString(size_t len) {
240 std::string str;
241 CreateRandomString(len, &str);
242 return str;
243 }
244
CreateRandomString(size_t len,const char * table,int table_size,std::string * str)245 bool 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
CreateRandomString(size_t len,std::string * str)261 bool CreateRandomString(size_t len, std::string* str) {
262 return CreateRandomString(len, BASE64, 64, str);
263 }
264
CreateRandomString(size_t len,const std::string & table,std::string * str)265 bool 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
CreateRandomId()271 uint32 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
CreateRandomId64()279 uint64 CreateRandomId64() {
280 return static_cast<uint64>(CreateRandomId()) << 32 | CreateRandomId();
281 }
282
CreateRandomNonZeroId()283 uint32 CreateRandomNonZeroId() {
284 uint32 id;
285 do {
286 id = CreateRandomId();
287 } while (id == 0);
288 return id;
289 }
290
CreateRandomDouble()291 double CreateRandomDouble() {
292 return CreateRandomId() / (std::numeric_limits<uint32>::max() +
293 std::numeric_limits<double>::epsilon());
294 }
295
296 } // namespace rtc
297