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