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