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