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