186 lines
3.7 KiB
C++
186 lines
3.7 KiB
C++
/*
|
|
* \copyright Copyright (c) 2015-2019 Governikus GmbH & Co. KG, Germany
|
|
*/
|
|
|
|
#include "Randomizer.h"
|
|
|
|
#include "SingletonHelper.h"
|
|
|
|
#include <chrono>
|
|
#include <openssl/rand.h>
|
|
#include <QRandomGenerator>
|
|
|
|
#ifdef Q_OS_WIN
|
|
#include <windows.h>
|
|
#elif defined(Q_OS_UNIX)
|
|
#if defined(Q_OS_Linux) && !defined(Q_OS_ANDROID)
|
|
#include <syscall.h>
|
|
#endif
|
|
#if defined(SYS_getrandom)
|
|
#include <linux/random.h>
|
|
#include <unistd.h>
|
|
#else
|
|
#include <QDebug>
|
|
#include <QFile>
|
|
#endif
|
|
#if defined(Q_OS_IOS) || defined(Q_OS_MACOS)
|
|
#include <Security/SecRandom.h>
|
|
#endif
|
|
#endif
|
|
|
|
|
|
using namespace governikus;
|
|
|
|
defineSingleton(Randomizer)
|
|
|
|
|
|
template<typename T, typename U = uchar> union UniversalBuffer
|
|
{
|
|
T number;
|
|
U data[sizeof(T)] = {};
|
|
};
|
|
|
|
template<typename T> QList<T> Randomizer::getEntropy()
|
|
{
|
|
QList<T> entropy;
|
|
|
|
entropy += static_cast<T>(std::chrono::system_clock::now().time_since_epoch().count());
|
|
entropy += std::random_device()();
|
|
entropy += static_cast<T>(qrand());
|
|
entropy += QRandomGenerator::securelySeeded().generate();
|
|
|
|
UniversalBuffer<T> buffer;
|
|
if (RAND_bytes(buffer.data, sizeof(buffer.data)))
|
|
{
|
|
entropy += buffer.number;
|
|
}
|
|
|
|
entropy += getEntropyWin<T>();
|
|
entropy += getEntropyUnixoid<T>();
|
|
entropy += getEntropyApple<T>();
|
|
|
|
return entropy;
|
|
}
|
|
|
|
|
|
template<typename T> QList<T> Randomizer::getEntropyWin()
|
|
{
|
|
QList<T> entropy;
|
|
|
|
#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
|
|
UniversalBuffer<T> buffer;
|
|
HCRYPTPROV provider = 0;
|
|
if (CryptAcquireContext(&provider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
|
|
{
|
|
if (CryptGenRandom(provider, sizeof(buffer.data), buffer.data))
|
|
{
|
|
entropy += buffer.number;
|
|
}
|
|
|
|
CryptReleaseContext(provider, 0);
|
|
}
|
|
#endif
|
|
|
|
return entropy;
|
|
}
|
|
|
|
|
|
template<typename T> QList<T> Randomizer::getEntropyUnixoid()
|
|
{
|
|
QList<T> entropy;
|
|
|
|
#ifdef SYS_getrandom
|
|
UniversalBuffer<T> buffer;
|
|
if (syscall(SYS_getrandom, buffer.data, sizeof(buffer.data), GRND_NONBLOCK))
|
|
{
|
|
entropy += buffer.number;
|
|
}
|
|
#elif defined(Q_OS_UNIX)
|
|
// Fallback for unixoid systems without SYS_getrandom (like linux before version 3.17 ).
|
|
// This is mainly relevant for older androids.
|
|
|
|
UniversalBuffer<T, char> buffer;
|
|
QFile file(QStringLiteral("/dev/urandom"));
|
|
if (file.open(QIODevice::ReadOnly))
|
|
{
|
|
qint64 bytesToRead = sizeof(buffer.data);
|
|
do
|
|
{
|
|
const qint64 bytesRead = file.read(buffer.data, bytesToRead);
|
|
if (bytesRead < 0)
|
|
{
|
|
qCritical() << "Failed to read" << file.fileName();
|
|
break;
|
|
}
|
|
bytesToRead -= bytesRead;
|
|
}
|
|
while (bytesToRead > 0);
|
|
|
|
entropy += buffer.number;
|
|
file.close();
|
|
}
|
|
else
|
|
{
|
|
qCritical() << "Failed to open" << file.fileName();
|
|
}
|
|
#endif
|
|
|
|
return entropy;
|
|
}
|
|
|
|
|
|
template<typename T> QList<T> Randomizer::getEntropyApple()
|
|
{
|
|
QList<T> entropy;
|
|
|
|
#if defined(Q_OS_IOS) || defined(Q_OS_MACOS)
|
|
UniversalBuffer<T> buffer;
|
|
if (SecRandomCopyBytes(kSecRandomDefault, sizeof(buffer.data), buffer.data) == 0)
|
|
{
|
|
entropy += buffer.number;
|
|
}
|
|
#endif
|
|
|
|
return entropy;
|
|
}
|
|
|
|
|
|
Randomizer::Randomizer()
|
|
{
|
|
const auto& entropy = getEntropy<std::mt19937::result_type>();
|
|
std::seed_seq seed(entropy.cbegin(), entropy.cend());
|
|
mGenerator.seed(seed);
|
|
|
|
// We need to seed pseudo random pool of openssl.
|
|
// yes, OpenSSL is an entropy source, too. But not the only one!
|
|
UniversalBuffer<std::mt19937::result_type> buffer;
|
|
buffer.number = mGenerator();
|
|
RAND_seed(buffer.data, sizeof(std::mt19937::result_type));
|
|
|
|
static const int MINIMUM_ENTROPY_SOURCES = 5;
|
|
mSecureRandom = seed.size() >= MINIMUM_ENTROPY_SOURCES;
|
|
}
|
|
|
|
|
|
Randomizer::~Randomizer()
|
|
{
|
|
}
|
|
|
|
|
|
Randomizer& Randomizer::getInstance()
|
|
{
|
|
return *Instance;
|
|
}
|
|
|
|
|
|
std::mt19937& Randomizer::getGenerator()
|
|
{
|
|
return mGenerator;
|
|
}
|
|
|
|
|
|
bool Randomizer::isSecureRandom() const
|
|
{
|
|
return mSecureRandom;
|
|
}
|