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
44class ARC4Stream {
45public:
46    ARC4Stream();
47
48    uint8_t i;
49    uint8_t j;
50    uint8_t s[256];
51};
52
53class ARC4RandomNumberGenerator {
54public:
55    ARC4RandomNumberGenerator();
56
57    uint32_t randomNumber();
58    void randomValues(void* buffer, size_t length);
59
60private:
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(JSC_MULTIPLE_THREADS)
70    Mutex m_mutex;
71#endif
72};
73
74ARC4Stream::ARC4Stream()
75{
76    for (int n = 0; n < 256; n++)
77        s[n] = n;
78    i = 0;
79    j = 0;
80}
81
82ARC4RandomNumberGenerator::ARC4RandomNumberGenerator()
83    : m_count(0)
84{
85}
86
87void 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
100void 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
114void ARC4RandomNumberGenerator::stirIfNeeded()
115{
116    if (m_count <= 0)
117        stir();
118}
119
120uint8_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
131uint32_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
141uint32_t ARC4RandomNumberGenerator::randomNumber()
142{
143#if ENABLE(JSC_MULTIPLE_THREADS)
144    MutexLocker locker(m_mutex);
145#endif
146
147    m_count -= 4;
148    stirIfNeeded();
149    return getWord();
150}
151
152void ARC4RandomNumberGenerator::randomValues(void* buffer, size_t length)
153{
154#if ENABLE(JSC_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
167ARC4RandomNumberGenerator& sharedRandomNumberGenerator()
168{
169    DEFINE_STATIC_LOCAL(ARC4RandomNumberGenerator, randomNumberGenerator, ());
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#endif
186
187}
188