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 #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:
     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:
     53   SecureRandomGenerator() : inited_(false) {
     54   }
     55   ~SecureRandomGenerator() {
     56   }
     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   }
     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:
     86   SecureRandomGenerator() {}
     87   ~SecureRandomGenerator() {}
     88   virtual bool Init(const void* seed, size_t len) {
     89     return true;
     90   }
     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:
    101   SecureRandomGenerator() : advapi32_(NULL), rtl_gen_random_(NULL) {}
    102   ~SecureRandomGenerator() {
    103     FreeLibrary(advapi32_);
    104   }
    105 
    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   }
    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:
    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   }
    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:
    173   TestRandomGenerator() : seed_(7) {
    174   }
    175   ~TestRandomGenerator() {
    176   }
    177   virtual bool Init(const void* seed, size_t len) {
    178     return true;
    179   }
    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:
    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.
    207 scoped_ptr<RandomGenerator>& GetGlobalRng() {
    208   LIBJINGLE_DEFINE_STATIC_LOCAL(scoped_ptr<RandomGenerator>, global_rng,
    209                                 (new SecureRandomGenerator()));
    210   return global_rng;
    211 }
    212 
    213 RandomGenerator& Rng() {
    214   return *GetGlobalRng();
    215 }
    216 
    217 }  // namespace
    218 
    219 void SetRandomTestMode(bool test) {
    220   if (!test) {
    221     GetGlobalRng().reset(new SecureRandomGenerator());
    222   } else {
    223     GetGlobalRng().reset(new TestRandomGenerator());
    224   }
    225 }
    226 
    227 bool InitRandom(int seed) {
    228   return InitRandom(reinterpret_cast<const char*>(&seed), sizeof(seed));
    229 }
    230 
    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 
    239 std::string CreateRandomString(size_t len) {
    240   std::string str;
    241   CreateRandomString(len, &str);
    242   return str;
    243 }
    244 
    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 
    261 bool CreateRandomString(size_t len, std::string* str) {
    262   return CreateRandomString(len, BASE64, 64, str);
    263 }
    264 
    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 
    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 
    279 uint64 CreateRandomId64() {
    280   return static_cast<uint64>(CreateRandomId()) << 32 | CreateRandomId();
    281 }
    282 
    283 uint32 CreateRandomNonZeroId() {
    284   uint32 id;
    285   do {
    286     id = CreateRandomId();
    287   } while (id == 0);
    288   return id;
    289 }
    290 
    291 double CreateRandomDouble() {
    292   return CreateRandomId() / (std::numeric_limits<uint32>::max() +
    293       std::numeric_limits<double>::epsilon());
    294 }
    295 
    296 }  // namespace rtc
    297