diff options
author | Volker Lendecke <vl@samba.org> | 2015-10-02 00:27:22 +0200 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2015-10-13 04:25:38 +0200 |
commit | e73ccc06efc3b489cac33e99b2cb86e022aabd7f (patch) | |
tree | f18c65e4950d2c96bbc60fc04ae60802a12185c2 /lib | |
parent | 5380f7b63648e505d6da25dc75d2487658998fdb (diff) | |
download | samba-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.c | 259 | ||||
-rw-r--r-- | lib/util/genrand.h | 11 | ||||
-rw-r--r-- | lib/util/tests/genrand.c | 12 | ||||
-rwxr-xr-x | lib/util/wscript_build | 2 |
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) |