~ubuntu-branches/ubuntu/saucy/kopete/saucy-proposed

« back to all changes in this revision

Viewing changes to protocols/jabber/googletalk/libjingle/talk/base/helpers.cc

  • Committer: Package Import Robot
  • Author(s): Jonathan Riddell
  • Date: 2013-06-21 02:22:39 UTC
  • Revision ID: package-import@ubuntu.com-20130621022239-63l3zc8p0nf26pt6
Tags: upstream-4.10.80
ImportĀ upstreamĀ versionĀ 4.10.80

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * libjingle
 
3
 * Copyright 2004--2005, Google Inc.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions are met:
 
7
 *
 
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.
 
15
 *
 
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.
 
26
 */
 
27
 
 
28
#include "talk/base/helpers.h"
 
29
 
 
30
#include <limits>
 
31
 
 
32
#ifdef WIN32
 
33
#define WIN32_LEAN_AND_MEAN
 
34
#include <windows.h>
 
35
#include <ntsecapi.h>
 
36
#else
 
37
#ifdef SSL_USE_OPENSSL
 
38
#include <openssl/rand.h>
 
39
#endif
 
40
#endif
 
41
 
 
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"
 
47
 
 
48
// Protect against max macro inclusion.
 
49
#undef max
 
50
 
 
51
namespace talk_base {
 
52
 
 
53
// Base class for RNG implementations.
 
54
class RandomGenerator {
 
55
 public:
 
56
  virtual ~RandomGenerator() {}
 
57
  virtual bool Init(const void* seed, size_t len) = 0;
 
58
  virtual bool Generate(void* buf, size_t len) = 0;
 
59
};
 
60
 
 
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.
 
64
#ifdef WIN32
 
65
class SecureRandomGenerator : public RandomGenerator {
 
66
 public:
 
67
  SecureRandomGenerator() : advapi32_(NULL), rtl_gen_random_(NULL) {}
 
68
  ~SecureRandomGenerator() {
 
69
    FreeLibrary(advapi32_);
 
70
  }
 
71
 
 
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_) {
 
77
      return true;
 
78
    }
 
79
 
 
80
    advapi32_ = LoadLibrary(L"advapi32.dll");
 
81
    if (!advapi32_) {
 
82
      return false;
 
83
    }
 
84
 
 
85
    rtl_gen_random_ = reinterpret_cast<RtlGenRandomProc>(
 
86
        GetProcAddress(advapi32_, "SystemFunction036"));
 
87
    if (!rtl_gen_random_) {
 
88
      FreeLibrary(advapi32_);
 
89
      return false;
 
90
    }
 
91
 
 
92
    return true;
 
93
  }
 
94
  virtual bool Generate(void* buf, size_t len) {
 
95
    if (!rtl_gen_random_ && !Init(NULL, 0)) {
 
96
      return false;
 
97
    }
 
98
    return (rtl_gen_random_(buf, static_cast<int>(len)) != FALSE);
 
99
  }
 
100
 
 
101
 private:
 
102
  typedef BOOL (WINAPI *RtlGenRandomProc)(PVOID, ULONG);
 
103
  HINSTANCE advapi32_;
 
104
  RtlGenRandomProc rtl_gen_random_;
 
105
};
 
106
#else
 
107
#ifndef SSL_USE_OPENSSL
 
108
// The old RNG.
 
109
class SecureRandomGenerator : public RandomGenerator {
 
110
 public:
 
111
  SecureRandomGenerator() : seed_(1) {
 
112
  }
 
113
  ~SecureRandomGenerator() {
 
114
  }
 
115
  virtual bool Init(const void* seed, size_t len) {
 
116
    uint32 hash = 0;
 
117
    for (size_t i = 0; i < len; ++i) {
 
118
      hash = ((hash << 2) + hash) + static_cast<const char*>(seed)[i];
 
119
    }
 
120
 
 
121
    seed_ = Time() ^ hash;
 
122
    return true;
 
123
  }
 
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());
 
127
    }
 
128
    return true;
 
129
  }
 
130
 
 
131
 private:
 
132
  int GetRandom() {
 
133
    return ((seed_ = seed_ * 214013L + 2531011L) >> 16) & 0x7fff;
 
134
  }
 
135
  int seed_;
 
136
};
 
137
#else
 
138
// The OpenSSL RNG. Need to make sure it doesn't run out of entropy.
 
139
class SecureRandomGenerator : public RandomGenerator {
 
140
 public:
 
141
  SecureRandomGenerator() : inited_(false) {
 
142
  }
 
143
  ~SecureRandomGenerator() {
 
144
  }
 
145
  virtual bool Init(const void* seed, size_t len) {
 
146
    // By default, seed from the system state.
 
147
    if (!inited_) {
 
148
      if (RAND_poll() <= 0) {
 
149
        return false;
 
150
      }
 
151
      inited_ = true;
 
152
    }
 
153
    // Allow app data to be mixed in, if provided.
 
154
    if (seed) {
 
155
      RAND_seed(seed, len);
 
156
    }
 
157
    return true;
 
158
  }
 
159
  virtual bool Generate(void* buf, size_t len) {
 
160
    if (!inited_ && !Init(NULL, 0)) {
 
161
      return false;
 
162
    }
 
163
    return (RAND_bytes(reinterpret_cast<unsigned char*>(buf), len) > 0);
 
164
  }
 
165
 
 
166
 private:
 
167
  bool inited_;
 
168
};
 
169
#endif  // SSL_USE_OPENSSL
 
170
#endif  // WIN32
 
171
 
 
172
// A test random generator, for predictable output.
 
173
class TestRandomGenerator : public RandomGenerator {
 
174
 public:
 
175
  TestRandomGenerator() : seed_(7) {
 
176
  }
 
177
  ~TestRandomGenerator() {
 
178
  }
 
179
  virtual bool Init(const void* seed, size_t len) {
 
180
    return true;
 
181
  }
 
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());
 
185
    }
 
186
    return true;
 
187
  }
 
188
 
 
189
 private:
 
190
  int GetRandom() {
 
191
    return ((seed_ = seed_ * 214013L + 2531011L) >> 16) & 0x7fff;
 
192
  }
 
193
  int seed_;
 
194
};
 
195
 
 
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', '+', '/'
 
203
};
 
204
 
 
205
namespace {
 
206
 
 
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()));
 
212
  return global_rng;
 
213
}
 
214
 
 
215
RandomGenerator& Rng() {
 
216
  return *GetGlobalRng();
 
217
}
 
218
 
 
219
}  // namespace
 
220
 
 
221
void SetRandomTestMode(bool test) {
 
222
  if (!test) {
 
223
    GetGlobalRng().reset(new SecureRandomGenerator());
 
224
  } else {
 
225
    GetGlobalRng().reset(new TestRandomGenerator());
 
226
  }
 
227
}
 
228
 
 
229
bool InitRandom(int seed) {
 
230
  return InitRandom(reinterpret_cast<const char*>(&seed), sizeof(seed));
 
231
}
 
232
 
 
233
bool InitRandom(const char* seed, size_t len) {
 
234
  if (!Rng().Init(seed, len)) {
 
235
    LOG(LS_ERROR) << "Failed to init random generator!";
 
236
    return false;
 
237
  }
 
238
  return true;
 
239
}
 
240
 
 
241
std::string CreateRandomString(size_t len) {
 
242
  std::string str;
 
243
  CreateRandomString(len, &str);
 
244
  return str;
 
245
}
 
246
 
 
247
bool CreateRandomString(size_t len,
 
248
                        const char* table, int table_size,
 
249
                        std::string* str) {
 
250
  str->clear();
 
251
  scoped_array<uint8> bytes(new uint8[len]);
 
252
  if (!Rng().Generate(bytes.get(), len)) {
 
253
    LOG(LS_ERROR) << "Failed to generate random string!";
 
254
    return false;
 
255
  }
 
256
  str->reserve(len);
 
257
  for (size_t i = 0; i < len; ++i) {
 
258
    str->push_back(table[bytes[i] % table_size]);
 
259
  }
 
260
  return true;
 
261
}
 
262
 
 
263
bool CreateRandomString(size_t len, std::string* str) {
 
264
  return CreateRandomString(len, BASE64, 64, str);
 
265
}
 
266
 
 
267
bool CreateRandomString(size_t len, const std::string& table,
 
268
                        std::string* str) {
 
269
  return CreateRandomString(len, table.c_str(),
 
270
                            static_cast<int>(table.size()), str);
 
271
}
 
272
 
 
273
uint32 CreateRandomId() {
 
274
  uint32 id;
 
275
  if (!Rng().Generate(&id, sizeof(id))) {
 
276
    LOG(LS_ERROR) << "Failed to generate random id!";
 
277
  }
 
278
  return id;
 
279
}
 
280
 
 
281
uint32 CreateRandomNonZeroId() {
 
282
  uint32 id;
 
283
  do {
 
284
    id = CreateRandomId();
 
285
  } while (id == 0);
 
286
  return id;
 
287
}
 
288
 
 
289
double CreateRandomDouble() {
 
290
  return CreateRandomId() / (std::numeric_limits<uint32>::max() +
 
291
      std::numeric_limits<double>::epsilon());
 
292
}
 
293
 
 
294
}  // namespace talk_base