Home | History | Annotate | Download | only in base
      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:
     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:
     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.
     61 class 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)
     74 class 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()
    119 class 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.
    146 class 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 
    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.
    184 scoped_ptr<RandomGenerator>& GetGlobalRng() {
    185   RTC_DEFINE_STATIC_LOCAL(scoped_ptr<RandomGenerator>, global_rng,
    186                           (new SecureRandomGenerator()));
    187   return global_rng;
    188 }
    189 
    190 RandomGenerator& Rng() {
    191   return *GetGlobalRng();
    192 }
    193 
    194 }  // namespace
    195 
    196 void SetRandomTestMode(bool test) {
    197   if (!test) {
    198     GetGlobalRng().reset(new SecureRandomGenerator());
    199   } else {
    200     GetGlobalRng().reset(new TestRandomGenerator());
    201   }
    202 }
    203 
    204 bool InitRandom(int seed) {
    205   return InitRandom(reinterpret_cast<const char*>(&seed), sizeof(seed));
    206 }
    207 
    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 
    216 std::string CreateRandomString(size_t len) {
    217   std::string str;
    218   CreateRandomString(len, &str);
    219   return str;
    220 }
    221 
    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 
    238 bool CreateRandomString(size_t len, std::string* str) {
    239   return CreateRandomString(len, kBase64, 64, str);
    240 }
    241 
    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.
    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 
    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 
    291 uint64_t CreateRandomId64() {
    292   return static_cast<uint64_t>(CreateRandomId()) << 32 | CreateRandomId();
    293 }
    294 
    295 uint32_t CreateRandomNonZeroId() {
    296   uint32_t id;
    297   do {
    298     id = CreateRandomId();
    299   } while (id == 0);
    300   return id;
    301 }
    302 
    303 double CreateRandomDouble() {
    304   return CreateRandomId() / (std::numeric_limits<uint32_t>::max() +
    305                              std::numeric_limits<double>::epsilon());
    306 }
    307 
    308 }  // namespace rtc
    309