diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2017-04-13 15:45:30 -0700 |
---|---|---|
committer | Thiago Macieira <thiago.macieira@intel.com> | 2017-06-12 06:14:51 +0000 |
commit | 0c355e78f0cf51d4ad6cfb2eb0f289979cba843a (patch) | |
tree | 588fce0d6687efdeca024a2027f211579623f96d /src/corelib | |
parent | dfdc466dc1a7b22cbab700a188daba4f052a25ce (diff) |
QRandomGenerator: add support for hardware-based random generators
This commit adds support for the x86 RDRAND instruction for
QRandomGenerator. This is the same that libstdc++-v3 uses for
std::random_device() by default. If it fails because the hardware does
not have enough entropy collected, we fall back to the operating system
generator, which often has more entropy collected from other sources.
Change-Id: Icd0e0d4b27cb4e5eb892fffd14b5167214e1ea3f
Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/corelib')
-rw-r--r-- | src/corelib/global/qrandom.cpp | 48 |
1 files changed, 46 insertions, 2 deletions
diff --git a/src/corelib/global/qrandom.cpp b/src/corelib/global/qrandom.cpp index 99a91c2221..954e879887 100644 --- a/src/corelib/global/qrandom.cpp +++ b/src/corelib/global/qrandom.cpp @@ -44,6 +44,7 @@ #include "qrandom_p.h" #include <qobjectdefs.h> #include <qthreadstorage.h> +#include <private/qsimd_p.h> #if QT_HAS_INCLUDE(<random>) # include <random> @@ -70,6 +71,37 @@ DECLSPEC_IMPORT BOOLEAN WINAPI SystemFunction036(PVOID RandomBuffer, ULONG Rando QT_BEGIN_NAMESPACE +#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND) +static qssize_t qt_random_cpu(void *buffer, qssize_t count); + +# ifdef Q_PROCESSOR_X86_64 +# define _rdrandXX_step _rdrand64_step +# else +# define _rdrandXX_step _rdrand32_step +# endif + +static QT_FUNCTION_TARGET(RDRND) qssize_t qt_random_cpu(void *buffer, qssize_t count) +{ + unsigned *ptr = reinterpret_cast<unsigned *>(buffer); + unsigned *end = ptr + count; + + while (ptr + sizeof(qregisteruint)/sizeof(*ptr) <= end) { + if (_rdrandXX_step(reinterpret_cast<qregisteruint *>(ptr)) == 0) + goto out; + ptr += sizeof(qregisteruint)/sizeof(*ptr); + } + + if (sizeof(*ptr) != sizeof(qregisteruint) && ptr != end) { + if (_rdrand32_step(ptr)) + goto out; + ++ptr; + } + +out: + return ptr - reinterpret_cast<unsigned *>(buffer); +} +#endif + namespace { #ifdef Q_OS_UNIX class SystemRandom @@ -196,6 +228,18 @@ static Q_NORETURN void fallback_fill(quint32 *, qssize_t) } #endif +static qssize_t fill_cpu(quint32 *buffer, qssize_t count) +{ +#if defined(Q_PROCESSOR_X86) && QT_COMPILER_SUPPORTS_HERE(RDRND) + if (qCpuHasFeature(RDRND) && (uint(qt_randomdevice_control) & SkipHWRNG) == 0) + return qt_random_cpu(buffer, count); +#else + Q_UNUSED(buffer); + Q_UNUSED(count); +#endif + return 0; +} + static void fill_internal(quint32 *buffer, qssize_t count) { if (Q_UNLIKELY(uint(qt_randomdevice_control) & SetRandomData)) { @@ -204,8 +248,8 @@ static void fill_internal(quint32 *buffer, qssize_t count) return; } - qssize_t filled = 0; - if (uint(qt_randomdevice_control) & SkipSystemRNG) == 0) { + qssize_t filled = fill_cpu(buffer, count); + if (filled != count && (uint(qt_randomdevice_control) & SkipSystemRNG) == 0) { qssize_t bytesFilled = SystemRandom::fillBuffer(buffer + filled, (count - filled) * qssize_t(sizeof(*buffer))); filled += bytesFilled / qssize_t(sizeof(*buffer)); |