Home | History | Annotate | Download | only in base
      1 /*
      2  * libjingle
      3  * Copyright 2004--2005, Google Inc.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *
      8  *  1. Redistributions of source code must retain the above copyright notice,
      9  *     this list of conditions and the following disclaimer.
     10  *  2. Redistributions in binary form must reproduce the above copyright notice,
     11  *     this list of conditions and the following disclaimer in the documentation
     12  *     and/or other materials provided with the distribution.
     13  *  3. The name of the author may not be used to endorse or promote products
     14  *     derived from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
     19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include "talk/base/helpers.h"
     29 
     30 #include <limits>
     31 
     32 #if defined(FEATURE_ENABLE_SSL)
     33 #include "talk/base/sslconfig.h"
     34 #if defined(SSL_USE_OPENSSL)
     35 #include <openssl/rand.h>
     36 #elif defined(SSL_USE_NSS_RNG)
     37 #include "pk11func.h"
     38 #else
     39 #ifdef WIN32
     40 #define WIN32_LEAN_AND_MEAN
     41 #include <windows.h>
     42 #include <ntsecapi.h>
     43 #endif  // WIN32
     44 #endif  // else
     45 #endif  // FEATURE_ENABLED_SSL
     46 
     47 #include "talk/base/base64.h"
     48 #include "talk/base/basictypes.h"
     49 #include "talk/base/logging.h"
     50 #include "talk/base/scoped_ptr.h"
     51 #include "talk/base/timeutils.h"
     52 
     53 // Protect against max macro inclusion.
     54 #undef max
     55 
     56 namespace talk_base {
     57 
     58 // Base class for RNG implementations.
     59 class RandomGenerator {
     60  public:
     61   virtual ~RandomGenerator() {}
     62   virtual bool Init(const void* seed, size_t len) = 0;
     63   virtual bool Generate(void* buf, size_t len) = 0;
     64 };
     65 
     66 #if defined(SSL_USE_OPENSSL)
     67 // The OpenSSL RNG. Need to make sure it doesn't run out of entropy.
     68 class SecureRandomGenerator : public RandomGenerator {
     69  public:
     70   SecureRandomGenerator() : inited_(false) {
     71   }
     72   ~SecureRandomGenerator() {
     73   }
     74   virtual bool Init(const void* seed, size_t len) {
     75     // By default, seed from the system state.
     76     if (!inited_) {
     77       if (RAND_poll() <= 0) {
     78         return false;
     79       }
     80       inited_ = true;
     81     }
     82     // Allow app data to be mixed in, if provided.
     83     if (seed) {
     84       RAND_seed(seed, len);
     85     }
     86     return true;
     87   }
     88   virtual bool Generate(void* buf, size_t len) {
     89     if (!inited_ && !Init(NULL, 0)) {
     90       return false;
     91     }
     92     return (RAND_bytes(reinterpret_cast<unsigned char*>(buf), len) > 0);
     93   }
     94 
     95  private:
     96   bool inited_;
     97 };
     98 
     99 #elif defined(SSL_USE_NSS_RNG)
    100 // The NSS RNG.
    101 class SecureRandomGenerator : public RandomGenerator {
    102  public:
    103   SecureRandomGenerator() {}
    104   ~SecureRandomGenerator() {}
    105   virtual bool Init(const void* seed, size_t len) {
    106     return true;
    107   }
    108   virtual bool Generate(void* buf, size_t len) {
    109     return (PK11_GenerateRandom(reinterpret_cast<unsigned char*>(buf),
    110                                 static_cast<int>(len)) == SECSuccess);
    111   }
    112 };
    113 
    114 #else
    115 #ifdef WIN32
    116 class SecureRandomGenerator : public RandomGenerator {
    117  public:
    118   SecureRandomGenerator() : advapi32_(NULL), rtl_gen_random_(NULL) {}
    119   ~SecureRandomGenerator() {
    120     FreeLibrary(advapi32_);
    121   }
    122 
    123   virtual bool Init(const void* seed, size_t seed_len) {
    124     // We don't do any additional seeding on Win32, we just use the CryptoAPI
    125     // RNG (which is exposed as a hidden function off of ADVAPI32 so that we
    126     // don't need to drag in all of CryptoAPI)
    127     if (rtl_gen_random_) {
    128       return true;
    129     }
    130 
    131     advapi32_ = LoadLibrary(L"advapi32.dll");
    132     if (!advapi32_) {
    133       return false;
    134     }
    135 
    136     rtl_gen_random_ = reinterpret_cast<RtlGenRandomProc>(
    137         GetProcAddress(advapi32_, "SystemFunction036"));
    138     if (!rtl_gen_random_) {
    139       FreeLibrary(advapi32_);
    140       return false;
    141     }
    142 
    143     return true;
    144   }
    145   virtual bool Generate(void* buf, size_t len) {
    146     if (!rtl_gen_random_ && !Init(NULL, 0)) {
    147       return false;
    148     }
    149     return (rtl_gen_random_(buf, static_cast<int>(len)) != FALSE);
    150   }
    151 
    152  private:
    153   typedef BOOL (WINAPI *RtlGenRandomProc)(PVOID, ULONG);
    154   HINSTANCE advapi32_;
    155   RtlGenRandomProc rtl_gen_random_;
    156 };
    157 
    158 #elif !defined(FEATURE_ENABLE_SSL)
    159 
    160 // No SSL implementation -- use rand()
    161 class SecureRandomGenerator : public RandomGenerator {
    162  public:
    163   virtual bool Init(const void* seed, size_t len) {
    164     if (len >= 4) {
    165       srand(*reinterpret_cast<const int*>(seed));
    166     } else {
    167       srand(*reinterpret_cast<const char*>(seed));
    168     }
    169     return true;
    170   }
    171   virtual bool Generate(void* buf, size_t len) {
    172     char* bytes = reinterpret_cast<char*>(buf);
    173     for (size_t i = 0; i < len; ++i) {
    174       bytes[i] = static_cast<char>(rand());
    175     }
    176     return true;
    177   }
    178 };
    179 
    180 #else
    181 
    182 #error No SSL implementation has been selected!
    183 
    184 #endif  // WIN32
    185 #endif
    186 
    187 // A test random generator, for predictable output.
    188 class TestRandomGenerator : public RandomGenerator {
    189  public:
    190   TestRandomGenerator() : seed_(7) {
    191   }
    192   ~TestRandomGenerator() {
    193   }
    194   virtual bool Init(const void* seed, size_t len) {
    195     return true;
    196   }
    197   virtual bool Generate(void* buf, size_t len) {
    198     for (size_t i = 0; i < len; ++i) {
    199       static_cast<uint8*>(buf)[i] = static_cast<uint8>(GetRandom());
    200     }
    201     return true;
    202   }
    203 
    204  private:
    205   int GetRandom() {
    206     return ((seed_ = seed_ * 214013L + 2531011L) >> 16) & 0x7fff;
    207   }
    208   int seed_;
    209 };
    210 
    211 // TODO: Use Base64::Base64Table instead.
    212 static const char BASE64[64] = {
    213   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
    214   'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
    215   'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
    216   'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
    217   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
    218 };
    219 
    220 namespace {
    221 
    222 // This round about way of creating a global RNG is to safe-guard against
    223 // indeterminant static initialization order.
    224 scoped_ptr<RandomGenerator>& GetGlobalRng() {
    225   LIBJINGLE_DEFINE_STATIC_LOCAL(scoped_ptr<RandomGenerator>, global_rng,
    226                                 (new SecureRandomGenerator()));
    227   return global_rng;
    228 }
    229 
    230 RandomGenerator& Rng() {
    231   return *GetGlobalRng();
    232 }
    233 
    234 }  // namespace
    235 
    236 void SetRandomTestMode(bool test) {
    237   if (!test) {
    238     GetGlobalRng().reset(new SecureRandomGenerator());
    239   } else {
    240     GetGlobalRng().reset(new TestRandomGenerator());
    241   }
    242 }
    243 
    244 bool InitRandom(int seed) {
    245   return InitRandom(reinterpret_cast<const char*>(&seed), sizeof(seed));
    246 }
    247 
    248 bool InitRandom(const char* seed, size_t len) {
    249   if (!Rng().Init(seed, len)) {
    250     LOG(LS_ERROR) << "Failed to init random generator!";
    251     return false;
    252   }
    253   return true;
    254 }
    255 
    256 std::string CreateRandomString(size_t len) {
    257   std::string str;
    258   CreateRandomString(len, &str);
    259   return str;
    260 }
    261 
    262 bool CreateRandomString(size_t len,
    263                         const char* table, int table_size,
    264                         std::string* str) {
    265   str->clear();
    266   scoped_ptr<uint8[]> bytes(new uint8[len]);
    267   if (!Rng().Generate(bytes.get(), len)) {
    268     LOG(LS_ERROR) << "Failed to generate random string!";
    269     return false;
    270   }
    271   str->reserve(len);
    272   for (size_t i = 0; i < len; ++i) {
    273     str->push_back(table[bytes[i] % table_size]);
    274   }
    275   return true;
    276 }
    277 
    278 bool CreateRandomString(size_t len, std::string* str) {
    279   return CreateRandomString(len, BASE64, 64, str);
    280 }
    281 
    282 bool CreateRandomString(size_t len, const std::string& table,
    283                         std::string* str) {
    284   return CreateRandomString(len, table.c_str(),
    285                             static_cast<int>(table.size()), str);
    286 }
    287 
    288 uint32 CreateRandomId() {
    289   uint32 id;
    290   if (!Rng().Generate(&id, sizeof(id))) {
    291     LOG(LS_ERROR) << "Failed to generate random id!";
    292   }
    293   return id;
    294 }
    295 
    296 uint64 CreateRandomId64() {
    297   return static_cast<uint64>(CreateRandomId()) << 32 | CreateRandomId();
    298 }
    299 
    300 uint32 CreateRandomNonZeroId() {
    301   uint32 id;
    302   do {
    303     id = CreateRandomId();
    304   } while (id == 0);
    305   return id;
    306 }
    307 
    308 double CreateRandomDouble() {
    309   return CreateRandomId() / (std::numeric_limits<uint32>::max() +
    310       std::numeric_limits<double>::epsilon());
    311 }
    312 
    313 }  // namespace talk_base
    314