1
0
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:
Kalle Olavi Niemitalo 2008-05-25 18:31:49 +03:00 committed by Kalle Olavi Niemitalo
parent 291a913d1e
commit 7a72a685e5
8 changed files with 155 additions and 22 deletions

View File

@ -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
}

View File

@ -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);
}

View File

@ -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++;
}
}

View File

@ -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. */

View File

@ -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
View 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
View 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

View File

@ -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;