- add third_party src.
[platform/framework/web/crosswalk.git] / src / third_party / libjingle / source / talk / base / helpers.cc
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 #include "talk/base/sslconfig.h"
33 #if defined(SSL_USE_OPENSSL)
34 #include <openssl/rand.h>
35 #elif defined(SSL_USE_NSS_RNG)
36 #include "pk11func.h"
37 #else
38 #ifdef WIN32
39 #define WIN32_LEAN_AND_MEAN
40 #include <windows.h>
41 #include <ntsecapi.h>
42 #endif  // WIN32
43 #endif
44
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"
50
51 // Protect against max macro inclusion.
52 #undef max
53
54 namespace talk_base {
55
56 // Base class for RNG implementations.
57 class RandomGenerator {
58  public:
59   virtual ~RandomGenerator() {}
60   virtual bool Init(const void* seed, size_t len) = 0;
61   virtual bool Generate(void* buf, size_t len) = 0;
62 };
63
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 {
67  public:
68   SecureRandomGenerator() : inited_(false) {
69   }
70   ~SecureRandomGenerator() {
71   }
72   virtual bool Init(const void* seed, size_t len) {
73     // By default, seed from the system state.
74     if (!inited_) {
75       if (RAND_poll() <= 0) {
76         return false;
77       }
78       inited_ = true;
79     }
80     // Allow app data to be mixed in, if provided.
81     if (seed) {
82       RAND_seed(seed, len);
83     }
84     return true;
85   }
86   virtual bool Generate(void* buf, size_t len) {
87     if (!inited_ && !Init(NULL, 0)) {
88       return false;
89     }
90     return (RAND_bytes(reinterpret_cast<unsigned char*>(buf), len) > 0);
91   }
92
93  private:
94   bool inited_;
95 };
96
97 #elif defined(SSL_USE_NSS_RNG)
98 // The NSS RNG.
99 class SecureRandomGenerator : public RandomGenerator {
100  public:
101   SecureRandomGenerator() {}
102   ~SecureRandomGenerator() {}
103   virtual bool Init(const void* seed, size_t len) {
104     return true;
105   }
106   virtual bool Generate(void* buf, size_t len) {
107     return (PK11_GenerateRandom(reinterpret_cast<unsigned char*>(buf),
108                                 static_cast<int>(len)) == SECSuccess);
109   }
110 };
111
112 #else
113 #ifdef WIN32
114 class SecureRandomGenerator : public RandomGenerator {
115  public:
116   SecureRandomGenerator() : advapi32_(NULL), rtl_gen_random_(NULL) {}
117   ~SecureRandomGenerator() {
118     FreeLibrary(advapi32_);
119   }
120
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_) {
126       return true;
127     }
128
129     advapi32_ = LoadLibrary(L"advapi32.dll");
130     if (!advapi32_) {
131       return false;
132     }
133
134     rtl_gen_random_ = reinterpret_cast<RtlGenRandomProc>(
135         GetProcAddress(advapi32_, "SystemFunction036"));
136     if (!rtl_gen_random_) {
137       FreeLibrary(advapi32_);
138       return false;
139     }
140
141     return true;
142   }
143   virtual bool Generate(void* buf, size_t len) {
144     if (!rtl_gen_random_ && !Init(NULL, 0)) {
145       return false;
146     }
147     return (rtl_gen_random_(buf, static_cast<int>(len)) != FALSE);
148   }
149
150  private:
151   typedef BOOL (WINAPI *RtlGenRandomProc)(PVOID, ULONG);
152   HINSTANCE advapi32_;
153   RtlGenRandomProc rtl_gen_random_;
154 };
155
156 #else
157
158 #error No SSL implementation has been selected!
159
160 #endif  // WIN32
161 #endif
162
163 // A test random generator, for predictable output.
164 class TestRandomGenerator : public RandomGenerator {
165  public:
166   TestRandomGenerator() : seed_(7) {
167   }
168   ~TestRandomGenerator() {
169   }
170   virtual bool Init(const void* seed, size_t len) {
171     return true;
172   }
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());
176     }
177     return true;
178   }
179
180  private:
181   int GetRandom() {
182     return ((seed_ = seed_ * 214013L + 2531011L) >> 16) & 0x7fff;
183   }
184   int seed_;
185 };
186
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', '+', '/'
194 };
195
196 namespace {
197
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()));
203   return global_rng;
204 }
205
206 RandomGenerator& Rng() {
207   return *GetGlobalRng();
208 }
209
210 }  // namespace
211
212 void SetRandomTestMode(bool test) {
213   if (!test) {
214     GetGlobalRng().reset(new SecureRandomGenerator());
215   } else {
216     GetGlobalRng().reset(new TestRandomGenerator());
217   }
218 }
219
220 bool InitRandom(int seed) {
221   return InitRandom(reinterpret_cast<const char*>(&seed), sizeof(seed));
222 }
223
224 bool InitRandom(const char* seed, size_t len) {
225   if (!Rng().Init(seed, len)) {
226     LOG(LS_ERROR) << "Failed to init random generator!";
227     return false;
228   }
229   return true;
230 }
231
232 std::string CreateRandomString(size_t len) {
233   std::string str;
234   CreateRandomString(len, &str);
235   return str;
236 }
237
238 bool CreateRandomString(size_t len,
239                         const char* table, int table_size,
240                         std::string* str) {
241   str->clear();
242   scoped_ptr<uint8[]> bytes(new uint8[len]);
243   if (!Rng().Generate(bytes.get(), len)) {
244     LOG(LS_ERROR) << "Failed to generate random string!";
245     return false;
246   }
247   str->reserve(len);
248   for (size_t i = 0; i < len; ++i) {
249     str->push_back(table[bytes[i] % table_size]);
250   }
251   return true;
252 }
253
254 bool CreateRandomString(size_t len, std::string* str) {
255   return CreateRandomString(len, BASE64, 64, str);
256 }
257
258 bool CreateRandomString(size_t len, const std::string& table,
259                         std::string* str) {
260   return CreateRandomString(len, table.c_str(),
261                             static_cast<int>(table.size()), str);
262 }
263
264 uint32 CreateRandomId() {
265   uint32 id;
266   if (!Rng().Generate(&id, sizeof(id))) {
267     LOG(LS_ERROR) << "Failed to generate random id!";
268   }
269   return id;
270 }
271
272 uint64 CreateRandomId64() {
273   return static_cast<uint64>(CreateRandomId()) << 32 | CreateRandomId();
274 }
275
276 uint32 CreateRandomNonZeroId() {
277   uint32 id;
278   do {
279     id = CreateRandomId();
280   } while (id == 0);
281   return id;
282 }
283
284 double CreateRandomDouble() {
285   return CreateRandomId() / (std::numeric_limits<uint32>::max() +
286       std::numeric_limits<double>::epsilon());
287 }
288
289 }  // namespace talk_base