diff --git a/src/evalfunc.c b/src/evalfunc.c index 84df6a62a..64a9aac39 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -8122,7 +8122,7 @@ f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED) init_srand(UINT32_T *x) { #ifndef MSWIN - static int dev_urandom_state = NOTDONE; // FAIL or OK once tried + static int getrandom_state = NOTDONE; // FAIL or OK once tried #endif if (srand_seed_for_testing_is_used) @@ -8131,34 +8131,12 @@ init_srand(UINT32_T *x) return; } #ifndef MSWIN - if (dev_urandom_state != FAIL) - { - int fd = open("/dev/urandom", O_RDONLY); - struct { - union { - UINT32_T number; - char bytes[sizeof(UINT32_T)]; - } contents; - } buf; - - // Attempt reading /dev/urandom. - if (fd == -1) - dev_urandom_state = FAIL; - else - { - buf.contents.number = 0; - if (read(fd, buf.contents.bytes, sizeof(UINT32_T)) - != sizeof(UINT32_T)) - dev_urandom_state = FAIL; - else - { - dev_urandom_state = OK; - *x = buf.contents.number; - } - close(fd); - } + if (getrandom_state != FAIL) + { + os_getrandom(x, sizeof(UINT32_T)); + getrandom_state = OK; } - if (dev_urandom_state != OK) + if (getrandom_state != OK) #endif { // Reading /dev/urandom doesn't work, fall back to: diff --git a/src/os_unix.c b/src/os_unix.c index bd75ccae1..af5450153 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -18,6 +18,9 @@ * changed beyond recognition. */ +#include +#include + #include "vim.h" #ifdef FEAT_MZSCHEME @@ -340,6 +343,31 @@ static struct signalinfo {-1, "Unknown!", FALSE} }; +void os_getrandom(void *buf, size_t len) +{ + ssize_t written; + uint8_t *p = buf; + + if (len > INT_MAX) { + smsg("os_getrandom: requested %zu bytes\n", len); + exit(1); + } + + while (len > 0) { + do { + errno = 0; + written = getrandom(p, len, 0); + } while ((written == -1) && (errno == EINTR)); + if (written <= 0) { + smsg("os_getrandom: getrandom failed: %s\n", + strerror(errno)); + exit(1); + } + p += written; + len -= written; + } +} + int mch_chdir(char *path) { diff --git a/src/proto/os_unix.pro b/src/proto/os_unix.pro index 926636440..7bac28a56 100644 --- a/src/proto/os_unix.pro +++ b/src/proto/os_unix.pro @@ -1,4 +1,5 @@ /* os_unix.c */ +void os_getrandom(void*, size_t); int mch_chdir(char *path); void mch_write(char_u *s, int len); int mch_inchar(char_u *buf, int maxlen, long wtime, int tb_change_cnt); diff --git a/src/sha256.c b/src/sha256.c index 9c79e0df1..aa6104423 100644 --- a/src/sha256.c +++ b/src/sha256.c @@ -20,6 +20,8 @@ * sha256_self_test() is implicitly called once. */ +#define _GNU_SOURCE + #include "vim.h" #if defined(FEAT_CRYPT) || defined(FEAT_PERSISTENT_UNDO) @@ -376,20 +378,6 @@ sha256_self_test(void) return failures > 0 ? FAIL : OK; } - static unsigned int -get_some_time(void) -{ -# ifdef HAVE_GETTIMEOFDAY - struct timeval tv; - - // Using usec makes it less predictable. - gettimeofday(&tv, NULL); - return (unsigned int)(tv.tv_sec + tv.tv_usec); -# else - return (unsigned int)time(NULL); -# endif -} - /* * Fill "header[header_len]" with random_data. * Also "salt[salt_len]" when "salt" is not NULL. @@ -401,27 +389,8 @@ sha2_seed( char_u *salt, int salt_len) { - int i; - static char_u random_data[1000]; - char_u sha256sum[32]; - context_sha256_T ctx; - - srand(get_some_time()); - - for (i = 0; i < (int)sizeof(random_data) - 1; i++) - random_data[i] = (char_u)((get_some_time() ^ rand()) & 0xff); - sha256_start(&ctx); - sha256_update(&ctx, (char_u *)random_data, sizeof(random_data)); - sha256_finish(&ctx, sha256sum); - - // put first block into header. - for (i = 0; i < header_len; i++) - header[i] = sha256sum[i % sizeof(sha256sum)]; - - // put remaining block into salt. - if (salt != NULL) - for (i = 0; i < salt_len; i++) - salt[i] = sha256sum[(i + header_len) % sizeof(sha256sum)]; + os_getrandom(header, header_len); + if (salt) os_getrandom(salt, salt_len); } #endif // FEAT_CRYPT diff --git a/src/testdir/test_random.vim b/src/testdir/test_random.vim index be8473f29..fd9d2a225 100644 --- a/src/testdir/test_random.vim +++ b/src/testdir/test_random.vim @@ -13,8 +13,15 @@ func Test_Rand() call assert_equal(3104308804, rand(r)) let s = srand() - " using /dev/urandom or used time, result is different each time - call assert_notequal(s, srand()) + if !has('win32') + " using getrandom() + call assert_notequal(s, srand()) + else + " using time() + call assert_equal(s, srand()) + call test_settime(12341235) + call assert_notequal(s, srand()) + endif call test_srand_seed(123456789) call assert_equal(4284103975, rand())