big dialogs: dlg_format_text: no need to pass the term.
[elinks.git] / src / util / random.c
blob42c6611c247279df793868a7133e822ca7fabc1b
1 /** Random numbers.
2 * @file */
4 #ifdef HAVE_CONFIG_H
5 #include "config.h"
6 #endif
8 #include <stdlib.h>
9 #include <time.h>
11 #include "elinks.h"
13 #include "util/random.h"
15 void
16 seed_rand_once(void)
18 static int seeded = 0;
20 if (!seeded) {
21 srand(time(NULL));
22 seeded = 1;
26 #ifndef CONFIG_SSL
28 static void
29 pseudorandom_nonce(unsigned char buf[], size_t size)
31 static int initialized = 0;
32 static int accept_bits;
33 static int accept_mask;
34 unsigned int got_mask;
35 unsigned int got_random;
36 size_t index;
38 if (!initialized) {
39 unsigned int shift;
41 seed_rand_once();
43 /* 32767 <= RAND_MAX <= INT_MAX. Find the largest
44 * accept_mask such that accept_mask <= RAND_MAX and
45 * accept_mask + 1 is a power of two. */
46 shift = RAND_MAX;
47 accept_bits = 0U;
48 accept_mask = 0U;
49 while (shift != 0U) {
50 shift >>= 1;
51 accept_bits++;
52 accept_mask = (accept_mask << 1) + 1U;
54 if (accept_mask > (unsigned int) RAND_MAX) {
55 accept_bits--;
56 accept_mask >>= 1;
59 initialized = 1;
62 got_mask = got_random = 0U;
63 for (index = 0; index < size; ) {
64 if (got_mask >= UCHAR_MAX) {
65 buf[index++] = (unsigned char) got_random;
66 got_mask >>= CHAR_BIT;
67 got_random >>= CHAR_BIT;
68 } else {
69 unsigned int candidate;
71 do {
72 candidate = rand();
73 } while (candidate > accept_mask);
75 /* These shifts can discard some bits. */
76 got_mask = (got_mask << accept_bits) | accept_mask;
77 got_random = (got_random << accept_bits) | candidate;
82 /** Fill a buffer with random bytes. The bytes are not
83 * cryptographically random enough to be used in a key, but they
84 * should be good enough for a nonce or boundary string that may
85 * be sent in cleartext.
87 * If CONFIG_SSL is defined, then this function is instead defined in
88 * src/network/ssl/ssl.c, and it gets random numbers directly from the
89 * selected SSL library. */
90 void
91 random_nonce(unsigned char buf[], size_t size)
93 size_t i = 0;
94 FILE *f = fopen("/dev/urandom", "rb");
96 if (!f) f = fopen("/dev/prandom", "rb"); /* OpenBSD */
97 if (f) {
98 i = fread(data, 1, length, f);
99 fclose(f);
102 /* If the random device did not exist or could not provide
103 * enough data, then fill the buffer with rand(). The
104 * resulting numbers may be predictable but they provide
105 * ELinks with at least some way to generate boundary strings
106 * for multipart uploads. A more secure algorithm and entropy
107 * collection could be implemented, but there doesn't seem to
108 * be much point as SSL libraries already provide this
109 * facility. */
110 if (i < size)
111 pseudorandom_nonce(buf + i, size - i);
114 #endif /* ndef CONFIG_SSL */