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
37namespace rtc {
38
39// Base class for RNG implementations.
40class RandomGenerator {
41 public:
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.
49class SecureRandomGenerator : public RandomGenerator {
50 public:
51  SecureRandomGenerator() {}
52  ~SecureRandomGenerator() override {}
53  bool Init(const void* seed, size_t len) override { return true; }
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.
61class SecureRandomGenerator : public RandomGenerator {
62 public:
63  SecureRandomGenerator() {}
64  ~SecureRandomGenerator() override {}
65  bool Init(const void* seed, size_t len) override { return true; }
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)
74class SecureRandomGenerator : public RandomGenerator {
75 public:
76  SecureRandomGenerator() : advapi32_(NULL), rtl_gen_random_(NULL) {}
77  ~SecureRandomGenerator() {
78    FreeLibrary(advapi32_);
79  }
80
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  }
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()
119class SecureRandomGenerator : public RandomGenerator {
120 public:
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  }
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.
146class TestRandomGenerator : public RandomGenerator {
147 public:
148  TestRandomGenerator() : seed_(7) {
149  }
150  ~TestRandomGenerator() override {
151  }
152  bool Init(const void* seed, size_t len) override { return true; }
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:
161  int GetRandom() {
162    return ((seed_ = seed_ * 214013L + 2531011L) >> 16) & 0x7fff;
163  }
164  int seed_;
165};
166
167namespace {
168
169// TODO: Use Base64::Base64Table instead.
170static 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
177static const char kHex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
178                              '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
179
180static 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.
184scoped_ptr<RandomGenerator>& GetGlobalRng() {
185  RTC_DEFINE_STATIC_LOCAL(scoped_ptr<RandomGenerator>, global_rng,
186                          (new SecureRandomGenerator()));
187  return global_rng;
188}
189
190RandomGenerator& Rng() {
191  return *GetGlobalRng();
192}
193
194}  // namespace
195
196void SetRandomTestMode(bool test) {
197  if (!test) {
198    GetGlobalRng().reset(new SecureRandomGenerator());
199  } else {
200    GetGlobalRng().reset(new TestRandomGenerator());
201  }
202}
203
204bool InitRandom(int seed) {
205  return InitRandom(reinterpret_cast<const char*>(&seed), sizeof(seed));
206}
207
208bool 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
216std::string CreateRandomString(size_t len) {
217  std::string str;
218  CreateRandomString(len, &str);
219  return str;
220}
221
222bool 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
238bool CreateRandomString(size_t len, std::string* str) {
239  return CreateRandomString(len, kBase64, 64, str);
240}
241
242bool 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.
251std::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
283uint32_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
291uint64_t CreateRandomId64() {
292  return static_cast<uint64_t>(CreateRandomId()) << 32 | CreateRandomId();
293}
294
295uint32_t CreateRandomNonZeroId() {
296  uint32_t id;
297  do {
298    id = CreateRandomId();
299  } while (id == 0);
300  return id;
301}
302
303double CreateRandomDouble() {
304  return CreateRandomId() / (std::numeric_limits<uint32_t>::max() +
305                             std::numeric_limits<double>::epsilon());
306}
307
308}  // namespace rtc
309