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