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 39namespace rtc { 40 41// Base class for RNG implementations. 42class 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. 51class 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. 84class 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) 99class 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() 144class 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. 171class 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. 195static 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 203namespace { 204 205// This round about way of creating a global RNG is to safe-guard against 206// indeterminant static initialization order. 207scoped_ptr<RandomGenerator>& GetGlobalRng() { 208 LIBJINGLE_DEFINE_STATIC_LOCAL(scoped_ptr<RandomGenerator>, global_rng, 209 (new SecureRandomGenerator())); 210 return global_rng; 211} 212 213RandomGenerator& Rng() { 214 return *GetGlobalRng(); 215} 216 217} // namespace 218 219void SetRandomTestMode(bool test) { 220 if (!test) { 221 GetGlobalRng().reset(new SecureRandomGenerator()); 222 } else { 223 GetGlobalRng().reset(new TestRandomGenerator()); 224 } 225} 226 227bool InitRandom(int seed) { 228 return InitRandom(reinterpret_cast<const char*>(&seed), sizeof(seed)); 229} 230 231bool 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 239std::string CreateRandomString(size_t len) { 240 std::string str; 241 CreateRandomString(len, &str); 242 return str; 243} 244 245bool 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 261bool CreateRandomString(size_t len, std::string* str) { 262 return CreateRandomString(len, BASE64, 64, str); 263} 264 265bool 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 271uint32 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 279uint64 CreateRandomId64() { 280 return static_cast<uint64>(CreateRandomId()) << 32 | CreateRandomId(); 281} 282 283uint32 CreateRandomNonZeroId() { 284 uint32 id; 285 do { 286 id = CreateRandomId(); 287 } while (id == 0); 288 return id; 289} 290 291double CreateRandomDouble() { 292 return CreateRandomId() / (std::numeric_limits<uint32>::max() + 293 std::numeric_limits<double>::epsilon()); 294} 295 296} // namespace rtc 297