2 * Copyright (c) 1996, David Mazieres <dm@uun.org>
3 * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
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.
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.
19 * Arc4 random number generator for OpenBSD.
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.
27 * RC4 is a registered trademark of RSA Laboratories.
31 #include "CryptographicallyRandomNumber.h"
33 #include "NeverDestroyed.h"
34 #include "OSRandomSource.h"
35 #include "ThreadingPrimitives.h"
50 class ARC4RandomNumberGenerator {
51 WTF_MAKE_FAST_ALLOCATED;
53 ARC4RandomNumberGenerator();
55 uint32_t randomNumber();
56 void randomValues(void* buffer, size_t length);
59 inline void addRandomData(unsigned char *data, int length);
62 inline uint8_t getByte();
63 inline uint32_t getWord();
70 ARC4Stream::ARC4Stream()
72 for (int n = 0; n < 256; n++)
78 ARC4RandomNumberGenerator::ARC4RandomNumberGenerator()
83 void ARC4RandomNumberGenerator::addRandomData(unsigned char* data, int length)
86 for (int n = 0; n < 256; n++) {
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;
93 m_stream.j = m_stream.i;
96 void ARC4RandomNumberGenerator::stir()
98 unsigned char randomness[128];
99 size_t length = sizeof(randomness);
100 cryptographicallyRandomValuesFromOS(randomness, length);
101 addRandomData(randomness, length);
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++)
110 void ARC4RandomNumberGenerator::stirIfNeeded()
116 uint8_t ARC4RandomNumberGenerator::getByte()
119 uint8_t si = m_stream.s[m_stream.i];
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]);
127 uint32_t ARC4RandomNumberGenerator::getWord()
130 val = getByte() << 24;
131 val |= getByte() << 16;
132 val |= getByte() << 8;
137 uint32_t ARC4RandomNumberGenerator::randomNumber()
139 MutexLocker locker(m_mutex);
146 void ARC4RandomNumberGenerator::randomValues(void* buffer, size_t length)
148 MutexLocker locker(m_mutex);
150 unsigned char* result = reinterpret_cast<unsigned char*>(buffer);
155 result[length] = getByte();
159 ARC4RandomNumberGenerator& sharedRandomNumberGenerator()
161 static NeverDestroyed<ARC4RandomNumberGenerator> randomNumberGenerator;
163 return randomNumberGenerator;
168 uint32_t cryptographicallyRandomNumber()
170 return sharedRandomNumberGenerator().randomNumber();
173 void cryptographicallyRandomValues(void* buffer, size_t length)
175 sharedRandomNumberGenerator().randomValues(buffer, length);