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.
51 class SecureRandomGenerator : public RandomGenerator {
52 public:
SecureRandomGenerator()53 SecureRandomGenerator() {}
~SecureRandomGenerator()54 ~SecureRandomGenerator() override {}
Init(const void * seed,size_t len)55 bool Init(const void* seed, size_t len) override { return true; }
Generate(void * buf,size_t len)56 bool Generate(void* buf, size_t len) override {
57 return (RAND_bytes(reinterpret_cast<unsigned char*>(buf), len) > 0);
58 }
59 };
60
61 #elif defined(SSL_USE_NSS_RNG)
62 // The NSS RNG.
63 class SecureRandomGenerator : public RandomGenerator {
64 public:
SecureRandomGenerator()65 SecureRandomGenerator() {}
~SecureRandomGenerator()66 ~SecureRandomGenerator() override {}
Init(const void * seed,size_t len)67 bool Init(const void* seed, size_t len) override { return true; }
Generate(void * buf,size_t len)68 bool Generate(void* buf, size_t len) override {
69 return (PK11_GenerateRandom(reinterpret_cast<unsigned char*>(buf),
70 static_cast<int>(len)) == SECSuccess);
71 }
72 };
73
74 #else
75 #if defined(WEBRTC_WIN)
76 class SecureRandomGenerator : public RandomGenerator {
77 public:
SecureRandomGenerator()78 SecureRandomGenerator() : advapi32_(NULL), rtl_gen_random_(NULL) {}
~SecureRandomGenerator()79 ~SecureRandomGenerator() {
80 FreeLibrary(advapi32_);
81 }
82
Init(const void * seed,size_t seed_len)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 }
Generate(void * buf,size_t len)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()
121 class SecureRandomGenerator : public RandomGenerator {
122 public:
Init(const void * seed,size_t len)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 }
Generate(void * buf,size_t len)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.
148 class TestRandomGenerator : public RandomGenerator {
149 public:
TestRandomGenerator()150 TestRandomGenerator() : seed_(7) {
151 }
~TestRandomGenerator()152 ~TestRandomGenerator() override {
153 }
Init(const void * seed,size_t len)154 bool Init(const void* seed, size_t len) override { return true; }
Generate(void * buf,size_t len)155 bool Generate(void* buf, size_t len) override {
156 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:
GetRandom()163 int GetRandom() {
164 return ((seed_ = seed_ * 214013L + 2531011L) >> 16) & 0x7fff;
165 }
166 int seed_;
167 };
168
169 // TODO: Use Base64::Base64Table instead.
170 static 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
178 namespace {
179
180 // This round about way of creating a global RNG is to safe-guard against
181 // indeterminant static initialization order.
GetGlobalRng()182 scoped_ptr<RandomGenerator>& GetGlobalRng() {
183 LIBJINGLE_DEFINE_STATIC_LOCAL(scoped_ptr<RandomGenerator>, global_rng,
184 (new SecureRandomGenerator()));
185 return global_rng;
186 }
187
Rng()188 RandomGenerator& Rng() {
189 return *GetGlobalRng();
190 }
191
192 } // namespace
193
SetRandomTestMode(bool test)194 void SetRandomTestMode(bool test) {
195 if (!test) {
196 GetGlobalRng().reset(new SecureRandomGenerator());
197 } else {
198 GetGlobalRng().reset(new TestRandomGenerator());
199 }
200 }
201
InitRandom(int seed)202 bool InitRandom(int seed) {
203 return InitRandom(reinterpret_cast<const char*>(&seed), sizeof(seed));
204 }
205
InitRandom(const char * seed,size_t len)206 bool 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
CreateRandomString(size_t len)214 std::string CreateRandomString(size_t len) {
215 std::string str;
216 CreateRandomString(len, &str);
217 return str;
218 }
219
CreateRandomString(size_t len,const char * table,int table_size,std::string * str)220 bool 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
CreateRandomString(size_t len,std::string * str)236 bool CreateRandomString(size_t len, std::string* str) {
237 return CreateRandomString(len, BASE64, 64, str);
238 }
239
CreateRandomString(size_t len,const std::string & table,std::string * str)240 bool 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
CreateRandomId()246 uint32 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
CreateRandomId64()254 uint64 CreateRandomId64() {
255 return static_cast<uint64>(CreateRandomId()) << 32 | CreateRandomId();
256 }
257
CreateRandomNonZeroId()258 uint32 CreateRandomNonZeroId() {
259 uint32 id;
260 do {
261 id = CreateRandomId();
262 } while (id == 0);
263 return id;
264 }
265
CreateRandomDouble()266 double CreateRandomDouble() {
267 return CreateRandomId() / (std::numeric_limits<uint32>::max() +
268 std::numeric_limits<double>::epsilon());
269 }
270
271 } // namespace rtc
272