Retry only for https protocol
[elinks.git] / src / util / random.c
blobcb4f5e803c94f726ce84651c2cc2856b41d45d61
1 /** Random numbers.
2 * @file */
4 #ifdef HAVE_CONFIG_H
5 #include "config.h"
6 #endif
8 #include <stdlib.h>
9 #include <stdio.h>
10 #include <time.h>
12 #include "elinks.h"
14 #include "util/random.h"
16 void
17 seed_rand_once(void)
19 static int seeded = 0;
21 if (!seeded) {
22 srand(time(NULL));
23 seeded = 1;
27 #ifndef CONFIG_SSL
29 static void
30 pseudorandom_nonce(unsigned char buf[], size_t size)
32 static int initialized = 0;
33 static int accept_bits;
34 static int accept_mask;
35 unsigned int got_mask;
36 unsigned int got_random;
37 size_t index;
39 if (!initialized) {
40 unsigned int shift;
42 seed_rand_once();
44 /* 32767 <= RAND_MAX <= INT_MAX. Find the largest
45 * accept_mask such that accept_mask <= RAND_MAX and
46 * accept_mask + 1 is a power of two. */
47 shift = RAND_MAX;
48 accept_bits = 0U;
49 accept_mask = 0U;
50 while (shift != 0U) {
51 shift >>= 1;
52 accept_bits++;
53 accept_mask = (accept_mask << 1) + 1U;
55 if (accept_mask > (unsigned int) RAND_MAX) {
56 accept_bits--;
57 accept_mask >>= 1;
60 initialized = 1;
63 got_mask = got_random = 0U;
64 for (index = 0; index < size; ) {
65 if (got_mask >= UCHAR_MAX) {
66 buf[index++] = (unsigned char) got_random;
67 got_mask >>= CHAR_BIT;
68 got_random >>= CHAR_BIT;
69 } else {
70 unsigned int candidate;
72 do {
73 candidate = rand();
74 } while (candidate > accept_mask);
76 /* These shifts can discard some bits. */
77 got_mask = (got_mask << accept_bits) | accept_mask;
78 got_random = (got_random << accept_bits) | candidate;
83 /** Fill a buffer with random bytes. The bytes are not
84 * cryptographically random enough to be used in a key, but they
85 * should be good enough for a nonce or boundary string that may
86 * be sent in cleartext.
88 * If CONFIG_SSL is defined, then this function is instead defined in
89 * src/network/ssl/ssl.c, and it gets random numbers directly from the
90 * selected SSL library. */
91 void
92 random_nonce(unsigned char buf[], size_t size)
94 size_t i = 0;
95 FILE *f = fopen("/dev/urandom", "rb");
97 if (!f) f = fopen("/dev/prandom", "rb"); /* OpenBSD */
98 if (f) {
99 i = fread(buf, 1, size, f);
100 fclose(f);
103 /* If the random device did not exist or could not provide
104 * enough data, then fill the buffer with rand(). The
105 * resulting numbers may be predictable but they provide
106 * ELinks with at least some way to generate boundary strings
107 * for multipart uploads. A more secure algorithm and entropy
108 * collection could be implemented, but there doesn't seem to
109 * be much point as SSL libraries already provide this
110 * facility. */
111 if (i < size)
112 pseudorandom_nonce(buf + i, size - i);
115 #endif /* ndef CONFIG_SSL */