]> git.zerfleddert.de Git - proxmark3-svn/blame - client/jansson/hashtable_seed.c
Code improved for less memory
[proxmark3-svn] / client / jansson / hashtable_seed.c
CommitLineData
556826b5
OM
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
48static 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)
62static 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
100typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTA)(HCRYPTPROV *phProv, LPCSTR pszContainer, LPCSTR pszProvider, DWORD dwProvType, DWORD dwFlags);
101typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer);
102typedef BOOL (WINAPI *CRYPTRELEASECONTEXT)(HCRYPTPROV hProv, DWORD dwFlags);
103
104static 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() */
145static 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
166static uint32_t generate_seed() {
6a2bd857 167 uint32_t seed = 0;
556826b5
OM
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
194volatile uint32_t hashtable_seed = 0;
195
196#if defined(HAVE_ATOMIC_BUILTINS) && (defined(HAVE_SCHED_YIELD) || !defined(_WIN32))
197static volatile char seed_initialized = 0;
198
199void 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))
220void 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)
246static long seed_initialized = 0;
247void 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 */
267void 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