summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2017-04-13 15:45:30 -0700
committerThiago Macieira <thiago.macieira@intel.com>2017-06-12 06:14:51 +0000
commit0c355e78f0cf51d4ad6cfb2eb0f289979cba843a (patch)
tree588fce0d6687efdeca024a2027f211579623f96d /src/corelib
parentdfdc466dc1a7b22cbab700a188daba4f052a25ce (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.cpp48
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));