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