OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 1996, David Mazieres <dm@uun.org> | 2 * Copyright (c) 1996, David Mazieres <dm@uun.org> |
3 * Copyright (c) 2008, Damien Miller <djm@openbsd.org> | 3 * Copyright (c) 2008, Damien Miller <djm@openbsd.org> |
4 * | 4 * |
5 * Permission to use, copy, modify, and distribute this software for any | 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 | 6 * purpose with or without fee is hereby granted, provided that the above |
7 * copyright notice and this permission notice appear in all copies. | 7 * copyright notice and this permission notice appear in all copies. |
8 * | 8 * |
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 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 | 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
16 */ | 16 */ |
17 | 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" | 18 #include "config.h" |
31 #include "wtf/CryptographicallyRandomNumber.h" | 19 #include "wtf/CryptographicallyRandomNumber.h" |
32 | 20 |
33 #include "wtf/StdLibExtras.h" | |
34 #include "wtf/Threading.h" | |
35 #include "wtf/ThreadingPrimitives.h" | |
36 | |
37 namespace WTF { | 21 namespace WTF { |
38 | 22 |
39 static RandomNumberSource sourceFunction; | 23 static RandomNumberSource sourceFunction; |
40 | 24 |
41 void setRandomSource(RandomNumberSource source) | 25 void setRandomSource(RandomNumberSource source) |
42 { | 26 { |
43 sourceFunction = source; | 27 sourceFunction = source; |
44 } | 28 } |
45 | 29 |
46 namespace { | |
47 | |
48 class ARC4Stream { | |
49 public: | |
50 ARC4Stream(); | |
51 | |
52 uint8_t i; | |
53 uint8_t j; | |
54 uint8_t s[256]; | |
55 }; | |
56 | |
57 class ARC4RandomNumberGenerator { | |
58 USING_FAST_MALLOC(ARC4RandomNumberGenerator); | |
59 public: | |
60 ARC4RandomNumberGenerator(); | |
61 | |
62 uint32_t randomNumber(); | |
63 void randomValues(void* buffer, size_t length); | |
64 | |
65 private: | |
66 inline void addRandomData(unsigned char *data, int length); | |
67 void stir(); | |
68 void stirIfNeeded(); | |
69 inline uint8_t getByte(); | |
70 inline uint32_t getWord(); | |
71 | |
72 ARC4Stream m_stream; | |
73 int m_count; | |
74 Mutex m_mutex; | |
75 }; | |
76 | |
77 ARC4Stream::ARC4Stream() | |
78 { | |
79 for (int n = 0; n < 256; n++) | |
80 s[n] = static_cast<uint8_t>(n); | |
81 i = 0; | |
82 j = 0; | |
83 } | |
84 | |
85 ARC4RandomNumberGenerator::ARC4RandomNumberGenerator() | |
86 : m_count(0) | |
87 { | |
88 } | |
89 | |
90 void ARC4RandomNumberGenerator::addRandomData(unsigned char* data, int length) | |
91 { | |
92 m_stream.i--; | |
93 for (int n = 0; n < 256; n++) { | |
94 m_stream.i++; | |
95 uint8_t si = m_stream.s[m_stream.i]; | |
96 m_stream.j += si + data[n % length]; | |
97 m_stream.s[m_stream.i] = m_stream.s[m_stream.j]; | |
98 m_stream.s[m_stream.j] = si; | |
99 } | |
100 m_stream.j = m_stream.i; | |
101 } | |
102 | |
103 void ARC4RandomNumberGenerator::stir() | |
104 { | |
105 unsigned char randomness[128]; | |
106 size_t length = sizeof(randomness); | |
107 (*sourceFunction)(randomness, length); | |
108 addRandomData(randomness, length); | |
109 | |
110 // Discard early keystream, as per recommendations in: | |
111 // http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps | |
112 for (int i = 0; i < 256; i++) | |
113 getByte(); | |
114 m_count = 1600000; | |
115 } | |
116 | |
117 void ARC4RandomNumberGenerator::stirIfNeeded() | |
118 { | |
119 if (m_count <= 0) | |
120 stir(); | |
121 } | |
122 | |
123 uint8_t ARC4RandomNumberGenerator::getByte() | |
124 { | |
125 m_stream.i++; | |
126 uint8_t si = m_stream.s[m_stream.i]; | |
127 m_stream.j += si; | |
128 uint8_t sj = m_stream.s[m_stream.j]; | |
129 m_stream.s[m_stream.i] = sj; | |
130 m_stream.s[m_stream.j] = si; | |
131 return (m_stream.s[(si + sj) & 0xff]); | |
132 } | |
133 | |
134 uint32_t ARC4RandomNumberGenerator::getWord() | |
135 { | |
136 uint32_t val; | |
137 val = getByte() << 24; | |
138 val |= getByte() << 16; | |
139 val |= getByte() << 8; | |
140 val |= getByte(); | |
141 return val; | |
142 } | |
143 | |
144 uint32_t ARC4RandomNumberGenerator::randomNumber() | |
145 { | |
146 MutexLocker locker(m_mutex); | |
147 | |
148 m_count -= 4; | |
149 stirIfNeeded(); | |
150 return getWord(); | |
151 } | |
152 | |
153 void ARC4RandomNumberGenerator::randomValues(void* buffer, size_t length) | |
154 { | |
155 MutexLocker locker(m_mutex); | |
156 | |
157 unsigned char* result = reinterpret_cast<unsigned char*>(buffer); | |
158 stirIfNeeded(); | |
159 while (length--) { | |
160 m_count--; | |
161 stirIfNeeded(); | |
162 result[length] = getByte(); | |
163 } | |
164 } | |
165 | |
166 ARC4RandomNumberGenerator& sharedRandomNumberGenerator() | |
167 { | |
168 AtomicallyInitializedStaticReference(ARC4RandomNumberGenerator, randomNumber
Generator, new ARC4RandomNumberGenerator); | |
169 return randomNumberGenerator; | |
170 } | |
171 | |
172 } | |
173 | |
174 | |
175 uint32_t cryptographicallyRandomNumber() | 30 uint32_t cryptographicallyRandomNumber() |
176 { | 31 { |
177 return sharedRandomNumberGenerator().randomNumber(); | 32 uint32_t result; |
| 33 cryptographicallyRandomValues(&result, sizeof(result)); |
| 34 return result; |
178 } | 35 } |
179 | 36 |
180 void cryptographicallyRandomValues(void* buffer, size_t length) | 37 void cryptographicallyRandomValues(void* buffer, size_t length) |
181 { | 38 { |
182 sharedRandomNumberGenerator().randomValues(buffer, length); | 39 (*sourceFunction)(reinterpret_cast<unsigned char*>(buffer), length); |
183 } | 40 } |
184 | 41 |
185 } | 42 } |
OLD | NEW |