diff options
Diffstat (limited to 'src/util/crypto_random.c')
-rw-r--r-- | src/util/crypto_random.c | 425 |
1 files changed, 0 insertions, 425 deletions
diff --git a/src/util/crypto_random.c b/src/util/crypto_random.c deleted file mode 100644 index dc2794554..000000000 --- a/src/util/crypto_random.c +++ /dev/null | |||
@@ -1,425 +0,0 @@ | |||
1 | /* | ||
2 | This file is part of GNUnet. Copyright (C) 2001-2014 Christian Grothoff | ||
3 | (and other contributing authors) | ||
4 | |||
5 | GNUnet is free software: you can redistribute it and/or modify it | ||
6 | under the terms of the GNU Affero General Public License as published | ||
7 | by the Free Software Foundation, either version 3 of the License, | ||
8 | or (at your option) any later version. | ||
9 | |||
10 | GNUnet is distributed in the hope that it will be useful, but | ||
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | Affero General Public License for more details. | ||
14 | |||
15 | You should have received a copy of the GNU Affero General Public License | ||
16 | along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
17 | |||
18 | SPDX-License-Identifier: AGPL3.0-or-later | ||
19 | |||
20 | */ | ||
21 | |||
22 | /** | ||
23 | * @file util/crypto_random.c | ||
24 | * @brief functions to gather random numbers | ||
25 | * @author Christian Grothoff | ||
26 | */ | ||
27 | #include "platform.h" | ||
28 | #include "gnunet_crypto_lib.h" | ||
29 | #include "gnunet_time_lib.h" | ||
30 | #include <gcrypt.h> | ||
31 | |||
32 | #define LOG(kind, ...) GNUNET_log_from (kind, "util-crypto-random", __VA_ARGS__) | ||
33 | |||
34 | #define LOG_STRERROR(kind, syscall) \ | ||
35 | GNUNET_log_from_strerror (kind, "util-crypto-random", syscall) | ||
36 | |||
37 | |||
38 | /* TODO: ndurner, move this to plibc? */ | ||
39 | /* The code is derived from glibc, obviously */ | ||
40 | #if ! HAVE_RANDOM || ! HAVE_SRANDOM | ||
41 | #ifdef RANDOM | ||
42 | #undef RANDOM | ||
43 | #endif | ||
44 | #ifdef SRANDOM | ||
45 | #undef SRANDOM | ||
46 | #endif | ||
47 | #define RANDOM() glibc_weak_rand32 () | ||
48 | #define SRANDOM(s) glibc_weak_srand32 (s) | ||
49 | #if defined(RAND_MAX) | ||
50 | #undef RAND_MAX | ||
51 | #endif | ||
52 | #define RAND_MAX 0x7fffffff /* Hopefully this is correct */ | ||
53 | |||
54 | |||
55 | static int32_t glibc_weak_rand32_state = 1; | ||
56 | |||
57 | |||
58 | void | ||
59 | glibc_weak_srand32 (int32_t s) | ||
60 | { | ||
61 | glibc_weak_rand32_state = s; | ||
62 | } | ||
63 | |||
64 | |||
65 | int32_t | ||
66 | glibc_weak_rand32 () | ||
67 | { | ||
68 | int32_t val = glibc_weak_rand32_state; | ||
69 | |||
70 | val = ((glibc_weak_rand32_state * 1103515245) + 12345) & 0x7fffffff; | ||
71 | glibc_weak_rand32_state = val; | ||
72 | return val; | ||
73 | } | ||
74 | |||
75 | |||
76 | #endif | ||
77 | |||
78 | /** | ||
79 | * Create a cryptographically weak pseudo-random number in the interval of 0 to 1. | ||
80 | * | ||
81 | * @return number between 0 and 1. | ||
82 | */ | ||
83 | static double | ||
84 | get_weak_random (void) | ||
85 | { | ||
86 | return((double) random () / RAND_MAX); | ||
87 | } | ||
88 | |||
89 | |||
90 | /** | ||
91 | * Seed a weak random generator. Only #GNUNET_CRYPTO_QUALITY_WEAK-mode generator | ||
92 | * can be seeded. | ||
93 | * | ||
94 | * @param seed the seed to use | ||
95 | */ | ||
96 | void | ||
97 | GNUNET_CRYPTO_seed_weak_random (int32_t seed) | ||
98 | { | ||
99 | #ifdef OPENBSD | ||
100 | srandom_deterministic (seed); | ||
101 | #else | ||
102 | srandom (seed); | ||
103 | #endif | ||
104 | } | ||
105 | |||
106 | |||
107 | /** | ||
108 | * @ingroup crypto | ||
109 | * Zero out @a buffer, securely against compiler optimizations. | ||
110 | * Used to delete key material. | ||
111 | * | ||
112 | * @param buffer the buffer to zap | ||
113 | * @param length buffer length | ||
114 | */ | ||
115 | void | ||
116 | GNUNET_CRYPTO_zero_keys (void *buffer, size_t length) | ||
117 | { | ||
118 | #if HAVE_MEMSET_S | ||
119 | memset_s (buffer, length, 0, length); | ||
120 | #elif HAVE_EXPLICIT_BZERO | ||
121 | explicit_bzero (buffer, length); | ||
122 | #else | ||
123 | volatile unsigned char *p = buffer; | ||
124 | while (length--) | ||
125 | *p++ = 0; | ||
126 | #endif | ||
127 | } | ||
128 | |||
129 | |||
130 | /** | ||
131 | * @ingroup crypto | ||
132 | * Fill block with a random values. | ||
133 | * | ||
134 | * @param mode desired quality of the random number | ||
135 | * @param buffer the buffer to fill | ||
136 | * @param length buffer length | ||
137 | */ | ||
138 | void | ||
139 | GNUNET_CRYPTO_random_block (enum GNUNET_CRYPTO_Quality mode, | ||
140 | void *buffer, | ||
141 | size_t length) | ||
142 | { | ||
143 | #ifdef gcry_fast_random_poll | ||
144 | static unsigned int invokeCount; | ||
145 | #endif | ||
146 | switch (mode) | ||
147 | { | ||
148 | case GNUNET_CRYPTO_QUALITY_STRONG: | ||
149 | /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */ | ||
150 | #ifdef gcry_fast_random_poll | ||
151 | if ((invokeCount++ % 256) == 0) | ||
152 | gcry_fast_random_poll (); | ||
153 | #endif | ||
154 | gcry_randomize (buffer, length, GCRY_STRONG_RANDOM); | ||
155 | return; | ||
156 | |||
157 | case GNUNET_CRYPTO_QUALITY_NONCE: | ||
158 | gcry_create_nonce (buffer, length); | ||
159 | return; | ||
160 | |||
161 | case GNUNET_CRYPTO_QUALITY_WEAK: | ||
162 | /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */ | ||
163 | #ifdef gcry_fast_random_poll | ||
164 | if ((invokeCount++ % 256) == 0) | ||
165 | gcry_fast_random_poll (); | ||
166 | #endif | ||
167 | gcry_randomize (buffer, length, GCRY_WEAK_RANDOM); | ||
168 | return; | ||
169 | |||
170 | default: | ||
171 | GNUNET_assert (0); | ||
172 | } | ||
173 | } | ||
174 | |||
175 | |||
176 | /** | ||
177 | * Produce a random unsigned 32-bit number modulo @a i. | ||
178 | * | ||
179 | * @param mode desired quality of the random number | ||
180 | * @param i the upper limit (exclusive) for the random number | ||
181 | * @return a random value in the interval [0,i[. | ||
182 | */ | ||
183 | uint32_t | ||
184 | GNUNET_CRYPTO_random_u32 (enum GNUNET_CRYPTO_Quality mode, | ||
185 | uint32_t i) | ||
186 | { | ||
187 | #ifdef gcry_fast_random_poll | ||
188 | static unsigned int invokeCount; | ||
189 | #endif | ||
190 | uint32_t ret; | ||
191 | uint32_t ul; | ||
192 | |||
193 | GNUNET_assert (i > 0); | ||
194 | |||
195 | switch (mode) | ||
196 | { | ||
197 | case GNUNET_CRYPTO_QUALITY_STRONG: | ||
198 | /* see http://lists.gnupg.org/pipermail/gcrypt-devel/2004-May/000613.html */ | ||
199 | #ifdef gcry_fast_random_poll | ||
200 | if ((invokeCount++ % 256) == 0) | ||
201 | gcry_fast_random_poll (); | ||
202 | #endif | ||
203 | ul = UINT32_MAX - (UINT32_MAX % i); | ||
204 | do | ||
205 | { | ||
206 | gcry_randomize ((unsigned char *) &ret, | ||
207 | sizeof(uint32_t), | ||
208 | GCRY_STRONG_RANDOM); | ||
209 | } | ||
210 | while (ret >= ul); | ||
211 | return ret % i; | ||
212 | |||
213 | case GNUNET_CRYPTO_QUALITY_NONCE: | ||
214 | ul = UINT32_MAX - (UINT32_MAX % i); | ||
215 | do | ||
216 | { | ||
217 | gcry_create_nonce (&ret, sizeof(ret)); | ||
218 | } | ||
219 | while (ret >= ul); | ||
220 | return ret % i; | ||
221 | |||
222 | case GNUNET_CRYPTO_QUALITY_WEAK: | ||
223 | ret = i * get_weak_random (); | ||
224 | if (ret >= i) | ||
225 | ret = i - 1; | ||
226 | return ret; | ||
227 | |||
228 | default: | ||
229 | GNUNET_assert (0); | ||
230 | } | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | |||
235 | /** | ||
236 | * Get an array with a random permutation of the | ||
237 | * numbers 0...n-1. | ||
238 | * @param mode #GNUNET_RANDOM_QUALITY_STRONG if the strong (but expensive) | ||
239 | * PRNG should be used, #GNUNET_RANDOM_QUALITY_WEAK otherwise | ||
240 | * @param n the size of the array | ||
241 | * @return the permutation array (allocated from heap) | ||
242 | */ | ||
243 | unsigned int * | ||
244 | GNUNET_CRYPTO_random_permute (enum GNUNET_CRYPTO_Quality mode, | ||
245 | unsigned int n) | ||
246 | { | ||
247 | unsigned int *ret; | ||
248 | unsigned int i; | ||
249 | unsigned int tmp; | ||
250 | uint32_t x; | ||
251 | |||
252 | GNUNET_assert (n > 0); | ||
253 | ret = GNUNET_malloc (n * sizeof(unsigned int)); | ||
254 | for (i = 0; i < n; i++) | ||
255 | ret[i] = i; | ||
256 | for (i = n - 1; i > 0; i--) | ||
257 | { | ||
258 | x = GNUNET_CRYPTO_random_u32 (mode, i + 1); | ||
259 | tmp = ret[x]; | ||
260 | ret[x] = ret[i]; | ||
261 | ret[i] = tmp; | ||
262 | } | ||
263 | return ret; | ||
264 | } | ||
265 | |||
266 | |||
267 | /** | ||
268 | * Generate random unsigned 64-bit value. | ||
269 | * | ||
270 | * @param mode desired quality of the random number | ||
271 | * @param max value returned will be in range [0,max) (exclusive) | ||
272 | * @return random 64-bit number | ||
273 | */ | ||
274 | uint64_t | ||
275 | GNUNET_CRYPTO_random_u64 (enum GNUNET_CRYPTO_Quality mode, | ||
276 | uint64_t max) | ||
277 | { | ||
278 | uint64_t ret; | ||
279 | uint64_t ul; | ||
280 | |||
281 | GNUNET_assert (max > 0); | ||
282 | switch (mode) | ||
283 | { | ||
284 | case GNUNET_CRYPTO_QUALITY_STRONG: | ||
285 | ul = UINT64_MAX - (UINT64_MAX % max); | ||
286 | do | ||
287 | { | ||
288 | gcry_randomize ((unsigned char *) &ret, | ||
289 | sizeof(uint64_t), | ||
290 | GCRY_STRONG_RANDOM); | ||
291 | } | ||
292 | while (ret >= ul); | ||
293 | return ret % max; | ||
294 | |||
295 | case GNUNET_CRYPTO_QUALITY_NONCE: | ||
296 | ul = UINT64_MAX - (UINT64_MAX % max); | ||
297 | do | ||
298 | { | ||
299 | gcry_create_nonce (&ret, sizeof(ret)); | ||
300 | } | ||
301 | while (ret >= ul); | ||
302 | |||
303 | return ret % max; | ||
304 | |||
305 | case GNUNET_CRYPTO_QUALITY_WEAK: | ||
306 | ret = max * get_weak_random (); | ||
307 | if (ret >= max) | ||
308 | ret = max - 1; | ||
309 | return ret; | ||
310 | |||
311 | default: | ||
312 | GNUNET_assert (0); | ||
313 | } | ||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | |||
318 | /** | ||
319 | * @ingroup crypto | ||
320 | * Fill UUID with a timeflake pseudo-random value. Note that | ||
321 | * timeflakes use only 80 bits of randomness and 48 bits | ||
322 | * to encode a timestamp in milliseconds. So what we return | ||
323 | * here is not a completely random number. | ||
324 | * | ||
325 | * @param mode desired quality of the random number | ||
326 | * @param uuid the value to fill | ||
327 | */ | ||
328 | void | ||
329 | GNUNET_CRYPTO_random_timeflake (enum GNUNET_CRYPTO_Quality mode, | ||
330 | struct GNUNET_Uuid *uuid) | ||
331 | { | ||
332 | struct GNUNET_TIME_Absolute now; | ||
333 | uint64_t ms; | ||
334 | uint64_t be; | ||
335 | char *base; | ||
336 | |||
337 | GNUNET_CRYPTO_random_block (mode, | ||
338 | uuid, | ||
339 | sizeof (struct GNUNET_Uuid)); | ||
340 | now = GNUNET_TIME_absolute_get (); | ||
341 | ms = now.abs_value_us / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us; | ||
342 | be = GNUNET_htonll (ms); | ||
343 | base = (char *) &be; | ||
344 | memcpy (uuid, | ||
345 | base + 2, | ||
346 | sizeof (be) - 2); | ||
347 | } | ||
348 | |||
349 | |||
350 | /** | ||
351 | * Allocation wrapper for libgcrypt, used to avoid bad locking | ||
352 | * strategy of libgcrypt implementation. | ||
353 | */ | ||
354 | static void * | ||
355 | w_malloc (size_t n) | ||
356 | { | ||
357 | return calloc (n, 1); | ||
358 | } | ||
359 | |||
360 | |||
361 | /** | ||
362 | * Allocation wrapper for libgcrypt, used to avoid bad locking | ||
363 | * strategy of libgcrypt implementation. | ||
364 | */ | ||
365 | static int | ||
366 | w_check (const void *p) | ||
367 | { | ||
368 | (void) p; | ||
369 | return 0; /* not secure memory */ | ||
370 | } | ||
371 | |||
372 | |||
373 | /** | ||
374 | * Initialize libgcrypt. | ||
375 | */ | ||
376 | void __attribute__ ((constructor)) | ||
377 | GNUNET_CRYPTO_random_init () | ||
378 | { | ||
379 | gcry_error_t rc; | ||
380 | |||
381 | if (! gcry_check_version (NEED_LIBGCRYPT_VERSION)) | ||
382 | { | ||
383 | fprintf ( | ||
384 | stderr, | ||
385 | _ ("libgcrypt has not the expected version (version %s is required).\n"), | ||
386 | NEED_LIBGCRYPT_VERSION); | ||
387 | GNUNET_assert (0); | ||
388 | } | ||
389 | /* set custom allocators */ | ||
390 | gcry_set_allocation_handler (&w_malloc, &w_malloc, &w_check, &realloc, &free); | ||
391 | /* Disable use of secure memory */ | ||
392 | if ((rc = gcry_control (GCRYCTL_DISABLE_SECMEM, 0))) | ||
393 | fprintf (stderr, | ||
394 | "Failed to set libgcrypt option %s: %s\n", | ||
395 | "DISABLE_SECMEM", | ||
396 | gcry_strerror (rc)); | ||
397 | /* Otherwise gnunet-ecc takes forever to complete, besides | ||
398 | we are fine with "just" using GCRY_STRONG_RANDOM */ | ||
399 | if ((rc = gcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0))) | ||
400 | fprintf (stderr, | ||
401 | "Failed to set libgcrypt option %s: %s\n", | ||
402 | "ENABLE_QUICK_RANDOM", | ||
403 | gcry_strerror (rc)); | ||
404 | gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0); | ||
405 | gcry_fast_random_poll (); | ||
406 | GNUNET_CRYPTO_seed_weak_random ( | ||
407 | time (NULL) | ||
408 | ^ GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX)); | ||
409 | } | ||
410 | |||
411 | |||
412 | /** | ||
413 | * Nicely shut down libgcrypt. | ||
414 | */ | ||
415 | void __attribute__ ((destructor)) | ||
416 | GNUNET_CRYPTO_random_fini () | ||
417 | { | ||
418 | gcry_set_progress_handler (NULL, NULL); | ||
419 | #ifdef GCRYCTL_CLOSE_RANDOM_DEVICE | ||
420 | (void) gcry_control (GCRYCTL_CLOSE_RANDOM_DEVICE, 0); | ||
421 | #endif | ||
422 | } | ||
423 | |||
424 | |||
425 | /* end of crypto_random.c */ | ||