summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorVolker Lendecke <vl@samba.org>2015-10-02 00:27:22 +0200
committerJeremy Allison <jra@samba.org>2015-10-13 04:25:38 +0200
commite73ccc06efc3b489cac33e99b2cb86e022aabd7f (patch)
treef18c65e4950d2c96bbc60fc04ae60802a12185c2 /lib
parent5380f7b63648e505d6da25dc75d2487658998fdb (diff)
downloadsamba-e73ccc06efc3b489cac33e99b2cb86e022aabd7f.tar.gz
Rely on /dev/urandom
This removes quite a bit of code. All reasonable systems have /dev/urandom these days. Linux, Solaris and the BSDs do. In case we find a system without /dev/urandom, we will have to go hunting in other libraries. The main reason for this is speed: On Ubuntu 14.04 doing direct reads from /dev/urandom is 2-3 times faster than our md4 based code. On virtualized FreeBSD 10 the difference is even larger. My first approach was to use fopen/fread. It was even faster, but less than twice as fast. So I thought we could save the additional complexity when having to deal with throwing away buffers when forking and the additional memory footprint per process. With this simple generate_random_buffer it will be easier to adapt new syscalls to get randomness. Signed-off-by: Volker Lendecke <vl@samba.org> Reviewed-by: Jeremy Allison <jra@samba.org> Autobuild-User(master): Jeremy Allison <jra@samba.org> Autobuild-Date(master): Tue Oct 13 04:25:39 CEST 2015 on sn-devel-104
Diffstat (limited to 'lib')
-rw-r--r--lib/util/genrand.c259
-rw-r--r--lib/util/genrand.h11
-rw-r--r--lib/util/tests/genrand.c12
-rwxr-xr-xlib/util/wscript_build2
4 files changed, 17 insertions, 267 deletions
diff --git a/lib/util/genrand.c b/lib/util/genrand.c
index 4473433b5f7..a775535c49e 100644
--- a/lib/util/genrand.c
+++ b/lib/util/genrand.c
@@ -21,268 +21,41 @@
#include "replace.h"
#include "system/filesys.h"
-#include "../lib/crypto/crypto.h"
#include "lib/util/genrand.h"
+#include "sys_rw_data.h"
#include "lib/util/blocking.h"
-#include "lib/util/time_basic.h"
-#include "lib/util/byteorder.h"
-
-/**
- * @file
- * @brief Random number generation
- */
-
-static unsigned char hash[258];
-static uint32_t counter;
-
-static bool done_reseed = false;
-static unsigned int bytes_since_reseed = 0;
static int urand_fd = -1;
-static void (*reseed_callback)(void *userdata, int *newseed);
-static void *reseed_callback_userdata = NULL;
-
-/**
- Copy any user given reseed data.
-**/
-
-_PUBLIC_ void set_rand_reseed_callback(void (*fn)(void *, int *), void *userdata)
-{
- reseed_callback = fn;
- reseed_callback_userdata = userdata;
- set_need_random_reseed();
-}
-
-/**
- * Tell the random number generator it needs to reseed.
- */
-_PUBLIC_ void set_need_random_reseed(void)
+static void open_urandom(void)
{
- done_reseed = false;
- bytes_since_reseed = 0;
-}
-
-static void get_rand_reseed_data(int *reseed_data)
-{
- if (reseed_callback) {
- reseed_callback(reseed_callback_userdata, reseed_data);
- } else {
- *reseed_data = 0;
- }
-}
-
-/****************************************************************
- Setup the seed.
-*****************************************************************/
-
-static void seed_random_stream(unsigned char *seedval, size_t seedlen)
-{
- unsigned char j = 0;
- size_t ind;
-
- for (ind = 0; ind < 256; ind++)
- hash[ind] = (unsigned char)ind;
-
- for( ind = 0; ind < 256; ind++) {
- unsigned char tc;
-
- j += (hash[ind] + seedval[ind%seedlen]);
-
- tc = hash[ind];
- hash[ind] = hash[j];
- hash[j] = tc;
- }
-
- hash[256] = 0;
- hash[257] = 0;
-}
-
-/****************************************************************
- Get datasize bytes worth of random data.
-*****************************************************************/
-
-static void get_random_stream(unsigned char *data, size_t datasize)
-{
- unsigned char index_i = hash[256];
- unsigned char index_j = hash[257];
- size_t ind;
-
- for( ind = 0; ind < datasize; ind++) {
- unsigned char tc;
- unsigned char t;
-
- index_i++;
- index_j += hash[index_i];
-
- tc = hash[index_i];
- hash[index_i] = hash[index_j];
- hash[index_j] = tc;
-
- t = hash[index_i] + hash[index_j];
- data[ind] = hash[t];
- }
-
- hash[256] = index_i;
- hash[257] = index_j;
-}
-
-/****************************************************************
- Get a 16 byte hash from the contents of a file.
-
- Note that the hash is initialised, because the extra entropy is not
- worth the valgrind pain.
-*****************************************************************/
-
-static void do_filehash(const char *fname, unsigned char *the_hash)
-{
- unsigned char buf[1011]; /* deliberate weird size */
- unsigned char tmp_md4[16];
- int fd, n;
-
- ZERO_STRUCT(tmp_md4);
-
- fd = open(fname,O_RDONLY,0);
- if (fd == -1)
+ if (urand_fd != -1) {
return;
-
- while ((n = read(fd, (char *)buf, sizeof(buf))) > 0) {
- mdfour(tmp_md4, buf, n);
- for (n=0;n<16;n++)
- the_hash[n] ^= tmp_md4[n];
- }
- close(fd);
-}
-
-/**************************************************************
- Try and get a good random number seed. Try a number of
- different factors. Firstly, try /dev/urandom - use if exists.
-
- We use /dev/urandom as a read of /dev/random can block if
- the entropy pool dries up. This leads clients to timeout
- or be very slow on connect.
-
- If we can't use /dev/urandom then seed the stream random generator
- above...
-**************************************************************/
-
-static int do_reseed(int fd)
-{
- unsigned char seed_inbuf[40];
- uint32_t v1, v2; struct timeval tval; pid_t mypid;
- int reseed_data = 0;
-
- if (fd == -1) {
- fd = open( "/dev/urandom", O_RDONLY,0);
- if (fd != -1) {
- smb_set_close_on_exec(fd);
- }
- }
- if (fd != -1
- && (read(fd, seed_inbuf, sizeof(seed_inbuf)) == sizeof(seed_inbuf))) {
- seed_random_stream(seed_inbuf, sizeof(seed_inbuf));
- return fd;
}
-
- /* Add in some secret file contents */
-
- do_filehash("/etc/shadow", &seed_inbuf[0]);
-
- /*
- * Add the counter, time of day, and pid.
- */
-
- GetTimeOfDay(&tval);
- mypid = getpid();
- v1 = (counter++) + mypid + tval.tv_sec;
- v2 = (counter++) * mypid + tval.tv_usec;
-
- SIVAL(seed_inbuf, 32, v1 ^ IVAL(seed_inbuf, 32));
- SIVAL(seed_inbuf, 36, v2 ^ IVAL(seed_inbuf, 36));
-
- /*
- * Add any user-given reseed data.
- */
-
- get_rand_reseed_data(&reseed_data);
- if (reseed_data) {
- size_t i;
- for (i = 0; i < sizeof(seed_inbuf); i++)
- seed_inbuf[i] ^= ((char *)(&reseed_data))[i % sizeof(reseed_data)];
+ urand_fd = open( "/dev/urandom", O_RDONLY,0);
+ if (urand_fd == -1) {
+ abort();
}
-
- seed_random_stream(seed_inbuf, sizeof(seed_inbuf));
-
- return -1;
+ smb_set_close_on_exec(urand_fd);
}
-/**
- Interface to the (hopefully) good crypto random number generator.
- Will use our internal PRNG if more than 40 bytes of random generation
- has been requested, otherwise tries to read from /dev/random
-**/
_PUBLIC_ void generate_random_buffer(uint8_t *out, int len)
{
- unsigned char md4_buf[64];
- unsigned char tmp_buf[16];
- unsigned char *p;
-
- if(!done_reseed) {
- bytes_since_reseed += len;
-
- /* Magic constant to try and avoid reading 40 bytes
- * and setting up the PRNG if the app only ever wants
- * a few bytes */
- if (bytes_since_reseed < 40) {
- if (urand_fd == -1) {
- urand_fd = open( "/dev/urandom", O_RDONLY,0);
- if (urand_fd != -1) {
- smb_set_close_on_exec(urand_fd);
- }
- }
- if(urand_fd != -1 && (read(urand_fd, out, len) == len)) {
- return;
- }
- }
-
- urand_fd = do_reseed(urand_fd);
- done_reseed = true;
- }
-
- /*
- * Generate random numbers in chunks of 64 bytes,
- * then md4 them & copy to the output buffer.
- * This way the raw state of the stream is never externally
- * seen.
- */
+ ssize_t rw_ret;
- p = out;
- while(len > 0) {
- int copy_len = len > 16 ? 16 : len;
+ open_urandom();
- get_random_stream(md4_buf, sizeof(md4_buf));
- mdfour(tmp_buf, md4_buf, sizeof(md4_buf));
- memcpy(p, tmp_buf, copy_len);
- p += copy_len;
- len -= copy_len;
+ rw_ret = read_data(urand_fd, out, len);
+ if (rw_ret != len) {
+ abort();
}
}
-/**
- Interface to the (hopefully) good crypto random number generator.
- Will always use /dev/urandom if available.
-**/
+/*
+ * Keep generate_secret_buffer in case we ever want to do something
+ * different
+ */
_PUBLIC_ void generate_secret_buffer(uint8_t *out, int len)
{
- if (urand_fd == -1) {
- urand_fd = open( "/dev/urandom", O_RDONLY,0);
- if (urand_fd != -1) {
- smb_set_close_on_exec(urand_fd);
- }
- }
- if(urand_fd != -1 && (read(urand_fd, out, len) == len)) {
- return;
- }
-
generate_random_buffer(out, len);
}
diff --git a/lib/util/genrand.h b/lib/util/genrand.h
index 73ca601df2f..ef6bbc64157 100644
--- a/lib/util/genrand.h
+++ b/lib/util/genrand.h
@@ -20,17 +20,6 @@
*/
/**
- Copy any user given reseed data.
-**/
-
-void set_rand_reseed_callback(void (*fn)(void *, int *), void *userdata);
-
-/**
- * Tell the random number generator it needs to reseed.
- */
-void set_need_random_reseed(void);
-
-/**
Interface to the (hopefully) good crypto random number generator.
Will use our internal PRNG if more than 40 bytes of random generation
has been requested, otherwise tries to read from /dev/random
diff --git a/lib/util/tests/genrand.c b/lib/util/tests/genrand.c
index 3d48be0c22c..81c20bc386f 100644
--- a/lib/util/tests/genrand.c
+++ b/lib/util/tests/genrand.c
@@ -23,17 +23,6 @@
#include "torture/torture.h"
#include "torture/local/proto.h"
-static void dummy_reseed(void *userdata, int *d)
-{
- *d = 42;
-}
-
-static bool test_reseed_callback(struct torture_context *tctx)
-{
- set_rand_reseed_callback(dummy_reseed, NULL);
- return true;
-}
-
static bool test_check_password_quality(struct torture_context *tctx)
{
torture_assert(tctx, !check_password_quality(""), "empty password");
@@ -64,7 +53,6 @@ static bool test_generate_random_str(struct torture_context *tctx)
struct torture_suite *torture_local_genrand(TALLOC_CTX *mem_ctx)
{
struct torture_suite *suite = torture_suite_create(mem_ctx, "genrand");
- torture_suite_add_simple_test(suite, "reseed_callback", test_reseed_callback);
torture_suite_add_simple_test(suite, "check_password_quality", test_check_password_quality);
torture_suite_add_simple_test(suite, "generate_random_str", test_generate_random_str);
return suite;
diff --git a/lib/util/wscript_build b/lib/util/wscript_build
index 2c4d093faea..81578a954f1 100755
--- a/lib/util/wscript_build
+++ b/lib/util/wscript_build
@@ -84,7 +84,7 @@ if not bld.env.SAMBA_UTIL_CORE_ONLY:
bld.SAMBA_LIBRARY('genrand',
source='genrand.c',
- deps='time-basic socket-blocking LIBCRYPTO',
+ deps='replace socket-blocking sys_rw',
local_include=False,
private_library=True)