mirror of
https://github.com/rkd77/elinks.git
synced 2024-12-04 14:46:47 -05:00
1008: Centralize random numbers.
If ELinks is being linked with SSL library, use its random number generator. Otherwise, try /dev/urandom and /dev/prandom. If they do not work, fall back to rand(), calling srand() only once. This fallback is mostly interesting for the Hurd and Microsoft Windows. BitTorrent piece selection and dom/test/html-mangle.c still use rand() (but not srand()) directly. Those would not benefit from being unpredictable, I think.
This commit is contained in:
parent
291a913d1e
commit
7a72a685e5
@ -8,6 +8,7 @@
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/rand.h>
|
||||
#elif defined(CONFIG_GNUTLS)
|
||||
#include <gcrypt.h>
|
||||
#include <gnutls/gnutls.h>
|
||||
#else
|
||||
#error "Huh?! You have SSL enabled, but not OPENSSL nor GNUTLS!! And then you want exactly *what* from me?"
|
||||
@ -27,6 +28,7 @@
|
||||
#include "util/conv.h"
|
||||
#include "util/error.h"
|
||||
#include "util/string.h"
|
||||
#include "util/random.h"
|
||||
|
||||
|
||||
/* FIXME: As you can see, SSL is currently implemented in very, erm,
|
||||
@ -282,3 +284,17 @@ get_ssl_connection_cipher(struct socket *socket)
|
||||
|
||||
return str.source;
|
||||
}
|
||||
|
||||
/* When CONFIG_SSL is defined, this implementation replaces the one in
|
||||
* src/util/random.c. */
|
||||
void
|
||||
random_nonce(unsigned char buf[], size_t size)
|
||||
{
|
||||
#ifdef CONFIG_OPENSSL
|
||||
RAND_pseudo_bytes(buf, size);
|
||||
#elif defined(CONFIG_GNUTLS)
|
||||
gcry_create_nonce(buf, size);
|
||||
#else
|
||||
# error unsupported SSL library
|
||||
#endif
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "util/conv.h"
|
||||
#include "util/md5.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/random.h"
|
||||
|
||||
|
||||
/* Hexes a binary md5 digest. Taken from RFC 2617 */
|
||||
@ -31,18 +32,14 @@ convert_to_md5_digest_hex_T(md5_digest_bin_T bin, md5_digest_hex_T hex)
|
||||
}
|
||||
}
|
||||
|
||||
/* Initializes a random cnonce that is also a hexed md5 digest. */
|
||||
/* Initializes a random cnonce that has the same format as a hexed md5
|
||||
* digest. */
|
||||
static void
|
||||
init_cnonce_digest(md5_digest_hex_T cnonce)
|
||||
{
|
||||
md5_digest_bin_T md5;
|
||||
int random;
|
||||
|
||||
srand(time(NULL));
|
||||
|
||||
random = rand();
|
||||
MD5((const unsigned char *) &random, sizeof(random), md5);
|
||||
|
||||
random_nonce(md5, MD5_DIGEST_LENGTH);
|
||||
convert_to_md5_digest_hex_T(md5, cnonce);
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "util/error.h"
|
||||
#include "util/lists.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/random.h"
|
||||
#include "util/sha1.h"
|
||||
#include "util/string.h"
|
||||
#include "util/snprintf.h"
|
||||
@ -167,13 +168,10 @@ init_bittorrent_peer_id(bittorrent_id_T peer_id)
|
||||
}
|
||||
|
||||
/* Hmm, sizeof(peer_id) don't work here. */
|
||||
random_nonce(peer_id + i, sizeof(bittorrent_id_T) - i);
|
||||
while (i < sizeof(bittorrent_id_T)) {
|
||||
int random = rand();
|
||||
|
||||
while (i < sizeof(bittorrent_id_T) && (random & 0xF)) {
|
||||
peer_id[i++] = hx(random & 0xF);
|
||||
random >>= 4;
|
||||
}
|
||||
peer_id[i] = hx(peer_id[i] & 0xF);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "util/file.h"
|
||||
#include "util/lists.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/random.h"
|
||||
#include "util/string.h"
|
||||
|
||||
|
||||
@ -165,7 +166,7 @@ find_random_in_bittorrent_piece_cache(struct bittorrent_piece_cache *cache,
|
||||
|
||||
assert(peer->bitfield->bitsize == peer->bittorrent->meta.pieces);
|
||||
|
||||
srand(time(NULL));
|
||||
seed_rand_once();
|
||||
|
||||
foreachback_bitfield_set (piece, peer->bitfield) {
|
||||
assertm(cache->entries[piece].rarity,
|
||||
@ -238,7 +239,7 @@ find_rarest_in_bittorrent_piece_cache(struct bittorrent_piece_cache *cache,
|
||||
|
||||
assert(peer->bitfield->bitsize == peer->bittorrent->meta.pieces);
|
||||
|
||||
srand(time(NULL));
|
||||
seed_rand_once();
|
||||
|
||||
/* Try to randomize the piece picking using the strategy from the random
|
||||
* piece selection. */
|
||||
|
@ -32,6 +32,7 @@ OBJS = \
|
||||
hash.o \
|
||||
memlist.o \
|
||||
memory.o \
|
||||
random.o \
|
||||
secsave.o \
|
||||
snprintf.o \
|
||||
string.o \
|
||||
|
114
src/util/random.c
Normal file
114
src/util/random.c
Normal file
@ -0,0 +1,114 @@
|
||||
/** Random numbers.
|
||||
* @file */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "elinks.h"
|
||||
|
||||
#include "util/random.h"
|
||||
|
||||
void
|
||||
seed_rand_once(void)
|
||||
{
|
||||
static int seeded = 0;
|
||||
|
||||
if (!seeded) {
|
||||
srand(time(NULL));
|
||||
seeded = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef CONFIG_SSL
|
||||
|
||||
static void
|
||||
pseudorandom_nonce(unsigned char buf[], size_t size)
|
||||
{
|
||||
static int initialized = 0;
|
||||
static int accept_bits;
|
||||
static int accept_mask;
|
||||
unsigned int got_mask;
|
||||
unsigned int got_random;
|
||||
size_t index;
|
||||
|
||||
if (!initialized) {
|
||||
unsigned int shift;
|
||||
|
||||
seed_rand_once();
|
||||
|
||||
/* 32767 <= RAND_MAX <= INT_MAX. Find the largest
|
||||
* accept_mask such that accept_mask <= RAND_MAX and
|
||||
* accept_mask + 1 is a power of two. */
|
||||
shift = RAND_MAX;
|
||||
accept_bits = 0U;
|
||||
accept_mask = 0U;
|
||||
while (shift != 0U) {
|
||||
shift >>= 1;
|
||||
accept_bits++;
|
||||
accept_mask = (accept_mask << 1) + 1U;
|
||||
}
|
||||
if (accept_mask > (unsigned int) RAND_MAX) {
|
||||
accept_bits--;
|
||||
accept_mask >>= 1;
|
||||
}
|
||||
|
||||
initialized = 1;
|
||||
}
|
||||
|
||||
got_mask = got_random = 0U;
|
||||
for (index = 0; index < size; ) {
|
||||
if (got_mask >= UCHAR_MAX) {
|
||||
buf[index++] = (unsigned char) got_random;
|
||||
got_mask >>= CHAR_BIT;
|
||||
got_random >>= CHAR_BIT;
|
||||
} else {
|
||||
unsigned int candidate;
|
||||
|
||||
do {
|
||||
candidate = rand();
|
||||
} while (candidate > accept_mask);
|
||||
|
||||
/* These shifts can discard some bits. */
|
||||
got_mask = (got_mask << accept_bits) | accept_mask;
|
||||
got_random = (got_random << accept_bits) | candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Fill a buffer with random bytes. The bytes are not
|
||||
* cryptographically random enough to be used in a key, but they
|
||||
* should be good enough for a nonce or boundary string that may
|
||||
* be sent in cleartext.
|
||||
*
|
||||
* If CONFIG_SSL is defined, then this function is instead defined in
|
||||
* src/network/ssl/ssl.c, and it gets random numbers directly from the
|
||||
* selected SSL library. */
|
||||
void
|
||||
random_nonce(unsigned char buf[], size_t size)
|
||||
{
|
||||
size_t i = 0;
|
||||
FILE *f = fopen("/dev/urandom", "rb");
|
||||
|
||||
if (!f) f = fopen("/dev/prandom", "rb"); /* OpenBSD */
|
||||
if (f) {
|
||||
i = fread(data, 1, length, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
/* If the random device did not exist or could not provide
|
||||
* enough data, then fill the buffer with rand(). The
|
||||
* resulting numbers may be predictable but they provide
|
||||
* ELinks with at least some way to generate boundary strings
|
||||
* for multipart uploads. A more secure algorithm and entropy
|
||||
* collection could be implemented, but there doesn't seem to
|
||||
* be much point as SSL libraries already provide this
|
||||
* facility. */
|
||||
if (i < size)
|
||||
pseudorandom_nonce(buf + i, size - i);
|
||||
}
|
||||
|
||||
#endif /* ndef CONFIG_SSL */
|
11
src/util/random.h
Normal file
11
src/util/random.h
Normal file
@ -0,0 +1,11 @@
|
||||
/** Random numbers.
|
||||
* @file */
|
||||
|
||||
#ifndef EL__UTIL_RANDOM_H
|
||||
#define EL__UTIL_RANDOM_H
|
||||
|
||||
void seed_rand_once(void);
|
||||
|
||||
void random_nonce(unsigned char buf[], size_t size);
|
||||
|
||||
#endif
|
@ -45,6 +45,7 @@
|
||||
#include "util/error.h"
|
||||
#include "util/file.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/random.h"
|
||||
#include "util/string.h"
|
||||
#include "viewer/action.h"
|
||||
#include "viewer/text/draw.h"
|
||||
@ -834,14 +835,8 @@ static void
|
||||
randomize_boundary(unsigned char *data, int length)
|
||||
{
|
||||
int i;
|
||||
FILE *f = fopen("/dev/urandom", "rb");
|
||||
|
||||
if (!f) f = fopen("/dev/prandom", "rb"); /* OpenBSD */
|
||||
if (f) {
|
||||
fread(data, 1, length, f);
|
||||
fclose(f);
|
||||
}
|
||||
/* FIXME. What if both fails */
|
||||
random_nonce(data, length);
|
||||
for (i = 0; i < length; i++) {
|
||||
/* Only [0-9A-Za-z]. */
|
||||
data[i] = data[i] & 63;
|
||||
|
Loading…
Reference in New Issue
Block a user