3 * Copyright 2004--2005, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
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.
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.
28 #include "talk/base/helpers.h"
32 #include "talk/base/sslconfig.h"
33 #if defined(SSL_USE_OPENSSL)
34 #include <openssl/rand.h>
35 #elif defined(SSL_USE_NSS_RNG)
39 #define WIN32_LEAN_AND_MEAN
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"
51 // Protect against max macro inclusion.
56 // Base class for RNG implementations.
57 class RandomGenerator {
59 virtual ~RandomGenerator() {}
60 virtual bool Init(const void* seed, size_t len) = 0;
61 virtual bool Generate(void* buf, size_t len) = 0;
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 {
68 SecureRandomGenerator() : inited_(false) {
70 ~SecureRandomGenerator() {
72 virtual bool Init(const void* seed, size_t len) {
73 // By default, seed from the system state.
75 if (RAND_poll() <= 0) {
80 // Allow app data to be mixed in, if provided.
86 virtual bool Generate(void* buf, size_t len) {
87 if (!inited_ && !Init(NULL, 0)) {
90 return (RAND_bytes(reinterpret_cast<unsigned char*>(buf), len) > 0);
97 #elif defined(SSL_USE_NSS_RNG)
99 class SecureRandomGenerator : public RandomGenerator {
101 SecureRandomGenerator() {}
102 ~SecureRandomGenerator() {}
103 virtual bool Init(const void* seed, size_t len) {
106 virtual bool Generate(void* buf, size_t len) {
107 return (PK11_GenerateRandom(reinterpret_cast<unsigned char*>(buf),
108 static_cast<int>(len)) == SECSuccess);
114 class SecureRandomGenerator : public RandomGenerator {
116 SecureRandomGenerator() : advapi32_(NULL), rtl_gen_random_(NULL) {}
117 ~SecureRandomGenerator() {
118 FreeLibrary(advapi32_);
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_) {
129 advapi32_ = LoadLibrary(L"advapi32.dll");
134 rtl_gen_random_ = reinterpret_cast<RtlGenRandomProc>(
135 GetProcAddress(advapi32_, "SystemFunction036"));
136 if (!rtl_gen_random_) {
137 FreeLibrary(advapi32_);
143 virtual bool Generate(void* buf, size_t len) {
144 if (!rtl_gen_random_ && !Init(NULL, 0)) {
147 return (rtl_gen_random_(buf, static_cast<int>(len)) != FALSE);
151 typedef BOOL (WINAPI *RtlGenRandomProc)(PVOID, ULONG);
153 RtlGenRandomProc rtl_gen_random_;
158 #error No SSL implementation has been selected!
163 // A test random generator, for predictable output.
164 class TestRandomGenerator : public RandomGenerator {
166 TestRandomGenerator() : seed_(7) {
168 ~TestRandomGenerator() {
170 virtual bool Init(const void* seed, size_t len) {
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());
182 return ((seed_ = seed_ * 214013L + 2531011L) >> 16) & 0x7fff;
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', '+', '/'
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()));
206 RandomGenerator& Rng() {
207 return *GetGlobalRng();
212 void SetRandomTestMode(bool test) {
214 GetGlobalRng().reset(new SecureRandomGenerator());
216 GetGlobalRng().reset(new TestRandomGenerator());
220 bool InitRandom(int seed) {
221 return InitRandom(reinterpret_cast<const char*>(&seed), sizeof(seed));
224 bool InitRandom(const char* seed, size_t len) {
225 if (!Rng().Init(seed, len)) {
226 LOG(LS_ERROR) << "Failed to init random generator!";
232 std::string CreateRandomString(size_t len) {
234 CreateRandomString(len, &str);
238 bool CreateRandomString(size_t len,
239 const char* table, int table_size,
242 scoped_ptr<uint8[]> bytes(new uint8[len]);
243 if (!Rng().Generate(bytes.get(), len)) {
244 LOG(LS_ERROR) << "Failed to generate random string!";
248 for (size_t i = 0; i < len; ++i) {
249 str->push_back(table[bytes[i] % table_size]);
254 bool CreateRandomString(size_t len, std::string* str) {
255 return CreateRandomString(len, BASE64, 64, str);
258 bool CreateRandomString(size_t len, const std::string& table,
260 return CreateRandomString(len, table.c_str(),
261 static_cast<int>(table.size()), str);
264 uint32 CreateRandomId() {
266 if (!Rng().Generate(&id, sizeof(id))) {
267 LOG(LS_ERROR) << "Failed to generate random id!";
272 uint64 CreateRandomId64() {
273 return static_cast<uint64>(CreateRandomId()) << 32 | CreateRandomId();
276 uint32 CreateRandomNonZeroId() {
279 id = CreateRandomId();
284 double CreateRandomDouble() {
285 return CreateRandomId() / (std::numeric_limits<uint32>::max() +
286 std::numeric_limits<double>::epsilon());
289 } // namespace talk_base