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 "CryptographicallyRandomNumber.h"
32 
33 #include "MainThread.h"
34 #include "OSRandomSource.h"
35 #include "StdLibExtras.h"
36 #include "ThreadingPrimitives.h"
37 
38 namespace WTF {
39 
40 #if USE(OS_RANDOMNESS)
41 
42 namespace {
43 
44 class ARC4Stream {
45 public:
46     ARC4Stream();
47 
48     uint8_t i;
49     uint8_t j;
50     uint8_t s[256];
51 };
52 
53 class ARC4RandomNumberGenerator {
54 public:
55     ARC4RandomNumberGenerator();
56 
57     uint32_t randomNumber();
58     void randomValues(void* buffer, size_t length);
59 
60 private:
61     inline void addRandomData(unsigned char *data, int length);
62     void stir();
63     void stirIfNeeded();
64     inline uint8_t getByte();
65     inline uint32_t getWord();
66 
67     ARC4Stream m_stream;
68     int m_count;
69 #if ENABLE(WTF_MULTIPLE_THREADS)
70     Mutex m_mutex;
71 #endif
72 };
73 
ARC4Stream()74 ARC4Stream::ARC4Stream()
75 {
76     for (int n = 0; n < 256; n++)
77         s[n] = n;
78     i = 0;
79     j = 0;
80 }
81 
ARC4RandomNumberGenerator()82 ARC4RandomNumberGenerator::ARC4RandomNumberGenerator()
83     : m_count(0)
84 {
85 }
86 
addRandomData(unsigned char * data,int length)87 void ARC4RandomNumberGenerator::addRandomData(unsigned char* data, int length)
88 {
89     m_stream.i--;
90     for (int n = 0; n < 256; n++) {
91         m_stream.i++;
92         uint8_t si = m_stream.s[m_stream.i];
93         m_stream.j += si + data[n % length];
94         m_stream.s[m_stream.i] = m_stream.s[m_stream.j];
95         m_stream.s[m_stream.j] = si;
96     }
97     m_stream.j = m_stream.i;
98 }
99 
stir()100 void ARC4RandomNumberGenerator::stir()
101 {
102     unsigned char randomness[128];
103     size_t length = sizeof(randomness);
104     cryptographicallyRandomValuesFromOS(randomness, length);
105     addRandomData(randomness, length);
106 
107     // Discard early keystream, as per recommendations in:
108     // http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
109     for (int i = 0; i < 256; i++)
110         getByte();
111     m_count = 1600000;
112 }
113 
stirIfNeeded()114 void ARC4RandomNumberGenerator::stirIfNeeded()
115 {
116     if (m_count <= 0)
117         stir();
118 }
119 
getByte()120 uint8_t ARC4RandomNumberGenerator::getByte()
121 {
122     m_stream.i++;
123     uint8_t si = m_stream.s[m_stream.i];
124     m_stream.j += si;
125     uint8_t sj = m_stream.s[m_stream.j];
126     m_stream.s[m_stream.i] = sj;
127     m_stream.s[m_stream.j] = si;
128     return (m_stream.s[(si + sj) & 0xff]);
129 }
130 
getWord()131 uint32_t ARC4RandomNumberGenerator::getWord()
132 {
133     uint32_t val;
134     val = getByte() << 24;
135     val |= getByte() << 16;
136     val |= getByte() << 8;
137     val |= getByte();
138     return val;
139 }
140 
randomNumber()141 uint32_t ARC4RandomNumberGenerator::randomNumber()
142 {
143 #if ENABLE(WTF_MULTIPLE_THREADS)
144     MutexLocker locker(m_mutex);
145 #endif
146 
147     m_count -= 4;
148     stirIfNeeded();
149     return getWord();
150 }
151 
randomValues(void * buffer,size_t length)152 void ARC4RandomNumberGenerator::randomValues(void* buffer, size_t length)
153 {
154 #if ENABLE(WTF_MULTIPLE_THREADS)
155     MutexLocker locker(m_mutex);
156 #endif
157 
158     unsigned char* result = reinterpret_cast<unsigned char*>(buffer);
159     stirIfNeeded();
160     while (length--) {
161         m_count--;
162         stirIfNeeded();
163         result[length] = getByte();
164     }
165 }
166 
sharedRandomNumberGenerator()167 ARC4RandomNumberGenerator& sharedRandomNumberGenerator()
168 {
169     DEFINE_STATIC_LOCAL(ARC4RandomNumberGenerator, randomNumberGenerator, ());
170     return randomNumberGenerator;
171 }
172 
173 }
174 
cryptographicallyRandomNumber()175 uint32_t cryptographicallyRandomNumber()
176 {
177     return sharedRandomNumberGenerator().randomNumber();
178 }
179 
cryptographicallyRandomValues(void * buffer,size_t length)180 void cryptographicallyRandomValues(void* buffer, size_t length)
181 {
182     sharedRandomNumberGenerator().randomValues(buffer, length);
183 }
184 
185 #endif
186 
187 }
188