Merge pull request #969 from pwpiwi/gcc10_fixes
[legacy-proxmark3.git] / client / jansson / hashtable_seed.c
blob540358ada785a6e535b65bd945a1f705cf43a46e
1 /* Generate sizeof(uint32_t) bytes of as random data as possible to seed
2 the hash function.
3 */
5 #ifdef HAVE_CONFIG_H
6 #include <jansson_private_config.h>
7 #endif
9 #include <stdio.h>
10 #include <time.h>
12 #ifdef HAVE_STDINT_H
13 #include <stdint.h>
14 #endif
16 #ifdef HAVE_FCNTL_H
17 #include <fcntl.h>
18 #endif
20 #ifdef HAVE_SCHED_H
21 #include <sched.h>
22 #endif
24 #ifdef HAVE_UNISTD_H
25 #include <unistd.h>
26 #endif
28 #ifdef HAVE_SYS_STAT_H
29 #include <sys/stat.h>
30 #endif
32 #ifdef HAVE_SYS_TIME_H
33 #include <sys/time.h>
34 #endif
36 #ifdef HAVE_SYS_TYPES_H
37 #include <sys/types.h>
38 #endif
40 #if defined(_WIN32)
41 /* For GetModuleHandle(), GetProcAddress() and GetCurrentProcessId() */
42 #include <windows.h>
43 #endif
45 #include "jansson.h"
48 static uint32_t buf_to_uint32(char *data) {
49 size_t i;
50 uint32_t result = 0;
52 for (i = 0; i < sizeof(uint32_t); i++)
53 result = (result << 8) | (unsigned char)data[i];
55 return result;
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() */
66 char data[sizeof(uint32_t)];
67 int ok;
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;
75 ok = read(urandom, data, sizeof(uint32_t)) == sizeof(uint32_t);
76 close(urandom);
77 #else
78 FILE *urandom;
80 urandom = fopen("/dev/urandom", "rb");
81 if (!urandom)
82 return 1;
84 ok = fread(data, 1, sizeof(uint32_t), urandom) == sizeof(uint32_t);
85 fclose(urandom);
86 #endif
88 if (!ok)
89 return 1;
91 *seed = buf_to_uint32(data);
92 return 0;
94 #endif
96 /* Windows Crypto API */
97 #if defined(_WIN32) && defined(USE_WINDOWS_CRYPTOAPI)
98 #include <wincrypt.h>
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);
104 static int seed_from_windows_cryptoapi(uint32_t *seed)
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;
114 hAdvAPI32 = GetModuleHandle(TEXT("advapi32.dll"));
115 if(hAdvAPI32 == NULL)
116 return 1;
118 pCryptAcquireContext = (CRYPTACQUIRECONTEXTA)GetProcAddress(hAdvAPI32, "CryptAcquireContextA");
119 if (!pCryptAcquireContext)
120 return 1;
122 pCryptGenRandom = (CRYPTGENRANDOM)GetProcAddress(hAdvAPI32, "CryptGenRandom");
123 if (!pCryptGenRandom)
124 return 1;
126 pCryptReleaseContext = (CRYPTRELEASECONTEXT)GetProcAddress(hAdvAPI32, "CryptReleaseContext");
127 if (!pCryptReleaseContext)
128 return 1;
130 if (!pCryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
131 return 1;
133 ok = pCryptGenRandom(hCryptProv, sizeof(uint32_t), data);
134 pCryptReleaseContext(hCryptProv, 0);
136 if (!ok)
137 return 1;
139 *seed = buf_to_uint32((char *)data);
140 return 0;
142 #endif
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
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
163 return 0;
166 static uint32_t generate_seed() {
167 uint32_t seed = 0;
168 int done = 0;
170 #if !defined(_WIN32) && defined(USE_URANDOM)
171 if (seed_from_urandom(&seed) == 0)
172 done = 1;
173 #endif
175 #if defined(_WIN32) && defined(USE_WINDOWS_CRYPTOAPI)
176 if (seed_from_windows_cryptoapi(&seed) == 0)
177 done = 1;
178 #endif
180 if (!done) {
181 /* Fall back to timestamp and PID if no better randomness is
182 available */
183 seed_from_timestamp_and_pid(&seed);
186 /* Make sure the seed is never zero */
187 if (seed == 0)
188 seed = 1;
190 return seed;
194 volatile uint32_t hashtable_seed = 0;
196 #if defined(HAVE_ATOMIC_BUILTINS) && (defined(HAVE_SCHED_YIELD) || !defined(_WIN32))
197 static volatile char seed_initialized = 0;
199 void json_object_seed(size_t seed) {
200 uint32_t new_seed = (uint32_t)seed;
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();
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);
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;
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.
229 new_seed = generate_seed();
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
242 } while(hashtable_seed == 0);
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;
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();
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);
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;
270 if (hashtable_seed == 0) {
271 if (new_seed == 0)
272 new_seed = generate_seed();
274 hashtable_seed = new_seed;
277 #endif