• 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 #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