Use std::mutex instead of WTF::Mutex in WTF
[WebKit-https.git] / Source / WTF / wtf / CryptographicallyRandomNumber.cpp
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
37 namespace WTF {
38
39 namespace {
40
41 class ARC4Stream {
42 public:
43     ARC4Stream();
44
45     uint8_t i;
46     uint8_t j;
47     uint8_t s[256];
48 };
49
50 class ARC4RandomNumberGenerator {
51     WTF_MAKE_FAST_ALLOCATED;
52 public:
53     ARC4RandomNumberGenerator();
54
55     uint32_t randomNumber();
56     void randomValues(void* buffer, size_t length);
57
58 private:
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
70 ARC4Stream::ARC4Stream()
71 {
72     for (int n = 0; n < 256; n++)
73         s[n] = n;
74     i = 0;
75     j = 0;
76 }
77
78 ARC4RandomNumberGenerator::ARC4RandomNumberGenerator()
79     : m_count(0)
80 {
81 }
82
83 void 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
96 void 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
110 void ARC4RandomNumberGenerator::stirIfNeeded()
111 {
112     if (m_count <= 0)
113         stir();
114 }
115
116 uint8_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
127 uint32_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
137 uint32_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
146 void 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
159 ARC4RandomNumberGenerator& sharedRandomNumberGenerator()
160 {
161     static NeverDestroyed<ARC4RandomNumberGenerator> randomNumberGenerator;
162
163     return randomNumberGenerator;
164 }
165
166 }
167
168 uint32_t cryptographicallyRandomNumber()
169 {
170     return sharedRandomNumberGenerator().randomNumber();
171 }
172
173 void cryptographicallyRandomValues(void* buffer, size_t length)
174 {
175     sharedRandomNumberGenerator().randomValues(buffer, length);
176 }
177
178 }