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"
33
#define WIN32_LEAN_AND_MEAN
37
#ifdef SSL_USE_OPENSSL
38
#include <openssl/rand.h>
42
#include "talk/base/base64.h"
43
#include "talk/base/basictypes.h"
44
#include "talk/base/logging.h"
45
#include "talk/base/scoped_ptr.h"
46
#include "talk/base/timeutils.h"
48
// Protect against max macro inclusion.
53
// Base class for RNG implementations.
54
class RandomGenerator {
56
virtual ~RandomGenerator() {}
57
virtual bool Init(const void* seed, size_t len) = 0;
58
virtual bool Generate(void* buf, size_t len) = 0;
61
// The real random generators, using either CryptoAPI or OpenSSL.
62
// We also support the 'old' generator on Mac/Linux until we have time to
63
// fully test the OpenSSL one.
65
class SecureRandomGenerator : public RandomGenerator {
67
SecureRandomGenerator() : advapi32_(NULL), rtl_gen_random_(NULL) {}
68
~SecureRandomGenerator() {
69
FreeLibrary(advapi32_);
72
virtual bool Init(const void* seed, size_t seed_len) {
73
// We don't do any additional seeding on Win32, we just use the CryptoAPI
74
// RNG (which is exposed as a hidden function off of ADVAPI32 so that we
75
// don't need to drag in all of CryptoAPI)
76
if (rtl_gen_random_) {
80
advapi32_ = LoadLibrary(L"advapi32.dll");
85
rtl_gen_random_ = reinterpret_cast<RtlGenRandomProc>(
86
GetProcAddress(advapi32_, "SystemFunction036"));
87
if (!rtl_gen_random_) {
88
FreeLibrary(advapi32_);
94
virtual bool Generate(void* buf, size_t len) {
95
if (!rtl_gen_random_ && !Init(NULL, 0)) {
98
return (rtl_gen_random_(buf, static_cast<int>(len)) != FALSE);
102
typedef BOOL (WINAPI *RtlGenRandomProc)(PVOID, ULONG);
104
RtlGenRandomProc rtl_gen_random_;
107
#ifndef SSL_USE_OPENSSL
109
class SecureRandomGenerator : public RandomGenerator {
111
SecureRandomGenerator() : seed_(1) {
113
~SecureRandomGenerator() {
115
virtual bool Init(const void* seed, size_t len) {
117
for (size_t i = 0; i < len; ++i) {
118
hash = ((hash << 2) + hash) + static_cast<const char*>(seed)[i];
121
seed_ = Time() ^ hash;
124
virtual bool Generate(void* buf, size_t len) {
125
for (size_t i = 0; i < len; ++i) {
126
static_cast<uint8*>(buf)[i] = static_cast<uint8>(GetRandom());
133
return ((seed_ = seed_ * 214013L + 2531011L) >> 16) & 0x7fff;
138
// The OpenSSL RNG. Need to make sure it doesn't run out of entropy.
139
class SecureRandomGenerator : public RandomGenerator {
141
SecureRandomGenerator() : inited_(false) {
143
~SecureRandomGenerator() {
145
virtual bool Init(const void* seed, size_t len) {
146
// By default, seed from the system state.
148
if (RAND_poll() <= 0) {
153
// Allow app data to be mixed in, if provided.
155
RAND_seed(seed, len);
159
virtual bool Generate(void* buf, size_t len) {
160
if (!inited_ && !Init(NULL, 0)) {
163
return (RAND_bytes(reinterpret_cast<unsigned char*>(buf), len) > 0);
169
#endif // SSL_USE_OPENSSL
172
// A test random generator, for predictable output.
173
class TestRandomGenerator : public RandomGenerator {
175
TestRandomGenerator() : seed_(7) {
177
~TestRandomGenerator() {
179
virtual bool Init(const void* seed, size_t len) {
182
virtual bool Generate(void* buf, size_t len) {
183
for (size_t i = 0; i < len; ++i) {
184
static_cast<uint8*>(buf)[i] = static_cast<uint8>(GetRandom());
191
return ((seed_ = seed_ * 214013L + 2531011L) >> 16) & 0x7fff;
196
// TODO: Use Base64::Base64Table instead.
197
static const char BASE64[64] = {
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
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
201
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
202
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
207
// This round about way of creating a global RNG is to safe-guard against
208
// indeterminant static initialization order.
209
scoped_ptr<RandomGenerator>& GetGlobalRng() {
210
LIBJINGLE_DEFINE_STATIC_LOCAL(scoped_ptr<RandomGenerator>, global_rng,
211
(new SecureRandomGenerator()));
215
RandomGenerator& Rng() {
216
return *GetGlobalRng();
221
void SetRandomTestMode(bool test) {
223
GetGlobalRng().reset(new SecureRandomGenerator());
225
GetGlobalRng().reset(new TestRandomGenerator());
229
bool InitRandom(int seed) {
230
return InitRandom(reinterpret_cast<const char*>(&seed), sizeof(seed));
233
bool InitRandom(const char* seed, size_t len) {
234
if (!Rng().Init(seed, len)) {
235
LOG(LS_ERROR) << "Failed to init random generator!";
241
std::string CreateRandomString(size_t len) {
243
CreateRandomString(len, &str);
247
bool CreateRandomString(size_t len,
248
const char* table, int table_size,
251
scoped_array<uint8> bytes(new uint8[len]);
252
if (!Rng().Generate(bytes.get(), len)) {
253
LOG(LS_ERROR) << "Failed to generate random string!";
257
for (size_t i = 0; i < len; ++i) {
258
str->push_back(table[bytes[i] % table_size]);
263
bool CreateRandomString(size_t len, std::string* str) {
264
return CreateRandomString(len, BASE64, 64, str);
267
bool CreateRandomString(size_t len, const std::string& table,
269
return CreateRandomString(len, table.c_str(),
270
static_cast<int>(table.size()), str);
273
uint32 CreateRandomId() {
275
if (!Rng().Generate(&id, sizeof(id))) {
276
LOG(LS_ERROR) << "Failed to generate random id!";
281
uint32 CreateRandomNonZeroId() {
284
id = CreateRandomId();
289
double CreateRandomDouble() {
290
return CreateRandomId() / (std::numeric_limits<uint32>::max() +
291
std::numeric_limits<double>::epsilon());
294
} // namespace talk_base