2de8201d57fec2e9fe694b8db6113ed2b5ff134c
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / wtf / CryptographicallyRandomNumber.cpp
1 /*
2  * Copyright (c) 1996, David Mazieres <dm@uun.org>
3  * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /*
19  * Arc4 random number generator for OpenBSD.
20  *
21  * This code is derived from section 17.1 of Applied Cryptography,
22  * second edition, which describes a stream cipher allegedly
23  * compatible with RSA Labs "RC4" cipher (the actual description of
24  * which is a trade secret).  The same algorithm is used as a stream
25  * cipher called "arcfour" in Tatu Ylonen's ssh package.
26  *
27  * RC4 is a registered trademark of RSA Laboratories.
28  */
29
30 #include "config.h"
31 #include "wtf/CryptographicallyRandomNumber.h"
32
33 #include "wtf/StdLibExtras.h"
34 #include "wtf/Threading.h"
35 #include "wtf/ThreadingPrimitives.h"
36
37 namespace WTF {
38
39 static RandomNumberSource sourceFunction;
40
41 void setRandomSource(RandomNumberSource source)
42 {
43     sourceFunction = source;
44 }
45
46 namespace {
47
48 class ARC4Stream {
49 public:
50     ARC4Stream();
51
52     uint8_t i;
53     uint8_t j;
54     uint8_t s[256];
55 };
56
57 class ARC4RandomNumberGenerator {
58     WTF_MAKE_FAST_ALLOCATED;
59 public:
60     ARC4RandomNumberGenerator();
61
62     uint32_t randomNumber();
63     void randomValues(void* buffer, size_t length);
64
65 private:
66     inline void addRandomData(unsigned char *data, int length);
67     void stir();
68     void stirIfNeeded();
69     inline uint8_t getByte();
70     inline uint32_t getWord();
71
72     ARC4Stream m_stream;
73     int m_count;
74     Mutex m_mutex;
75 };
76
77 ARC4Stream::ARC4Stream()
78 {
79     for (int n = 0; n < 256; n++)
80         s[n] = n;
81     i = 0;
82     j = 0;
83 }
84
85 ARC4RandomNumberGenerator::ARC4RandomNumberGenerator()
86     : m_count(0)
87 {
88 }
89
90 void ARC4RandomNumberGenerator::addRandomData(unsigned char* data, int length)
91 {
92     m_stream.i--;
93     for (int n = 0; n < 256; n++) {
94         m_stream.i++;
95         uint8_t si = m_stream.s[m_stream.i];
96         m_stream.j += si + data[n % length];
97         m_stream.s[m_stream.i] = m_stream.s[m_stream.j];
98         m_stream.s[m_stream.j] = si;
99     }
100     m_stream.j = m_stream.i;
101 }
102
103 void ARC4RandomNumberGenerator::stir()
104 {
105     unsigned char randomness[128];
106     size_t length = sizeof(randomness);
107     (*sourceFunction)(randomness, length);
108     addRandomData(randomness, length);
109
110     // Discard early keystream, as per recommendations in:
111     // http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
112     for (int i = 0; i < 256; i++)
113         getByte();
114     m_count = 1600000;
115 }
116
117 void ARC4RandomNumberGenerator::stirIfNeeded()
118 {
119     if (m_count <= 0)
120         stir();
121 }
122
123 uint8_t ARC4RandomNumberGenerator::getByte()
124 {
125     m_stream.i++;
126     uint8_t si = m_stream.s[m_stream.i];
127     m_stream.j += si;
128     uint8_t sj = m_stream.s[m_stream.j];
129     m_stream.s[m_stream.i] = sj;
130     m_stream.s[m_stream.j] = si;
131     return (m_stream.s[(si + sj) & 0xff]);
132 }
133
134 uint32_t ARC4RandomNumberGenerator::getWord()
135 {
136     uint32_t val;
137     val = getByte() << 24;
138     val |= getByte() << 16;
139     val |= getByte() << 8;
140     val |= getByte();
141     return val;
142 }
143
144 uint32_t ARC4RandomNumberGenerator::randomNumber()
145 {
146     MutexLocker locker(m_mutex);
147
148     m_count -= 4;
149     stirIfNeeded();
150     return getWord();
151 }
152
153 void ARC4RandomNumberGenerator::randomValues(void* buffer, size_t length)
154 {
155     MutexLocker locker(m_mutex);
156
157     unsigned char* result = reinterpret_cast<unsigned char*>(buffer);
158     stirIfNeeded();
159     while (length--) {
160         m_count--;
161         stirIfNeeded();
162         result[length] = getByte();
163     }
164 }
165
166 ARC4RandomNumberGenerator& sharedRandomNumberGenerator()
167 {
168     AtomicallyInitializedStatic(ARC4RandomNumberGenerator*, randomNumberGenerator = new ARC4RandomNumberGenerator);
169     return *randomNumberGenerator;
170 }
171
172 }
173
174
175 uint32_t cryptographicallyRandomNumber()
176 {
177     return sharedRandomNumberGenerator().randomNumber();
178 }
179
180 void cryptographicallyRandomValues(void* buffer, size_t length)
181 {
182     sharedRandomNumberGenerator().randomValues(buffer, length);
183 }
184
185 }