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