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 #include "talk/base/sslconfig.h"
     33 #if defined(SSL_USE_OPENSSL)
     34 #include <openssl/rand.h>
     35 #elif defined(SSL_USE_NSS_RNG)
     36 #include "pk11func.h"
     37 #else
     38 #ifdef WIN32
     39 #define WIN32_LEAN_AND_MEAN
     40 #include <windows.h>
     41 #include <ntsecapi.h>
     42 #endif  // WIN32
     43 #endif
     44 
     45 #include "talk/base/base64.h"
     46 #include "talk/base/basictypes.h"
     47 #include "talk/base/logging.h"
     48 #include "talk/base/scoped_ptr.h"
     49 #include "talk/base/timeutils.h"
     50 
     51 // Protect against max macro inclusion.
     52 #undef max
     53 
     54 namespace talk_base {
     55 
     56 // Base class for RNG implementations.
     57 class RandomGenerator {
     58  public:
     59   virtual ~RandomGenerator() {}
     60   virtual bool Init(const void* seed, size_t len) = 0;
     61   virtual bool Generate(void* buf, size_t len) = 0;
     62 };
     63 
     64 #if defined(SSL_USE_OPENSSL)
     65 // The OpenSSL RNG. Need to make sure it doesn't run out of entropy.
     66 class SecureRandomGenerator : public RandomGenerator {
     67  public:
     68   SecureRandomGenerator() : inited_(false) {
     69   }
     70   ~SecureRandomGenerator() {
     71   }
     72   virtual bool Init(const void* seed, size_t len) {
     73     // By default, seed from the system state.
     74     if (!inited_) {
     75       if (RAND_poll() <= 0) {
     76         return false;
     77       }
     78       inited_ = true;
     79     }
     80     // Allow app data to be mixed in, if provided.
     81     if (seed) {
     82       RAND_seed(seed, len);
     83     }
     84     return true;
     85   }
     86   virtual bool Generate(void* buf, size_t len) {
     87     if (!inited_ && !Init(NULL, 0)) {
     88       return false;
     89     }
     90     return (RAND_bytes(reinterpret_cast<unsigned char*>(buf), len) > 0);
     91   }
     92 
     93  private:
     94   bool inited_;
     95 };
     96 
     97 #elif defined(SSL_USE_NSS_RNG)
     98 // The NSS RNG.
     99 class SecureRandomGenerator : public RandomGenerator {
    100  public:
    101   SecureRandomGenerator() {}
    102   ~SecureRandomGenerator() {}
    103   virtual bool Init(const void* seed, size_t len) {
    104     return true;
    105   }
    106   virtual bool Generate(void* buf, size_t len) {
    107     return (PK11_GenerateRandom(reinterpret_cast<unsigned char*>(buf),
    108                                 static_cast<int>(len)) == SECSuccess);
    109   }
    110 };
    111 
    112 #else
    113 #ifdef WIN32
    114 class SecureRandomGenerator : public RandomGenerator {
    115  public:
    116   SecureRandomGenerator() : advapi32_(NULL), rtl_gen_random_(NULL) {}
    117   ~SecureRandomGenerator() {
    118     FreeLibrary(advapi32_);
    119   }
    120 
    121   virtual bool Init(const void* seed, size_t seed_len) {
    122     // We don't do any additional seeding on Win32, we just use the CryptoAPI
    123     // RNG (which is exposed as a hidden function off of ADVAPI32 so that we
    124     // don't need to drag in all of CryptoAPI)
    125     if (rtl_gen_random_) {
    126       return true;
    127     }
    128 
    129     advapi32_ = LoadLibrary(L"advapi32.dll");
    130     if (!advapi32_) {
    131       return false;
    132     }
    133 
    134     rtl_gen_random_ = reinterpret_cast<RtlGenRandomProc>(
    135         GetProcAddress(advapi32_, "SystemFunction036"));
    136     if (!rtl_gen_random_) {
    137       FreeLibrary(advapi32_);
    138       return false;
    139     }
    140 
    141     return true;
    142   }
    143   virtual bool Generate(void* buf, size_t len) {
    144     if (!rtl_gen_random_ && !Init(NULL, 0)) {
    145       return false;
    146     }
    147     return (rtl_gen_random_(buf, static_cast<int>(len)) != FALSE);
    148   }
    149 
    150  private:
    151   typedef BOOL (WINAPI *RtlGenRandomProc)(PVOID, ULONG);
    152   HINSTANCE advapi32_;
    153   RtlGenRandomProc rtl_gen_random_;
    154 };
    155 
    156 #else
    157 
    158 #error No SSL implementation has been selected!
    159 
    160 #endif  // WIN32
    161 #endif
    162 
    163 // A test random generator, for predictable output.
    164 class TestRandomGenerator : public RandomGenerator {
    165  public:
    166   TestRandomGenerator() : seed_(7) {
    167   }
    168   ~TestRandomGenerator() {
    169   }
    170   virtual bool Init(const void* seed, size_t len) {
    171     return true;
    172   }
    173   virtual bool Generate(void* buf, size_t len) {
    174     for (size_t i = 0; i < len; ++i) {
    175       static_cast<uint8*>(buf)[i] = static_cast<uint8>(GetRandom());
    176     }
    177     return true;
    178   }
    179 
    180  private:
    181   int GetRandom() {
    182     return ((seed_ = seed_ * 214013L + 2531011L) >> 16) & 0x7fff;
    183   }
    184   int seed_;
    185 };
    186 
    187 // TODO: Use Base64::Base64Table instead.
    188 static const char BASE64[64] = {
    189   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
    190   'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
    191   'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
    192   'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
    193   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
    194 };
    195 
    196 namespace {
    197 
    198 // This round about way of creating a global RNG is to safe-guard against
    199 // indeterminant static initialization order.
    200 scoped_ptr<RandomGenerator>& GetGlobalRng() {
    201   LIBJINGLE_DEFINE_STATIC_LOCAL(scoped_ptr<RandomGenerator>, global_rng,
    202                                 (new SecureRandomGenerator()));
    203   return global_rng;
    204 }
    205 
    206 RandomGenerator& Rng() {
    207   return *GetGlobalRng();
    208 }
    209 
    210 }  // namespace
    211 
    212 void SetRandomTestMode(bool test) {
    213   if (!test) {
    214     GetGlobalRng().reset(new SecureRandomGenerator());
    215   } else {
    216     GetGlobalRng().reset(new TestRandomGenerator());
    217   }
    218 }
    219 
    220 bool InitRandom(int seed) {
    221   return InitRandom(reinterpret_cast<const char*>(&seed), sizeof(seed));
    222 }
    223 
    224 bool InitRandom(const char* seed, size_t len) {
    225   if (!Rng().Init(seed, len)) {
    226     LOG(LS_ERROR) << "Failed to init random generator!";
    227     return false;
    228   }
    229   return true;
    230 }
    231 
    232 std::string CreateRandomString(size_t len) {
    233   std::string str;
    234   CreateRandomString(len, &str);
    235   return str;
    236 }
    237 
    238 bool CreateRandomString(size_t len,
    239                         const char* table, int table_size,
    240                         std::string* str) {
    241   str->clear();
    242   scoped_array<uint8> bytes(new uint8[len]);
    243   if (!Rng().Generate(bytes.get(), len)) {
    244     LOG(LS_ERROR) << "Failed to generate random string!";
    245     return false;
    246   }
    247   str->reserve(len);
    248   for (size_t i = 0; i < len; ++i) {
    249     str->push_back(table[bytes[i] % table_size]);
    250   }
    251   return true;
    252 }
    253 
    254 bool CreateRandomString(size_t len, std::string* str) {
    255   return CreateRandomString(len, BASE64, 64, str);
    256 }
    257 
    258 bool CreateRandomString(size_t len, const std::string& table,
    259                         std::string* str) {
    260   return CreateRandomString(len, table.c_str(),
    261                             static_cast<int>(table.size()), str);
    262 }
    263 
    264 uint32 CreateRandomId() {
    265   uint32 id;
    266   if (!Rng().Generate(&id, sizeof(id))) {
    267     LOG(LS_ERROR) << "Failed to generate random id!";
    268   }
    269   return id;
    270 }
    271 
    272 uint64 CreateRandomId64() {
    273   return static_cast<uint64>(CreateRandomId()) << 32 | CreateRandomId();
    274 }
    275 
    276 uint32 CreateRandomNonZeroId() {
    277   uint32 id;
    278   do {
    279     id = CreateRandomId();
    280   } while (id == 0);
    281   return id;
    282 }
    283 
    284 double CreateRandomDouble() {
    285   return CreateRandomId() / (std::numeric_limits<uint32>::max() +
    286       std::numeric_limits<double>::epsilon());
    287 }
    288 
    289 }  // namespace talk_base
    290