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