From c961f78f03c9b455cd9a93a73045e01f7c4178c2 Mon Sep 17 00:00:00 2001 From: Ilari Liusvaara Date: Sun, 4 May 2014 19:08:25 +0300 Subject: [PATCH] Use urandom / rtlgenrandom Simplify the mess of random number generation. Also, even if rtlgenrandom is officially documented as don't use, if it gets changed/removed, if this emulator works is the least of your worries (Microsoft just broke all backward compatibility). --- include/library/crandom.hpp | 24 +++++++++++++ src/core/misc.cpp | 78 +++++------------------------------------ src/library/crandom.cpp | 75 +++++++++++++++++++++++++++++++++++++++ src/platform/wxwidgets/main.cpp | 8 +++++ src/util/lsnes-dumpavi.cpp | 8 +++++ 5 files changed, 123 insertions(+), 70 deletions(-) create mode 100644 include/library/crandom.hpp create mode 100644 src/library/crandom.cpp diff --git a/include/library/crandom.hpp b/include/library/crandom.hpp new file mode 100644 index 00000000..d1fb9f67 --- /dev/null +++ b/include/library/crandom.hpp @@ -0,0 +1,24 @@ +#ifndef _library__random__hpp__included__ +#define _library__random__hpp__included__ + +#include + +namespace crandom +{ +/** + * Initialize random number generator. + * + * Throws std::runtime_error: Can't initialize RNG. + */ + void init(); +/** + * Generate random bits. Automatically initializes the generator if not already initialized. + * + * Parameter buffer: The buffer to fill. + * Parameter buffersize: Number of bytes to fill. + * Throws std::runtime_error: Can't initialize RNG. + */ + void generate(void* buffer, size_t buffersize); +} + +#endif diff --git a/src/core/misc.cpp b/src/core/misc.cpp index d789a062..8ea0a508 100644 --- a/src/core/misc.cpp +++ b/src/core/misc.cpp @@ -9,6 +9,7 @@ #include "core/moviedata.hpp" #include "core/settings.hpp" #include "core/window.hpp" +#include "library/crandom.hpp" #include "library/directory.hpp" #include "library/hex.hpp" #include "library/loadlib.hpp" @@ -62,6 +63,7 @@ namespace { #ifdef ARCH_IS_I386 uint32_t r; + //This reads undefined value if RDRAND is not supported. Don't care. asm volatile (".byte 0xb8, 0x01, 0x00, 0x00, 0x00, 0x0f, 0xa2, 0xf7, 0xc1, 0x00, 0x00, 0x00, 0x40, " "0x74, 0x03, 0x0f, 0xc7, 0xf0" : "=a"(r) : : "ebx", "ecx", "edx"); return r; @@ -70,18 +72,6 @@ namespace #endif } - //Returns 32 bytes. - void arch_random_256(uint8_t* buf) - { - uint32_t tmp[1026]; - uint64_t tsc = arch_get_tsc(); - tmp[1024] = tsc; - tmp[1025] = tsc >> 32; - for(unsigned i = 0; i < 1024; i++) - tmp[i] = arch_get_random(); - sha256::hash(buf, reinterpret_cast(tmp), sizeof(tmp)); - } - void do_mix_tsc() { const unsigned slots = 32; @@ -118,31 +108,6 @@ namespace return hex::b_to(out, sizeof(out)); } - std::string collect_identifying_information() - { - //TODO: Collect as much identifying information as possible. - std::ostringstream str; - time_t told = time(NULL); - time_t tnew; - uint64_t loops = 0; - uint64_t base = 0; - int cnt = 0; - while(cnt < 3) { - tnew = time(NULL); - if(tnew > told) { - told = tnew; - cnt++; - str << (loops - base) << " "; - base = loops; - } - loops++; - } - str << arch_get_tsc() << " "; - for(unsigned i = 0; i < 256; i++) - str << arch_get_random() << " "; - return str.str(); - } - char endian_char(int e) { if(e < 0) @@ -210,34 +175,12 @@ void set_random_seed(const std::string& seed) throw(std::bad_alloc) void set_random_seed() throw(std::bad_alloc) { - //Try /dev/urandom first. - { - std::ifstream r("/dev/urandom", std::ios::binary); - if(r.is_open()) { - char buf[128]; - r.read(buf, sizeof(buf)); - std::string s(buf, sizeof(buf)); - set_random_seed(s); - return; - } - } - //If libgcrypt is available, use that. -#ifdef USE_LIBGCRYPT_SHA256 - { - char buf[128]; - gcry_randomize((unsigned char*)buf, sizeof(buf), GCRY_STRONG_RANDOM); - std::string s(buf, sizeof(buf)); - set_random_seed(s); - return; - } -#endif - //Fall back to time. - std::ostringstream str; - str << collect_identifying_information() << " " << time(NULL); - set_random_seed(str.str()); + char buf[128]; + crandom::generate(buf, 128); + std::string s(buf, sizeof(buf)); + set_random_seed(s); } - struct loaded_rom load_rom_from_commandline(std::vector cmdline) throw(std::bad_alloc, std::runtime_error) { @@ -357,6 +300,7 @@ bool in_global_ctors() void reached_main() { + crandom::init(); new_core_flag = false; //We'll process the static cores anyway. reached_main_flag = true; lsnes_cmd.set_oom_panic(OOM_panic); @@ -427,17 +371,11 @@ void highrandom_256(uint8_t* buf) uint8_t tmp[104]; std::string s = get_random_hexstring(64); std::copy(s.begin(), s.end(), reinterpret_cast(tmp)); - arch_random_256(tmp + 64); + crandom::generate(tmp + 64, 32); serialization::u64b(tmp + 96, arch_get_tsc()); skein::hash hsh(skein::hash::PIPE_1024, 256); hsh.write(tmp, 104); hsh.read(buf); -#ifdef USE_LIBGCRYPT_SHA256 - memset(tmp, 0, 32); - gcry_randomize((unsigned char*)buf, 32, GCRY_STRONG_RANDOM); - for(unsigned i = 0; i < 32; i++) - buf[i] ^= tmp[i]; -#endif } std::string get_temp_file() diff --git a/src/library/crandom.cpp b/src/library/crandom.cpp new file mode 100644 index 00000000..a6be2e01 --- /dev/null +++ b/src/library/crandom.cpp @@ -0,0 +1,75 @@ +#include "crandom.hpp" +#include +#include + +#if defined(_WIN32) || defined(_WIN64) +#include + +namespace +{ + typedef BOOLEAN (WINAPI *rtlgenrandom_t)(PVOID buf, ULONG buflen); + HMODULE advapi; + rtlgenrandom_t rtlgenrandom_fn; +} + +namespace crandom +{ +void init() +{ + if(rtlgenrandom_fn) return; + advapi = LoadLibraryA("advapi32.dll"); + if(!advapi) + throw std::runtime_error("Can't load advapi32.dll"); + rtlgenrandom_fn = (rtlgenrandom_t)GetProcAddress(advapi, "SystemFunction036"); + if(!rtlgenrandom_fn) + throw std::runtime_error("Can't find rtlgenrandom"); +} + +void generate(void* buffer, size_t buffersize) +{ + if(!rtlgenrandom_fn) + init(); + while(!rtlgenrandom_fn(buffer, buffersize)); +} +} + +#else +#include +#include +#include + +namespace +{ + int fd = -1; + void try_file(const char* name) + { + int err = 0; + while(fd < 0 && err != ENOENT && err != ENXIO) { + fd = open(name, O_RDONLY); + if(fd < 0) err = errno; + } + } +} + +namespace crandom +{ +void init() +{ + if(fd < 0) try_file("/dev/urandom"); + if(fd < 0) try_file("/dev/random"); + if(fd < 0) throw std::runtime_error("Can't open /dev/urandom"); +} + +void generate(void* buffer, size_t buffersize) +{ + if(fd < 0) + init(); + size_t out = 0; + while(out < buffersize) { + ssize_t r = read(fd, (char*)buffer + out, buffersize - out); + if(r > 0) out += r; + } +} +} + +#endif diff --git a/src/platform/wxwidgets/main.cpp b/src/platform/wxwidgets/main.cpp index 29586da5..b2e0928c 100644 --- a/src/platform/wxwidgets/main.cpp +++ b/src/platform/wxwidgets/main.cpp @@ -19,6 +19,7 @@ #include "core/settings.hpp" #include "core/window.hpp" #include "interface/romtype.hpp" +#include "library/crandom.hpp" #include "library/string.hpp" #include "library/threads.hpp" #include "library/utf8.hpp" @@ -450,6 +451,13 @@ bool lsnes_app::OnInit() if(exit_immediately) return false; + try { + crandom::init(); + } catch(std::exception& e) { + show_message_ok(NULL, "RNG error", "Error initializing system RNG", wxICON_ERROR); + return false; + } + reached_main(); set_random_seed(); bring_app_foreground(); diff --git a/src/util/lsnes-dumpavi.cpp b/src/util/lsnes-dumpavi.cpp index c91de208..bb9635ed 100644 --- a/src/util/lsnes-dumpavi.cpp +++ b/src/util/lsnes-dumpavi.cpp @@ -20,6 +20,7 @@ #include "core/settings.hpp" #include "core/window.hpp" #include "library/directory.hpp" +#include "library/crandom.hpp" #include "library/string.hpp" #include @@ -296,6 +297,13 @@ namespace int main(int argc, char** argv) { + try { + crandom::init(); + } catch(std::exception& e) { + std::cerr << "Error initializing system RNG" << std::endl; + return 1; + } + reached_main(); std::vector cmdline; for(int i = 1; i < argc; i++) -- 2.11.4.GIT