diff --git a/configure.ac b/configure.ac index 2f21427ae..a086d9c72 100644 --- a/configure.ac +++ b/configure.ac @@ -171,12 +171,19 @@ AC_ARG_WITH([system-univalue], [system_univalue=$withval], [system_univalue=no] ) + AC_ARG_ENABLE([zmq], [AS_HELP_STRING([--disable-zmq], [disable ZMQ notifications])], [use_zmq=$enableval], [use_zmq=yes]) +AC_ARG_ENABLE([rdseed], + [AS_HELP_STRING([--disable-rdseed], + [disable rdseed entropy (default is yes where available)])], + [use_rdseed=$enableval], + [use_rdseed=yes]) + AC_ARG_WITH([protoc-bindir],[AS_HELP_STRING([--with-protoc-bindir=BIN_DIR],[specify protoc bin path])], [protoc_bin_path=$withval], []) AC_ARG_ENABLE(man, @@ -861,6 +868,23 @@ else fi fi + + +dnl Use rdseed to gather entropy +if test "x$use_rdseed" = "xyes"; then + dnl Only enable rdseed on the compiler when targeting x86 + case $host in + *x86*) + CXXFLAGS="$CXXFLAGS -mrdseed" + ;; + *i686*) + CXXFLAGS="$CXXFLAGS -mrdseed" + ;; + *) + use_rdseed="no" + esac +fi + save_CXXFLAGS="${CXXFLAGS}" CXXFLAGS="${CXXFLAGS} ${CRYPTO_CFLAGS} ${SSL_CFLAGS}" AC_CHECK_DECLS([EVP_MD_CTX_new],,,[AC_INCLUDES_DEFAULT diff --git a/src/lowlevel.h b/src/lowlevel.h new file mode 100644 index 000000000..71fa44275 --- /dev/null +++ b/src/lowlevel.h @@ -0,0 +1,58 @@ +// Copyright (c) 2021 The Dogecoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +//Here be dragons, wizards, witches and master of the dark arts. +//Careful thou who wonders 'round these parts without magic spells, +//mana potions and doggy treats...especially magical doggy treats. + + +//Only define this header on x86 +#if ( defined(i386) || defined(__i386) || defined(__i386__) || \ + defined( __386) || defined(_X86_) || defined( _M_I86) || \ + defined(__i386__) || defined(__X86__) || defined(__x86_64) ) + + #ifndef LOWLEVEL_H + #define LOWLEVEL_H + #define LOWLEVEL_USE_RDSEED (1) + + #if ( defined(_WIN32) || defined(WIN32) || \ + defined(__WIN32__) || defined(__NT__) ) + #include + #else + #include + #endif + + #include + + #ifndef bit_RDSEED + #define bit_RDSEED (1 << 18) + #endif + + /* To address compatibility issues with MacOS, given the lacking implementation + * of intrinsics we here implement rdseed in byte code so that we may use it + * anywhere the ISA extension permits it. + * + * See: https://software.intel.com/content/www/us/en/develop/articles/the-drng-library-and-manual.html + * You will find this function definition at: + * libdrng-1.0.tar.gz: https://software.intel.com/file/469237/download + */ + #if defined(__APPLE__) + # define _rdseed16_step(x) ({ unsigned char err; asm volatile(".byte 0x66; .byte 0x0f; .byte 0xc7; .byte 0xf8; setc %1":"=a"(*x), "=qm"(err)); err; }) + # define _rdseed32_step(x) ({ unsigned char err; asm volatile(".byte 0x0f; .byte 0xc7; .byte 0xf8; setc %1":"=a"(*x), "=qm"(err)); err; }) + #endif + + /* \union Useful for buffers that will need to be hashed + * where data gather comes from different int types. + */ + union block_512bits { + char byte[64]; + unsigned char ubyte[64]; + uint16_t word[32]; + uint32_t dword[16]; + uint64_t qword[8]; + unsigned long long int ulli[8]; + }; + + #endif /*LOWLEVEL_H*/ +#endif /*Detect x86*/ diff --git a/src/random.cpp b/src/random.cpp index 6634019be..1b5ffc48a 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -23,6 +23,7 @@ #include #include +#include static void RandFailure() { @@ -129,20 +130,87 @@ void GetRandBytes(unsigned char* buf, int num) } } + +/* /fn int getRDSEED( uint64_t *buff, int num) + * /brief Use Intel's SP 800-90B & C compliant Hardware implemented + * instruction to add entropy to the pool use to create keys. + * + * For details, see: https://software.intel.com/content/www/us/en/develop/blogs/the-difference-between-rdrand-and-rdseed.html + * + * /param buff Buffer to fill with random bits. + * /param num Number of 64-bit words to write to buffer. + * /return Returns 1 if the hardware returned a valid stream of random numbers, 0 otherwise. + * + */ +int getRDSEED( uint64_t *buff, uint32_t num){ + //Initialize state to 0, or failed. + uint32_t cumulativeStatus = 0; + + #ifdef LOWELEVEL_USE_RDSEEED + //Check to see if the processor running this code has + //this Instruction. Most Intel/AMD CPUs after 2015 + //should have this instruction. + uint32_t level, eax, ebx, ecx, edx; + + //Level where the RDSEED feature is described + level = 1; + + //Extract feature vector + __get_cpuid(level, &eax, &ebx, &ecx, &edx); + + //Check if RDSEED exists on this processor + if( (ecx & bit_RDSEED) == bit_RDSEED ) { + + //Re-initialize value to 1, or success + cumulativeStatus = 1; + + for( uint32_t kk = 0; kk < num; kk++){ + //Get RBG data + uint32_t rng_high, rng_low; + + int32_t status1 = _rdseed32_step( &rng_low ); + int32_t status2 = _rdseed32_step( &rng_high ); + + //Place values into a 64-bit register + uint64_t temp = rng_high; + temp <<= 32; + temp += rng_low; + + //Store into buffer + buff[kk] = temp; + + //Update status value. + //cumulativeStatus will be 1 iff all iterations are 1. + cumulativeStatus &= status1 & status2; + } + } + #endif /*LOWLEVEL_USE_RDSEED*/ + + return cumulativeStatus; +} + void GetStrongRandBytes(unsigned char* out, int num) { - assert(num <= 32); + assert(num <= 64); CSHA512 hasher; unsigned char buf[64]; // First source: OpenSSL's RNG RandAddSeedPerfmon(); - GetRandBytes(buf, 32); - hasher.Write(buf, 32); + GetRandBytes(buf, 64); + hasher.Write(buf, 64); // Second source: OS RNG GetOSRand(buf); - hasher.Write(buf, 32); + hasher.Write(buf, 64); + + //Third Source: Intel's NIST SP 800-90B & C compliant RBG + //if available, use it. + #ifdef LOWLEVEL_H + block_512bits buf2; + if ( getRDSEED(buf2.qword, 8) == 1 ) + hasher.Write(buf2.ubyte, 64); + #endif // Produce output hasher.Finalize(buf);