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