diff --git a/src/core/Database.cpp b/src/core/Database.cpp index 80d168225..f125a2786 100644 --- a/src/core/Database.cpp +++ b/src/core/Database.cpp @@ -212,7 +212,7 @@ void Database::setKey(const CompositeKey& key, const QByteArray& transformSeed, void Database::setKey(const CompositeKey& key) { - setKey(key, Random::randomArray(32)); + setKey(key, randomGen()->randomArray(32)); } bool Database::hasKey() const diff --git a/src/core/PasswordGenerator.cpp b/src/core/PasswordGenerator.cpp index 88abf663a..f8daec695 100644 --- a/src/core/PasswordGenerator.cpp +++ b/src/core/PasswordGenerator.cpp @@ -40,20 +40,20 @@ QString PasswordGenerator::generatePassword(int length, if (flags & CharFromEveryGroup) { for (int i = 0; i < groups.size(); i++) { - int pos = Random::randomUInt(groups[i].size()); + int pos = randomGen()->randomUInt(groups[i].size()); password.append(groups[i][pos]); } for (int i = groups.size(); i < length; i++) { - int pos = Random::randomUInt(passwordChars.size()); + int pos = randomGen()->randomUInt(passwordChars.size()); password.append(passwordChars[pos]); } // shuffle chars for (int i = (password.size() - 1); i >= 1; i--) { - int j = Random::randomUInt(i + 1); + int j = randomGen()->randomUInt(i + 1); QChar tmp = password[i]; password[i] = password[j]; @@ -62,7 +62,7 @@ QString PasswordGenerator::generatePassword(int length, } else { for (int i = 0; i < length; i++) { - int pos = Random::randomUInt(passwordChars.size()); + int pos = randomGen()->randomUInt(passwordChars.size()); password.append(passwordChars[pos]); } diff --git a/src/core/Uuid.cpp b/src/core/Uuid.cpp index 8cd6a9b85..e832d1e84 100644 --- a/src/core/Uuid.cpp +++ b/src/core/Uuid.cpp @@ -37,7 +37,7 @@ Uuid::Uuid(const QByteArray& data) Uuid Uuid::random() { - return Uuid(Random::randomArray(Length)); + return Uuid(randomGen()->randomArray(Length)); } QString Uuid::toBase64() const diff --git a/src/crypto/Random.cpp b/src/crypto/Random.cpp index 2869bec23..a3e14272e 100644 --- a/src/crypto/Random.cpp +++ b/src/crypto/Random.cpp @@ -25,9 +25,17 @@ #define QUINT32_MAX 4294967295U #endif +class RandomBackendGcrypt : public RandomBackend +{ +public: + void randomize(void* data, int len) Q_DECL_OVERRIDE; +}; + +Random* Random::m_instance(Q_NULLPTR); + void Random::randomize(QByteArray& ba) { - randomize(ba.data(), ba.size()); + m_backend->randomize(ba.data(), ba.size()); } QByteArray Random::randomArray(int len) @@ -51,7 +59,7 @@ quint32 Random::randomUInt(quint32 limit) // To avoid modulo bias: // Make sure rand is below the largest number where rand%limit==0 do { - randomize(&rand, 4); + m_backend->randomize(&rand, 4); } while (rand > ceil); return (rand % limit); @@ -62,13 +70,32 @@ quint32 Random::randomUIntRange(quint32 min, quint32 max) return min + randomUInt(max - min); } -void Random::randomize(void* data, int len) +Random* Random::instance() +{ + if (!m_instance) { + m_instance = new Random(new RandomBackendGcrypt()); + } + + return m_instance; +} + +void Random::createWithBackend(RandomBackend* backend) +{ + Q_ASSERT(backend); + Q_ASSERT(!m_instance); + + m_instance = new Random(backend); +} + +Random::Random(RandomBackend* backend) + : m_backend(backend) +{ +} + + +void RandomBackendGcrypt::randomize(void* data, int len) { Q_ASSERT(Crypto::initalized()); gcry_randomize(data, len, GCRY_STRONG_RANDOM); } - -Random::Random() -{ -} diff --git a/src/crypto/Random.h b/src/crypto/Random.h index 6728e99f6..813c359b6 100644 --- a/src/crypto/Random.h +++ b/src/crypto/Random.h @@ -19,26 +19,45 @@ #define KEEPASSX_RANDOM_H #include +#include + +class RandomBackend +{ +public: + virtual void randomize(void* data, int len) = 0; + virtual ~RandomBackend() {} +}; class Random { public: - static void randomize(QByteArray& ba); - static QByteArray randomArray(int len); + void randomize(QByteArray& ba); + QByteArray randomArray(int len); /** * Generate a random quint32 in the range [0, @p limit) */ - static quint32 randomUInt(quint32 limit); + quint32 randomUInt(quint32 limit); /** * Generate a random quint32 in the range [@p min, @p max) */ - static quint32 randomUIntRange(quint32 min, quint32 max); + quint32 randomUIntRange(quint32 min, quint32 max); + + static Random* instance(); + static void createWithBackend(RandomBackend* backend); private: - static void randomize(void* data, int len); - Random(); + Random(RandomBackend* backend); + + QScopedPointer m_backend; + static Random* m_instance; + + Q_DISABLE_COPY(Random) }; +inline Random* randomGen() { + return Random::instance(); +} + #endif // KEEPASSX_RANDOM_H diff --git a/src/format/KeePass2Writer.cpp b/src/format/KeePass2Writer.cpp index c22412a19..69e24746d 100644 --- a/src/format/KeePass2Writer.cpp +++ b/src/format/KeePass2Writer.cpp @@ -45,10 +45,10 @@ void KeePass2Writer::writeDatabase(QIODevice* device, Database* db) m_error = false; m_errorStr.clear(); - QByteArray masterSeed = Random::randomArray(32); - QByteArray encryptionIV = Random::randomArray(16); - QByteArray protectedStreamKey = Random::randomArray(32); - QByteArray startBytes = Random::randomArray(32); + QByteArray masterSeed = randomGen()->randomArray(32); + QByteArray encryptionIV = randomGen()->randomArray(16); + QByteArray protectedStreamKey = randomGen()->randomArray(32); + QByteArray startBytes = randomGen()->randomArray(32); QByteArray endOfHeader = "\r\n\r\n"; CryptoHash hash(CryptoHash::Sha256); diff --git a/src/keys/FileKey.cpp b/src/keys/FileKey.cpp index 77687ba74..e8cf2697e 100644 --- a/src/keys/FileKey.cpp +++ b/src/keys/FileKey.cpp @@ -121,7 +121,7 @@ void FileKey::create(QIODevice* device) xmlWriter.writeStartElement("Key"); - QByteArray data = Random::randomArray(32); + QByteArray data = randomGen()->randomArray(32); xmlWriter.writeTextElement("Data", QString::fromAscii(data.toBase64())); xmlWriter.writeEndElement();