• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #else
20 #if defined(WEBRTC_WIN)
21 #define WIN32_LEAN_AND_MEAN
22 #include <windows.h>
23 #include <ntsecapi.h>
24 #endif  // WEBRTC_WIN
25 #endif  // else
26 #endif  // FEATURE_ENABLED_SSL
27 
28 #include "webrtc/base/base64.h"
29 #include "webrtc/base/basictypes.h"
30 #include "webrtc/base/logging.h"
31 #include "webrtc/base/scoped_ptr.h"
32 #include "webrtc/base/timeutils.h"
33 
34 // Protect against max macro inclusion.
35 #undef max
36 
37 namespace rtc {
38 
39 // Base class for RNG implementations.
40 class RandomGenerator {
41  public:
~RandomGenerator()42   virtual ~RandomGenerator() {}
43   virtual bool Init(const void* seed, size_t len) = 0;
44   virtual bool Generate(void* buf, size_t len) = 0;
45 };
46 
47 #if defined(SSL_USE_OPENSSL)
48 // The OpenSSL RNG.
49 class SecureRandomGenerator : public RandomGenerator {
50  public:
SecureRandomGenerator()51   SecureRandomGenerator() {}
~SecureRandomGenerator()52   ~SecureRandomGenerator() override {}
Init(const void * seed,size_t len)53   bool Init(const void* seed, size_t len) override { return true; }
Generate(void * buf,size_t len)54   bool Generate(void* buf, size_t len) override {
55     return (RAND_bytes(reinterpret_cast<unsigned char*>(buf), len) > 0);
56   }
57 };
58 
59 #elif defined(SSL_USE_NSS_RNG)
60 // The NSS RNG.
61 class SecureRandomGenerator : public RandomGenerator {
62  public:
SecureRandomGenerator()63   SecureRandomGenerator() {}
~SecureRandomGenerator()64   ~SecureRandomGenerator() override {}
Init(const void * seed,size_t len)65   bool Init(const void* seed, size_t len) override { return true; }
Generate(void * buf,size_t len)66   bool Generate(void* buf, size_t len) override {
67     return (PK11_GenerateRandom(reinterpret_cast<unsigned char*>(buf),
68                                 static_cast<int>(len)) == SECSuccess);
69   }
70 };
71 
72 #else
73 #if defined(WEBRTC_WIN)
74 class SecureRandomGenerator : public RandomGenerator {
75  public:
SecureRandomGenerator()76   SecureRandomGenerator() : advapi32_(NULL), rtl_gen_random_(NULL) {}
~SecureRandomGenerator()77   ~SecureRandomGenerator() {
78     FreeLibrary(advapi32_);
79   }
80 
Init(const void * seed,size_t seed_len)81   virtual bool Init(const void* seed, size_t seed_len) {
82     // We don't do any additional seeding on Win32, we just use the CryptoAPI
83     // RNG (which is exposed as a hidden function off of ADVAPI32 so that we
84     // don't need to drag in all of CryptoAPI)
85     if (rtl_gen_random_) {
86       return true;
87     }
88 
89     advapi32_ = LoadLibrary(L"advapi32.dll");
90     if (!advapi32_) {
91       return false;
92     }
93 
94     rtl_gen_random_ = reinterpret_cast<RtlGenRandomProc>(
95         GetProcAddress(advapi32_, "SystemFunction036"));
96     if (!rtl_gen_random_) {
97       FreeLibrary(advapi32_);
98       return false;
99     }
100 
101     return true;
102   }
Generate(void * buf,size_t len)103   virtual bool Generate(void* buf, size_t len) {
104     if (!rtl_gen_random_ && !Init(NULL, 0)) {
105       return false;
106     }
107     return (rtl_gen_random_(buf, static_cast<int>(len)) != FALSE);
108   }
109 
110  private:
111   typedef BOOL (WINAPI *RtlGenRandomProc)(PVOID, ULONG);
112   HINSTANCE advapi32_;
113   RtlGenRandomProc rtl_gen_random_;
114 };
115 
116 #elif !defined(FEATURE_ENABLE_SSL)
117 
118 // No SSL implementation -- use rand()
119 class SecureRandomGenerator : public RandomGenerator {
120  public:
Init(const void * seed,size_t len)121   virtual bool Init(const void* seed, size_t len) {
122     if (len >= 4) {
123       srand(*reinterpret_cast<const int*>(seed));
124     } else {
125       srand(*reinterpret_cast<const char*>(seed));
126     }
127     return true;
128   }
Generate(void * buf,size_t len)129   virtual bool Generate(void* buf, size_t len) {
130     char* bytes = reinterpret_cast<char*>(buf);
131     for (size_t i = 0; i < len; ++i) {
132       bytes[i] = static_cast<char>(rand());
133     }
134     return true;
135   }
136 };
137 
138 #else
139 
140 #error No SSL implementation has been selected!
141 
142 #endif  // WEBRTC_WIN
143 #endif
144 
145 // A test random generator, for predictable output.
146 class TestRandomGenerator : public RandomGenerator {
147  public:
TestRandomGenerator()148   TestRandomGenerator() : seed_(7) {
149   }
~TestRandomGenerator()150   ~TestRandomGenerator() override {
151   }
Init(const void * seed,size_t len)152   bool Init(const void* seed, size_t len) override { return true; }
Generate(void * buf,size_t len)153   bool Generate(void* buf, size_t len) override {
154     for (size_t i = 0; i < len; ++i) {
155       static_cast<uint8_t*>(buf)[i] = static_cast<uint8_t>(GetRandom());
156     }
157     return true;
158   }
159 
160  private:
GetRandom()161   int GetRandom() {
162     return ((seed_ = seed_ * 214013L + 2531011L) >> 16) & 0x7fff;
163   }
164   int seed_;
165 };
166 
167 namespace {
168 
169 // TODO: Use Base64::Base64Table instead.
170 static const char kBase64[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 static const char kHex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
178                               '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
179 
180 static const char kUuidDigit17[4] = {'8', '9', 'a', 'b'};
181 
182 // This round about way of creating a global RNG is to safe-guard against
183 // indeterminant static initialization order.
GetGlobalRng()184 scoped_ptr<RandomGenerator>& GetGlobalRng() {
185   RTC_DEFINE_STATIC_LOCAL(scoped_ptr<RandomGenerator>, global_rng,
186                           (new SecureRandomGenerator()));
187   return global_rng;
188 }
189 
Rng()190 RandomGenerator& Rng() {
191   return *GetGlobalRng();
192 }
193 
194 }  // namespace
195 
SetRandomTestMode(bool test)196 void SetRandomTestMode(bool test) {
197   if (!test) {
198     GetGlobalRng().reset(new SecureRandomGenerator());
199   } else {
200     GetGlobalRng().reset(new TestRandomGenerator());
201   }
202 }
203 
InitRandom(int seed)204 bool InitRandom(int seed) {
205   return InitRandom(reinterpret_cast<const char*>(&seed), sizeof(seed));
206 }
207 
InitRandom(const char * seed,size_t len)208 bool InitRandom(const char* seed, size_t len) {
209   if (!Rng().Init(seed, len)) {
210     LOG(LS_ERROR) << "Failed to init random generator!";
211     return false;
212   }
213   return true;
214 }
215 
CreateRandomString(size_t len)216 std::string CreateRandomString(size_t len) {
217   std::string str;
218   CreateRandomString(len, &str);
219   return str;
220 }
221 
CreateRandomString(size_t len,const char * table,int table_size,std::string * str)222 bool CreateRandomString(size_t len,
223                         const char* table, int table_size,
224                         std::string* str) {
225   str->clear();
226   scoped_ptr<uint8_t[]> bytes(new uint8_t[len]);
227   if (!Rng().Generate(bytes.get(), len)) {
228     LOG(LS_ERROR) << "Failed to generate random string!";
229     return false;
230   }
231   str->reserve(len);
232   for (size_t i = 0; i < len; ++i) {
233     str->push_back(table[bytes[i] % table_size]);
234   }
235   return true;
236 }
237 
CreateRandomString(size_t len,std::string * str)238 bool CreateRandomString(size_t len, std::string* str) {
239   return CreateRandomString(len, kBase64, 64, str);
240 }
241 
CreateRandomString(size_t len,const std::string & table,std::string * str)242 bool CreateRandomString(size_t len, const std::string& table,
243                         std::string* str) {
244   return CreateRandomString(len, table.c_str(),
245                             static_cast<int>(table.size()), str);
246 }
247 
248 // Version 4 UUID is of the form:
249 // xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
250 // Where 'x' is a hex digit, and 'y' is 8, 9, a or b.
CreateRandomUuid()251 std::string CreateRandomUuid() {
252   std::string str;
253   scoped_ptr<uint8_t[]> bytes(new uint8_t[31]);
254   if (!Rng().Generate(bytes.get(), 31)) {
255     LOG(LS_ERROR) << "Failed to generate random string!";
256     return str;
257   }
258   str.reserve(36);
259   for (size_t i = 0; i < 8; ++i) {
260     str.push_back(kHex[bytes[i] % 16]);
261   }
262   str.push_back('-');
263   for (size_t i = 8; i < 12; ++i) {
264     str.push_back(kHex[bytes[i] % 16]);
265   }
266   str.push_back('-');
267   str.push_back('4');
268   for (size_t i = 12; i < 15; ++i) {
269     str.push_back(kHex[bytes[i] % 16]);
270   }
271   str.push_back('-');
272   str.push_back(kUuidDigit17[bytes[15] % 4]);
273   for (size_t i = 16; i < 19; ++i) {
274     str.push_back(kHex[bytes[i] % 16]);
275   }
276   str.push_back('-');
277   for (size_t i = 19; i < 31; ++i) {
278     str.push_back(kHex[bytes[i] % 16]);
279   }
280   return str;
281 }
282 
CreateRandomId()283 uint32_t CreateRandomId() {
284   uint32_t id;
285   if (!Rng().Generate(&id, sizeof(id))) {
286     LOG(LS_ERROR) << "Failed to generate random id!";
287   }
288   return id;
289 }
290 
CreateRandomId64()291 uint64_t CreateRandomId64() {
292   return static_cast<uint64_t>(CreateRandomId()) << 32 | CreateRandomId();
293 }
294 
CreateRandomNonZeroId()295 uint32_t CreateRandomNonZeroId() {
296   uint32_t id;
297   do {
298     id = CreateRandomId();
299   } while (id == 0);
300   return id;
301 }
302 
CreateRandomDouble()303 double CreateRandomDouble() {
304   return CreateRandomId() / (std::numeric_limits<uint32_t>::max() +
305                              std::numeric_limits<double>::epsilon());
306 }
307 
308 }  // namespace rtc
309