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