]> git.zerfleddert.de Git - proxmark3-svn/blob - client/jansson/hashtable_seed.c
8aed54068f96ada1f3951da6e836c8431ce9378c
[proxmark3-svn] / client / jansson / hashtable_seed.c
1 /* Generate sizeof(uint32_t) bytes of as random data as possible to seed
2 the hash function.
3 */
4
5 #ifdef HAVE_CONFIG_H
6 #include <jansson_private_config.h>
7 #endif
8
9 #include <stdio.h>
10 #include <time.h>
11
12 #ifdef HAVE_STDINT_H
13 #include <stdint.h>
14 #endif
15
16 #ifdef HAVE_FCNTL_H
17 #include <fcntl.h>
18 #endif
19
20 #ifdef HAVE_SCHED_H
21 #include <sched.h>
22 #endif
23
24 #ifdef HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
27
28 #ifdef HAVE_SYS_STAT_H
29 #include <sys/stat.h>
30 #endif
31
32 #ifdef HAVE_SYS_TIME_H
33 #include <sys/time.h>
34 #endif
35
36 #ifdef HAVE_SYS_TYPES_H
37 #include <sys/types.h>
38 #endif
39
40 #if defined(_WIN32)
41 /* For GetModuleHandle(), GetProcAddress() and GetCurrentProcessId() */
42 #include <windows.h>
43 #endif
44
45 #include "jansson.h"
46
47
48 static uint32_t buf_to_uint32(char *data) {
49 size_t i;
50 uint32_t result = 0;
51
52 for (i = 0; i < sizeof(uint32_t); i++)
53 result = (result << 8) | (unsigned char)data[i];
54
55 return result;
56 }
57
58
59
60 /* /dev/urandom */
61 #if !defined(_WIN32) && defined(USE_URANDOM)
62 static int seed_from_urandom(uint32_t *seed) {
63 /* Use unbuffered I/O if we have open(), close() and read(). Otherwise
64 fall back to fopen() */
65
66 char data[sizeof(uint32_t)];
67 int ok;
68
69 #if defined(HAVE_OPEN) && defined(HAVE_CLOSE) && defined(HAVE_READ)
70 int urandom;
71 urandom = open("/dev/urandom", O_RDONLY);
72 if (urandom == -1)
73 return 1;
74
75 ok = read(urandom, data, sizeof(uint32_t)) == sizeof(uint32_t);
76 close(urandom);
77 #else
78 FILE *urandom;
79
80 urandom = fopen("/dev/urandom", "rb");
81 if (!urandom)
82 return 1;
83
84 ok = fread(data, 1, sizeof(uint32_t), urandom) == sizeof(uint32_t);
85 fclose(urandom);
86 #endif
87
88 if (!ok)
89 return 1;
90
91 *seed = buf_to_uint32(data);
92 return 0;
93 }
94 #endif
95
96 /* Windows Crypto API */
97 #if defined(_WIN32) && defined(USE_WINDOWS_CRYPTOAPI)
98 #include <wincrypt.h>
99
100 typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTA)(HCRYPTPROV *phProv, LPCSTR pszContainer, LPCSTR pszProvider, DWORD dwProvType, DWORD dwFlags);
101 typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer);
102 typedef BOOL (WINAPI *CRYPTRELEASECONTEXT)(HCRYPTPROV hProv, DWORD dwFlags);
103
104 static int seed_from_windows_cryptoapi(uint32_t *seed)
105 {
106 HINSTANCE hAdvAPI32 = NULL;
107 CRYPTACQUIRECONTEXTA pCryptAcquireContext = NULL;
108 CRYPTGENRANDOM pCryptGenRandom = NULL;
109 CRYPTRELEASECONTEXT pCryptReleaseContext = NULL;
110 HCRYPTPROV hCryptProv = 0;
111 BYTE data[sizeof(uint32_t)];
112 int ok;
113
114 hAdvAPI32 = GetModuleHandle(TEXT("advapi32.dll"));
115 if(hAdvAPI32 == NULL)
116 return 1;
117
118 pCryptAcquireContext = (CRYPTACQUIRECONTEXTA)GetProcAddress(hAdvAPI32, "CryptAcquireContextA");
119 if (!pCryptAcquireContext)
120 return 1;
121
122 pCryptGenRandom = (CRYPTGENRANDOM)GetProcAddress(hAdvAPI32, "CryptGenRandom");
123 if (!pCryptGenRandom)
124 return 1;
125
126 pCryptReleaseContext = (CRYPTRELEASECONTEXT)GetProcAddress(hAdvAPI32, "CryptReleaseContext");
127 if (!pCryptReleaseContext)
128 return 1;
129
130 if (!pCryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
131 return 1;
132
133 ok = pCryptGenRandom(hCryptProv, sizeof(uint32_t), data);
134 pCryptReleaseContext(hCryptProv, 0);
135
136 if (!ok)
137 return 1;
138
139 *seed = buf_to_uint32((char *)data);
140 return 0;
141 }
142 #endif
143
144 /* gettimeofday() and getpid() */
145 static int seed_from_timestamp_and_pid(uint32_t *seed) {
146 #ifdef HAVE_GETTIMEOFDAY
147 /* XOR of seconds and microseconds */
148 struct timeval tv;
149 gettimeofday(&tv, NULL);
150 *seed = (uint32_t)tv.tv_sec ^ (uint32_t)tv.tv_usec;
151 #else
152 /* Seconds only */
153 *seed = (uint32_t)time(NULL);
154 #endif
155
156 /* XOR with PID for more randomness */
157 #if defined(_WIN32)
158 *seed ^= (uint32_t)GetCurrentProcessId();
159 #elif defined(HAVE_GETPID)
160 *seed ^= (uint32_t)getpid();
161 #endif
162
163 return 0;
164 }
165
166 static uint32_t generate_seed() {
167 uint32_t seed;
168 int done = 0;
169
170 #if !defined(_WIN32) && defined(USE_URANDOM)
171 if (seed_from_urandom(&seed) == 0)
172 done = 1;
173 #endif
174
175 #if defined(_WIN32) && defined(USE_WINDOWS_CRYPTOAPI)
176 if (seed_from_windows_cryptoapi(&seed) == 0)
177 done = 1;
178 #endif
179
180 if (!done) {
181 /* Fall back to timestamp and PID if no better randomness is
182 available */
183 seed_from_timestamp_and_pid(&seed);
184 }
185
186 /* Make sure the seed is never zero */
187 if (seed == 0)
188 seed = 1;
189
190 return seed;
191 }
192
193
194 volatile uint32_t hashtable_seed = 0;
195
196 #if defined(HAVE_ATOMIC_BUILTINS) && (defined(HAVE_SCHED_YIELD) || !defined(_WIN32))
197 static volatile char seed_initialized = 0;
198
199 void json_object_seed(size_t seed) {
200 uint32_t new_seed = (uint32_t)seed;
201
202 if (hashtable_seed == 0) {
203 if (__atomic_test_and_set(&seed_initialized, __ATOMIC_RELAXED) == 0) {
204 /* Do the seeding ourselves */
205 if (new_seed == 0)
206 new_seed = generate_seed();
207
208 __atomic_store_n(&hashtable_seed, new_seed, __ATOMIC_RELEASE);
209 } else {
210 /* Wait for another thread to do the seeding */
211 do {
212 #ifdef HAVE_SCHED_YIELD
213 sched_yield();
214 #endif
215 } while(__atomic_load_n(&hashtable_seed, __ATOMIC_ACQUIRE) == 0);
216 }
217 }
218 }
219 #elif defined(HAVE_SYNC_BUILTINS) && (defined(HAVE_SCHED_YIELD) || !defined(_WIN32))
220 void json_object_seed(size_t seed) {
221 uint32_t new_seed = (uint32_t)seed;
222
223 if (hashtable_seed == 0) {
224 if (new_seed == 0) {
225 /* Explicit synchronization fences are not supported by the
226 __sync builtins, so every thread getting here has to
227 generate the seed value.
228 */
229 new_seed = generate_seed();
230 }
231
232 do {
233 if (__sync_bool_compare_and_swap(&hashtable_seed, 0, new_seed)) {
234 /* We were the first to seed */
235 break;
236 } else {
237 /* Wait for another thread to do the seeding */
238 #ifdef HAVE_SCHED_YIELD
239 sched_yield();
240 #endif
241 }
242 } while(hashtable_seed == 0);
243 }
244 }
245 #elif defined(_WIN32)
246 static long seed_initialized = 0;
247 void json_object_seed(size_t seed) {
248 uint32_t new_seed = (uint32_t)seed;
249
250 if (hashtable_seed == 0) {
251 if (InterlockedIncrement(&seed_initialized) == 1) {
252 /* Do the seeding ourselves */
253 if (new_seed == 0)
254 new_seed = generate_seed();
255
256 hashtable_seed = new_seed;
257 } else {
258 /* Wait for another thread to do the seeding */
259 do {
260 SwitchToThread();
261 } while (hashtable_seed == 0);
262 }
263 }
264 }
265 #else
266 /* Fall back to a thread-unsafe version */
267 void json_object_seed(size_t seed) {
268 uint32_t new_seed = (uint32_t)seed;
269
270 if (hashtable_seed == 0) {
271 if (new_seed == 0)
272 new_seed = generate_seed();
273
274 hashtable_seed = new_seed;
275 }
276 }
277 #endif
Impressum, Datenschutz