diff options
29 files changed, 608 insertions, 180 deletions
diff --git a/src/core/Database.cpp b/src/core/Database.cpp index 4c888eab9..098cc06af 100644 --- a/src/core/Database.cpp +++ b/src/core/Database.cpp @@ -188,32 +188,51 @@ void Database::setCompressionAlgo(Database::CompressionAlgorithm algo) m_data.compressionAlgo = algo; } -void Database::setTransformRounds(quint64 rounds) +bool Database::setTransformRounds(quint64 rounds) { if (m_data.transformRounds != rounds) { + quint64 oldRounds = m_data.transformRounds; + m_data.transformRounds = rounds; if (m_data.hasKey) { - setKey(m_data.key); + if (!setKey(m_data.key)) { + m_data.transformRounds = oldRounds; + return false; + } } } + + return true; } -void Database::setKey(const CompositeKey& key, const QByteArray& transformSeed, bool updateChangedTime) +bool Database::setKey(const CompositeKey& key, const QByteArray& transformSeed, + bool updateChangedTime) { + bool ok; + QString errorString; + + QByteArray transformedMasterKey = + key.transform(transformSeed, transformRounds(), &ok, &errorString); + if (!ok) { + return false; + } + m_data.key = key; m_data.transformSeed = transformSeed; - m_data.transformedMasterKey = key.transform(transformSeed, transformRounds()); + m_data.transformedMasterKey = transformedMasterKey; m_data.hasKey = true; if (updateChangedTime) { m_metadata->setMasterKeyChanged(Tools::currentDateTimeUtc()); } Q_EMIT modifiedImmediate(); + + return true; } -void Database::setKey(const CompositeKey& key) +bool Database::setKey(const CompositeKey& key) { - setKey(key, randomGen()->randomArray(32)); + return setKey(key, randomGen()->randomArray(32)); } bool Database::hasKey() const diff --git a/src/core/Database.h b/src/core/Database.h index 3e0c675df..97ccad234 100644 --- a/src/core/Database.h +++ b/src/core/Database.h @@ -90,13 +90,14 @@ public: void setCipher(const Uuid& cipher); void setCompressionAlgo(Database::CompressionAlgorithm algo); - void setTransformRounds(quint64 rounds); - void setKey(const CompositeKey& key, const QByteArray& transformSeed, bool updateChangedTime = true); + bool setTransformRounds(quint64 rounds); + bool setKey(const CompositeKey& key, const QByteArray& transformSeed, + bool updateChangedTime = true); /** * Sets the database key and generates a random transform seed. */ - void setKey(const CompositeKey& key); + bool setKey(const CompositeKey& key); bool hasKey() const; bool verifyKey(const CompositeKey& key) const; void recycleEntry(Entry* entry); diff --git a/src/crypto/Crypto.cpp b/src/crypto/Crypto.cpp index bf3076e85..d4fc6493e 100644 --- a/src/crypto/Crypto.cpp +++ b/src/crypto/Crypto.cpp @@ -143,65 +143,137 @@ bool Crypto::checkAlgorithms() bool Crypto::selfTest() { + return testSha256() && testAes256() && testTwofish() && testSalsa20(); +} + +void Crypto::raiseError(const QString& str) +{ + m_errorStr = str; + qWarning("Crypto::selfTest: %s", qPrintable(m_errorStr)); +} + +bool Crypto::testSha256() +{ QByteArray sha256Test = CryptoHash::hash("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", CryptoHash::Sha256); if (sha256Test != QByteArray::fromHex("248D6A61D20638B8E5C026930C3E6039A33CE45964FF2167F6ECEDD419DB06C1")) { - m_errorStr = "SHA-256 mismatch."; - qWarning("Crypto::selfTest: %s", qPrintable(m_errorStr)); + raiseError("SHA-256 mismatch."); return false; } + return true; +} + +bool Crypto::testAes256() +{ QByteArray key = QByteArray::fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"); QByteArray iv = QByteArray::fromHex("000102030405060708090a0b0c0d0e0f"); QByteArray plainText = QByteArray::fromHex("6bc1bee22e409f96e93d7e117393172a"); plainText.append(QByteArray::fromHex("ae2d8a571e03ac9c9eb76fac45af8e51")); QByteArray cipherText = QByteArray::fromHex("f58c4c04d6e5f1ba779eabfb5f7bfbd6"); cipherText.append(QByteArray::fromHex("9cfc4e967edb808d679f777bc6702c7d")); + bool ok; - SymmetricCipher aes256Encrypt(SymmetricCipher::Aes256, SymmetricCipher::Cbc, SymmetricCipher::Encrypt, key, iv); - if (aes256Encrypt.process(plainText) != cipherText) { - m_errorStr = "AES-256 encryption mismatch."; - qWarning("Crypto::selfTest: %s", qPrintable(m_errorStr)); + SymmetricCipher aes256Encrypt(SymmetricCipher::Aes256, SymmetricCipher::Cbc, SymmetricCipher::Encrypt); + if (!aes256Encrypt.init(key, iv)) { + raiseError(aes256Encrypt.errorString()); + return false; + } + QByteArray encryptedText = aes256Encrypt.process(plainText, &ok); + if (!ok) { + raiseError(aes256Encrypt.errorString()); + return false; + } + if (encryptedText != cipherText) { + raiseError("AES-256 encryption mismatch."); return false; } - SymmetricCipher aes256Descrypt(SymmetricCipher::Aes256, SymmetricCipher::Cbc, SymmetricCipher::Decrypt, key, iv); - if (aes256Descrypt.process(cipherText) != plainText) { - m_errorStr = "AES-256 decryption mismatch."; - qWarning("Crypto::selfTest: %s", qPrintable(m_errorStr)); + SymmetricCipher aes256Descrypt(SymmetricCipher::Aes256, SymmetricCipher::Cbc, SymmetricCipher::Decrypt); + if (!aes256Descrypt.init(key, iv)) { + raiseError(aes256Descrypt.errorString()); + return false; + } + QByteArray decryptedText = aes256Descrypt.process(cipherText, &ok); + if (!ok) { + raiseError(aes256Descrypt.errorString()); + return false; + } + if (decryptedText != plainText) { + raiseError("AES-256 decryption mismatch."); return false; } - // Twofish - cipherText = QByteArray::fromHex("e0227c3cc80f3cb1b2ed847cc6f57d3c"); + return true; +} + +bool Crypto::testTwofish() +{ + QByteArray key = QByteArray::fromHex("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4"); + QByteArray iv = QByteArray::fromHex("000102030405060708090a0b0c0d0e0f"); + QByteArray plainText = QByteArray::fromHex("6bc1bee22e409f96e93d7e117393172a"); + plainText.append(QByteArray::fromHex("ae2d8a571e03ac9c9eb76fac45af8e51")); + QByteArray cipherText = QByteArray::fromHex("e0227c3cc80f3cb1b2ed847cc6f57d3c"); cipherText.append(QByteArray::fromHex("657b1e7960b30fb7c8d62e72ae37c3a0")); + bool ok; - SymmetricCipher twofishEncrypt(SymmetricCipher::Twofish, SymmetricCipher::Cbc, SymmetricCipher::Encrypt, key, iv); - if (twofishEncrypt.process(plainText) != cipherText) { - m_errorStr = "Twofish encryption mismatch."; - qWarning("Crypto::selfTest: %s", qPrintable(m_errorStr)); + SymmetricCipher twofishEncrypt(SymmetricCipher::Twofish, SymmetricCipher::Cbc, SymmetricCipher::Encrypt); + if (!twofishEncrypt.init(key, iv)) { + raiseError(twofishEncrypt.errorString()); + return false; + } + QByteArray encryptedText = twofishEncrypt.process(plainText, &ok); + if (!ok) { + raiseError(twofishEncrypt.errorString()); return false; } + if (encryptedText != cipherText) { + raiseError("Twofish encryption mismatch."); + return false; + } + - SymmetricCipher twofishDecrypt(SymmetricCipher::Twofish, SymmetricCipher::Cbc, SymmetricCipher::Decrypt, key, iv); - if (twofishDecrypt.process(cipherText) != plainText) { - m_errorStr = "Twofish decryption mismatch."; - qWarning("Crypto::selfTest: %s", qPrintable(m_errorStr)); + SymmetricCipher twofishDecrypt(SymmetricCipher::Twofish, SymmetricCipher::Cbc, SymmetricCipher::Decrypt); + if (!twofishDecrypt.init(key, iv)) { + raiseError(twofishEncrypt.errorString()); + return false; + } + QByteArray decryptedText = twofishDecrypt.process(cipherText, &ok); + if (!ok) { + raiseError(twofishDecrypt.errorString()); return false; } + if (decryptedText != plainText) { + raiseError("Twofish encryption mismatch."); + return false; + } + + return true; +} +bool Crypto::testSalsa20() +{ QByteArray salsa20Key = QByteArray::fromHex("F3F4F5F6F7F8F9FAFBFCFDFEFF000102030405060708090A0B0C0D0E0F101112"); QByteArray salsa20iv = QByteArray::fromHex("0000000000000000"); QByteArray salsa20Plain = QByteArray::fromHex("00000000000000000000000000000000"); QByteArray salsa20Cipher = QByteArray::fromHex("B4C0AFA503BE7FC29A62058166D56F8F"); + bool ok; SymmetricCipher salsa20Stream(SymmetricCipher::Salsa20, SymmetricCipher::Stream, - SymmetricCipher::Encrypt, salsa20Key, salsa20iv); + SymmetricCipher::Encrypt); + if (!salsa20Stream.init(salsa20Key, salsa20iv)) { + raiseError(salsa20Stream.errorString()); + return false; + } - if (salsa20Stream.process(salsa20Plain) != salsa20Cipher) { - m_errorStr = "Salsa20 stream cipher mismatch."; - qWarning("Crypto::selfTest: %s", qPrintable(m_errorStr)); + QByteArray salsaProcessed = salsa20Stream.process(salsa20Plain, &ok); + if (!ok) { + raiseError(salsa20Stream.errorString()); + return false; + } + if (salsaProcessed != salsa20Cipher) { + raiseError("Salsa20 stream cipher mismatch."); return false; } diff --git a/src/crypto/Crypto.h b/src/crypto/Crypto.h index 9926f14b2..07f6454fe 100644 --- a/src/crypto/Crypto.h +++ b/src/crypto/Crypto.h @@ -34,6 +34,11 @@ private: Crypto(); static bool checkAlgorithms(); static bool selfTest(); + static void raiseError(const QString& str); + static bool testSha256(); + static bool testAes256(); + static bool testTwofish(); + static bool testSalsa20(); static bool m_initalized; static QString m_errorStr; diff --git a/src/crypto/SymmetricCipher.cpp b/src/crypto/SymmetricCipher.cpp index 5f9222653..454548caa 100644 --- a/src/crypto/SymmetricCipher.cpp +++ b/src/crypto/SymmetricCipher.cpp @@ -22,17 +22,39 @@ #include "crypto/SymmetricCipherSalsa20.h" SymmetricCipher::SymmetricCipher(SymmetricCipher::Algorithm algo, SymmetricCipher::Mode mode, - SymmetricCipher::Direction direction, const QByteArray& key, const QByteArray& iv) + SymmetricCipher::Direction direction) : m_backend(createBackend(algo, mode, direction)) + , m_initialized(false) { - m_backend->setKey(key); - m_backend->setIv(iv); } SymmetricCipher::~SymmetricCipher() { } +bool SymmetricCipher::init(const QByteArray& key, const QByteArray& iv) +{ + if (!m_backend->init()) { + return false; + } + + if (!m_backend->setKey(key)) { + return false; + } + + if (!m_backend->setIv(iv)) { + return false; + } + + m_initialized = true; + return true; +} + +bool SymmetricCipher::isInitalized() const +{ + return m_initialized; +} + SymmetricCipherBackend* SymmetricCipher::createBackend(SymmetricCipher::Algorithm algo, SymmetricCipher::Mode mode, SymmetricCipher::Direction direction) { @@ -55,12 +77,17 @@ SymmetricCipherBackend* SymmetricCipher::createBackend(SymmetricCipher::Algorith } } -void SymmetricCipher::reset() +bool SymmetricCipher::reset() { - m_backend->reset(); + return m_backend->reset(); } int SymmetricCipher::blockSize() const { return m_backend->blockSize(); } + +QString SymmetricCipher::errorString() const +{ + return m_backend->errorString(); +} diff --git a/src/crypto/SymmetricCipher.h b/src/crypto/SymmetricCipher.h index d036e532e..65cab76fa 100644 --- a/src/crypto/SymmetricCipher.h +++ b/src/crypto/SymmetricCipher.h @@ -20,6 +20,7 @@ #include <QByteArray> #include <QScopedPointer> +#include <QString> #include "core/Global.h" #include "crypto/SymmetricCipherBackend.h" @@ -48,30 +49,35 @@ public: }; SymmetricCipher(SymmetricCipher::Algorithm algo, SymmetricCipher::Mode mode, - SymmetricCipher::Direction direction, const QByteArray& key, const QByteArray& iv); + SymmetricCipher::Direction direction); ~SymmetricCipher(); - inline QByteArray process(const QByteArray& data) { - return m_backend->process(data); + bool init(const QByteArray& key, const QByteArray& iv); + bool isInitalized() const; + + inline QByteArray process(const QByteArray& data, bool* ok) { + return m_backend->process(data, ok); } - inline void processInPlace(QByteArray& data) { - m_backend->processInPlace(data); + inline bool processInPlace(QByteArray& data) { + return m_backend->processInPlace(data); } - inline void processInPlace(QByteArray& data, quint64 rounds) { + inline bool processInPlace(QByteArray& data, quint64 rounds) { Q_ASSERT(rounds > 0); - m_backend->processInPlace(data, rounds); + return m_backend->processInPlace(data, rounds); } - void reset(); + bool reset(); int blockSize() const; + QString errorString() const; private: static SymmetricCipherBackend* createBackend(SymmetricCipher::Algorithm algo, SymmetricCipher::Mode mode, SymmetricCipher::Direction direction); const QScopedPointer<SymmetricCipherBackend> m_backend; + bool m_initialized; Q_DISABLE_COPY(SymmetricCipher) }; diff --git a/src/crypto/SymmetricCipherBackend.h b/src/crypto/SymmetricCipherBackend.h index e6110cba5..763ffb40d 100644 --- a/src/crypto/SymmetricCipherBackend.h +++ b/src/crypto/SymmetricCipherBackend.h @@ -24,15 +24,18 @@ class SymmetricCipherBackend { public: virtual ~SymmetricCipherBackend() {} - virtual void setKey(const QByteArray& key) = 0; - virtual void setIv(const QByteArray& iv) = 0; + virtual bool init() = 0; + virtual bool setKey(const QByteArray& key) = 0; + virtual bool setIv(const QByteArray& iv) = 0; - virtual QByteArray process(const QByteArray& data) = 0; - virtual void processInPlace(QByteArray& data) = 0; - virtual void processInPlace(QByteArray& data, quint64 rounds) = 0; + virtual QByteArray process(const QByteArray& data, bool* ok) = 0; + virtual bool processInPlace(QByteArray& data) = 0; + virtual bool processInPlace(QByteArray& data, quint64 rounds) = 0; - virtual void reset() = 0; + virtual bool reset() = 0; virtual int blockSize() const = 0; + + virtual QString errorString() const = 0; }; #endif // KEEPASSX_SYMMETRICCIPHERBACKEND_H diff --git a/src/crypto/SymmetricCipherGcrypt.cpp b/src/crypto/SymmetricCipherGcrypt.cpp index cf52bafab..5c4fe6ab3 100644 --- a/src/crypto/SymmetricCipherGcrypt.cpp +++ b/src/crypto/SymmetricCipherGcrypt.cpp @@ -22,22 +22,12 @@ SymmetricCipherGcrypt::SymmetricCipherGcrypt(SymmetricCipher::Algorithm algo, SymmetricCipher::Mode mode, SymmetricCipher::Direction direction) - : m_algo(gcryptAlgo(algo)) + : m_ctx(Q_NULLPTR) + , m_algo(gcryptAlgo(algo)) , m_mode(gcryptMode(mode)) , m_direction(direction) , m_blockSize(-1) { - Q_ASSERT(Crypto::initalized()); - - gcry_error_t error; - - error = gcry_cipher_open(&m_ctx, m_algo, m_mode, 0); - Q_ASSERT(error == 0); // TODO: real error checking - - size_t blockSizeT; - error = gcry_cipher_algo_info(m_algo, GCRYCTL_GET_BLKLEN, Q_NULLPTR, &blockSizeT); - Q_ASSERT(error == 0); - m_blockSize = blockSizeT; } SymmetricCipherGcrypt::~SymmetricCipherGcrypt() @@ -83,21 +73,65 @@ int SymmetricCipherGcrypt::gcryptMode(SymmetricCipher::Mode mode) } } -void SymmetricCipherGcrypt::setKey(const QByteArray& key) +void SymmetricCipherGcrypt::setErrorString(gcry_error_t err) +{ + const char* gcryptError = gcry_strerror(err); + const char* gcryptErrorSource = gcry_strsource(err); + + m_errorString = QString("%1/%2").arg(QString::fromLocal8Bit(gcryptErrorSource), + QString::fromLocal8Bit(gcryptError)); +} + +bool SymmetricCipherGcrypt::init() +{ + Q_ASSERT(Crypto::initalized()); + + gcry_error_t error; + + error = gcry_cipher_open(&m_ctx, m_algo, m_mode, 0); + if (error != 0) { + setErrorString(error); + return false; + } + + size_t blockSizeT; + error = gcry_cipher_algo_info(m_algo, GCRYCTL_GET_BLKLEN, Q_NULLPTR, &blockSizeT); + if (error != 0) { + setErrorString(error); + return false; + } + + m_blockSize = blockSizeT; + return true; +} + +bool SymmetricCipherGcrypt::setKey(const QByteArray& key) { m_key = key; gcry_error_t error = gcry_cipher_setkey(m_ctx, m_key.constData(), m_key.size()); - Q_ASSERT(error == 0); + + if (error != 0) { + setErrorString(error); + return false; + } + + return true; } -void SymmetricCipherGcrypt::setIv(const QByteArray& iv) +bool SymmetricCipherGcrypt::setIv(const QByteArray& iv) { m_iv = iv; gcry_error_t error = gcry_cipher_setiv(m_ctx, m_iv.constData(), m_iv.size()); - Q_ASSERT(error == 0); + + if (error != 0) { + setErrorString(error); + return false; + } + + return true; } -QByteArray SymmetricCipherGcrypt::process(const QByteArray& data) +QByteArray SymmetricCipherGcrypt::process(const QByteArray& data, bool* ok) { // TODO: check block size @@ -113,12 +147,16 @@ QByteArray SymmetricCipherGcrypt::process(const QByteArray& data) error = gcry_cipher_encrypt(m_ctx, result.data(), data.size(), data.constData(), data.size()); } - Q_ASSERT(error == 0); + if (error != 0) { + setErrorString(error); + *ok = false; + } + *ok = true; return result; } -void SymmetricCipherGcrypt::processInPlace(QByteArray& data) +bool SymmetricCipherGcrypt::processInPlace(QByteArray& data) { // TODO: check block size @@ -131,10 +169,15 @@ void SymmetricCipherGcrypt::processInPlace(QByteArray& data) error = gcry_cipher_encrypt(m_ctx, data.data(), data.size(), Q_NULLPTR, 0); } - Q_ASSERT(error == 0); + if (error != 0) { + setErrorString(error); + return false; + } + + return true; } -void SymmetricCipherGcrypt::processInPlace(QByteArray& data, quint64 rounds) +bool SymmetricCipherGcrypt::processInPlace(QByteArray& data, quint64 rounds) { // TODO: check block size @@ -146,28 +189,52 @@ void SymmetricCipherGcrypt::processInPlace(QByteArray& data, quint64 rounds) if (m_direction == SymmetricCipher::Decrypt) { for (quint64 i = 0; i != rounds; ++i) { error = gcry_cipher_decrypt(m_ctx, rawData, size, Q_NULLPTR, 0); - Q_ASSERT(error == 0); + + if (error != 0) { + setErrorString(error); + return false; + } } } else { for (quint64 i = 0; i != rounds; ++i) { error = gcry_cipher_encrypt(m_ctx, rawData, size, Q_NULLPTR, 0); - Q_ASSERT(error == 0); + + if (error != 0) { + setErrorString(error); + return false; + } } } + + return true; } -void SymmetricCipherGcrypt::reset() +bool SymmetricCipherGcrypt::reset() { gcry_error_t error; error = gcry_cipher_reset(m_ctx); - Q_ASSERT(error == 0); + if (error != 0) { + setErrorString(error); + return false; + } + error = gcry_cipher_setiv(m_ctx, m_iv.constData(), m_iv.size()); - Q_ASSERT(error == 0); + if (error != 0) { + setErrorString(error); + return false; + } + + return true; } int SymmetricCipherGcrypt::blockSize() const { return m_blockSize; } + +QString SymmetricCipherGcrypt::errorString() const +{ + return m_errorString; +} diff --git a/src/crypto/SymmetricCipherGcrypt.h b/src/crypto/SymmetricCipherGcrypt.h index c22059a4e..bc1560097 100644 --- a/src/crypto/SymmetricCipherGcrypt.h +++ b/src/crypto/SymmetricCipherGcrypt.h @@ -29,19 +29,24 @@ public: SymmetricCipherGcrypt(SymmetricCipher::Algorithm algo, SymmetricCipher::Mode mode, SymmetricCipher::Direction direction); ~SymmetricCipherGcrypt(); - void setKey(const QByteArray& key); - void setIv(const QByteArray& iv); - QByteArray process(const QByteArray& data); - void processInPlace(QByteArray& data); - void processInPlace(QByteArray& data, quint64 rounds); + bool init(); + bool setKey(const QByteArray& key); + bool setIv(const QByteArray& iv); - void reset(); + QByteArray process(const QByteArray& data, bool* ok); + bool processInPlace(QByteArray& data); + bool processInPlace(QByteArray& data, quint64 rounds); + + bool reset(); int blockSize() const; + QString errorString() const; + private: static int gcryptAlgo(SymmetricCipher::Algorithm algo); static int gcryptMode(SymmetricCipher::Mode mode); + void setErrorString(gcry_error_t err); gcry_cipher_hd_t m_ctx; const int m_algo; @@ -50,6 +55,7 @@ private: QByteArray m_key; QByteArray m_iv; int m_blockSize; + QString m_errorString; }; #endif // KEEPASSX_SYMMETRICCIPHERGCRYPT_H diff --git a/src/crypto/SymmetricCipherSalsa20.h b/src/crypto/SymmetricCipherSalsa20.h index e3e4726f8..6a5c24562 100644 --- a/src/crypto/SymmetricCipherSalsa20.h +++ b/src/crypto/SymmetricCipherSalsa20.h @@ -28,17 +28,18 @@ public: SymmetricCipherSalsa20(SymmetricCipher::Algorithm algo, SymmetricCipher::Mode mode, SymmetricCipher::Direction direction); ~SymmetricCipherSalsa20(); + bool init(); void setAlgorithm(SymmetricCipher::Algorithm algo); void setMode(SymmetricCipher::Mode mode); void setDirection(SymmetricCipher::Direction direction); - void setKey(const QByteArray& key); - void setIv(const QByteArray& iv); + bool setKey(const QByteArray& key); + bool setIv(const QByteArray& iv); - QByteArray process(const QByteArray& data); - void processInPlace(QByteArray& data); - void processInPlace(QByteArray& data, quint64 rounds); + QByteArray process(const QByteArray& data, bool* ok); + bool processInPlace(QByteArray& data); + bool processInPlace(QByteArray& data, quint64 rounds); - void reset(); + bool reset(); int blockSize() const; private: diff --git a/src/format/KeePass1Reader.cpp b/src/format/KeePass1Reader.cpp index d4760b9e7..a15c832b3 100644 --- a/src/format/KeePass1Reader.cpp +++ b/src/format/KeePass1Reader.cpp @@ -154,14 +154,16 @@ Database* KeePass1Reader::readDatabase(QIODevice* device, const QString& passwor raiseError("Invalid number of transform rounds"); return Q_NULLPTR; } - m_db->setTransformRounds(m_transformRounds); + if (!m_db->setTransformRounds(m_transformRounds)) { + raiseError(tr("Unable to calculate master key")); + return Q_NULLPTR; + } qint64 contentPos = m_device->pos(); QScopedPointer<SymmetricCipherStream> cipherStream(testKeys(password, keyfileData, contentPos)); if (!cipherStream) { - raiseError("Unable to create cipher stream"); return Q_NULLPTR; } @@ -234,7 +236,10 @@ Database* KeePass1Reader::readDatabase(QIODevice* device, const QString& passwor key.addKey(newFileKey); } - db->setKey(key); + if (!db->setKey(key)) { + raiseError(tr("Unable to calculate master key")); + return Q_NULLPTR; + } return db.take(); } @@ -326,16 +331,26 @@ SymmetricCipherStream* KeePass1Reader::testKeys(const QString& password, const Q } QByteArray finalKey = key(passwordData, keyfileData); + if (finalKey.isEmpty()) { + return Q_NULLPTR; + } if (m_encryptionFlags & KeePass1::Rijndael) { cipherStream.reset(new SymmetricCipherStream(m_device, SymmetricCipher::Aes256, - SymmetricCipher::Cbc, SymmetricCipher::Decrypt, finalKey, m_encryptionIV)); + SymmetricCipher::Cbc, SymmetricCipher::Decrypt)); } else { cipherStream.reset(new SymmetricCipherStream(m_device, SymmetricCipher::Twofish, - SymmetricCipher::Cbc, SymmetricCipher::Decrypt, finalKey, m_encryptionIV)); + SymmetricCipher::Cbc, SymmetricCipher::Decrypt)); } - cipherStream->open(QIODevice::ReadOnly); + if (!cipherStream->init(finalKey, m_encryptionIV)) { + raiseError(cipherStream->errorString()); + return Q_NULLPTR; + } + if (!cipherStream->open(QIODevice::ReadOnly)) { + raiseError(cipherStream->errorString()); + return Q_NULLPTR; + } bool success = verifyKey(cipherStream.data()); @@ -372,9 +387,18 @@ QByteArray KeePass1Reader::key(const QByteArray& password, const QByteArray& key key.setPassword(password); key.setKeyfileData(keyfileData); + bool ok; + QString errorString; + QByteArray transformedKey = key.transform(m_transformSeed, m_transformRounds, &ok, &errorString); + + if (!ok) { + raiseError(errorString); + return QByteArray(); + } + CryptoHash hash(CryptoHash::Sha256); hash.addData(m_masterSeed); - hash.addData(key.transform(m_transformSeed, m_transformRounds)); + hash.addData(transformedKey); return hash.result(); } diff --git a/src/format/KeePass2RandomStream.cpp b/src/format/KeePass2RandomStream.cpp index 8b4a7c8e2..1944e5d5b 100644 --- a/src/format/KeePass2RandomStream.cpp +++ b/src/format/KeePass2RandomStream.cpp @@ -20,14 +20,19 @@ #include "crypto/CryptoHash.h" #include "format/KeePass2.h" -KeePass2RandomStream::KeePass2RandomStream(const QByteArray& key) - : m_cipher(SymmetricCipher::Salsa20, SymmetricCipher::Stream, SymmetricCipher::Encrypt, - CryptoHash::hash(key, CryptoHash::Sha256), KeePass2::INNER_STREAM_SALSA20_IV) +KeePass2RandomStream::KeePass2RandomStream() + : m_cipher(SymmetricCipher::Salsa20, SymmetricCipher::Stream, SymmetricCipher::Encrypt) , m_offset(0) { } -QByteArray KeePass2RandomStream::randomBytes(int size) +bool KeePass2RandomStream::init(const QByteArray& key) +{ + return m_cipher.init(CryptoHash::hash(key, CryptoHash::Sha256), + KeePass2::INNER_STREAM_SALSA20_IV); +} + +QByteArray KeePass2RandomStream::randomBytes(int size, bool* ok) { QByteArray result; @@ -35,7 +40,10 @@ QByteArray KeePass2RandomStream::randomBytes(int size) while (bytesRemaining > 0) { if (m_buffer.size() == m_offset) { - loadBlock(); + if (!loadBlock()) { + *ok = false; + return QByteArray(); + } } int bytesToCopy = qMin(bytesRemaining, m_buffer.size() - m_offset); @@ -44,12 +52,20 @@ QByteArray KeePass2RandomStream::randomBytes(int size) bytesRemaining -= bytesToCopy; } + *ok = true; return result; } -QByteArray KeePass2RandomStream::process(const QByteArray& data) +QByteArray KeePass2RandomStream::process(const QByteArray& data, bool* ok) { - QByteArray randomData = randomBytes(data.size()); + bool randomBytesOk; + + QByteArray randomData = randomBytes(data.size(), &randomBytesOk); + if (!randomBytesOk) { + *ok = false; + return QByteArray(); + } + QByteArray result; result.resize(data.size()); @@ -57,23 +73,39 @@ QByteArray KeePass2RandomStream::process(const QByteArray& data) result[i] = data[i] ^ randomData[i]; } + *ok = true; return result; } -void KeePass2RandomStream::processInPlace(QByteArray& data) +bool KeePass2RandomStream::processInPlace(QByteArray& data) { - QByteArray randomData = randomBytes(data.size()); + bool ok; + QByteArray randomData = randomBytes(data.size(), &ok); + if (!ok) { + return false; + } for (int i = 0; i < data.size(); i++) { data[i] = data[i] ^ randomData[i]; } + + return true; +} + +QString KeePass2RandomStream::errorString() const +{ + return m_cipher.errorString(); } -void KeePass2RandomStream::loadBlock() +bool KeePass2RandomStream::loadBlock() { Q_ASSERT(m_offset == m_buffer.size()); m_buffer.fill('\0', m_cipher.blockSize()); - m_cipher.processInPlace(m_buffer); + if (!m_cipher.processInPlace(m_buffer)) { + return false; + } m_offset = 0; + + return true; } diff --git a/src/format/KeePass2RandomStream.h b/src/format/KeePass2RandomStream.h index c5bcf8cdb..c951a95ad 100644 --- a/src/format/KeePass2RandomStream.h +++ b/src/format/KeePass2RandomStream.h @@ -25,13 +25,15 @@ class KeePass2RandomStream { public: - explicit KeePass2RandomStream(const QByteArray& key); - QByteArray randomBytes(int size); - QByteArray process(const QByteArray& data); - void processInPlace(QByteArray& data); + KeePass2RandomStream(); + bool init(const QByteArray& key); + QByteArray randomBytes(int size, bool* ok); + QByteArray process(const QByteArray& data, bool* ok); + bool processInPlace(QByteArray& data); + QString errorString() const; private: - void loadBlock(); + bool loadBlock(); SymmetricCipher m_cipher; QByteArray m_buffer; diff --git a/src/format/KeePass2Reader.cpp b/src/format/KeePass2Reader.cpp index 72b4d8e06..20d20d862 100644 --- a/src/format/KeePass2Reader.cpp +++ b/src/format/KeePass2Reader.cpp @@ -96,16 +96,26 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke return Q_NULLPTR; } - m_db->setKey(key, m_transformSeed, false); + if (!m_db->setKey(key, m_transformSeed, false)) { + raiseError(tr("Unable to calculate master key")); + return Q_NULLPTR; + } CryptoHash hash(CryptoHash::Sha256); hash.addData(m_masterSeed); hash.addData(m_db->transformedMasterKey()); QByteArray finalKey = hash.result(); - SymmetricCipherStream cipherStream(m_device, SymmetricCipher::Aes256, SymmetricCipher::Cbc, - SymmetricCipher::Decrypt, finalKey, m_encryptionIV); - cipherStream.open(QIODevice::ReadOnly); + SymmetricCipherStream cipherStream(m_device, SymmetricCipher::Aes256, + SymmetricCipher::Cbc, SymmetricCipher::Decrypt); + if (!cipherStream.init(finalKey, m_encryptionIV)) { + raiseError(cipherStream.errorString()); + return Q_NULLPTR; + } + if (!cipherStream.open(QIODevice::ReadOnly)) { + raiseError(cipherStream.errorString()); + return Q_NULLPTR; + } QByteArray realStart = cipherStream.read(32); @@ -115,7 +125,10 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke } HashedBlockStream hashedStream(&cipherStream); - hashedStream.open(QIODevice::ReadOnly); + if (!hashedStream.open(QIODevice::ReadOnly)) { + raiseError(hashedStream.errorString()); + return Q_NULLPTR; + } QIODevice* xmlDevice; QScopedPointer<QtIOCompressor> ioCompressor; @@ -126,11 +139,18 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke else { ioCompressor.reset(new QtIOCompressor(&hashedStream)); ioCompressor->setStreamFormat(QtIOCompressor::GzipFormat); - ioCompressor->open(QIODevice::ReadOnly); + if (!ioCompressor->open(QIODevice::ReadOnly)) { + raiseError(ioCompressor->errorString()); + return Q_NULLPTR; + } xmlDevice = ioCompressor.data(); } - KeePass2RandomStream randomStream(m_protectedStreamKey); + KeePass2RandomStream randomStream; + if (!randomStream.init(m_protectedStreamKey)) { + raiseError(randomStream.errorString()); + return Q_NULLPTR; + } QScopedPointer<QBuffer> buffer; @@ -340,7 +360,9 @@ void KeePass2Reader::setTansformRounds(const QByteArray& data) raiseError("Invalid transform rounds size"); } else { - m_db->setTransformRounds(Endian::bytesToUInt64(data, KeePass2::BYTEORDER)); + if (!m_db->setTransformRounds(Endian::bytesToUInt64(data, KeePass2::BYTEORDER))) { + raiseError(tr("Unable to calculate master key")); + } } } diff --git a/src/format/KeePass2Writer.cpp b/src/format/KeePass2Writer.cpp index 69e24746d..f233ac733 100644 --- a/src/format/KeePass2Writer.cpp +++ b/src/format/KeePass2Writer.cpp @@ -88,13 +88,20 @@ void KeePass2Writer::writeDatabase(QIODevice* device, Database* db) CHECK_RETURN(writeData(header.data())); SymmetricCipherStream cipherStream(device, SymmetricCipher::Aes256, SymmetricCipher::Cbc, - SymmetricCipher::Encrypt, finalKey, encryptionIV); - cipherStream.open(QIODevice::WriteOnly); + SymmetricCipher::Encrypt); + cipherStream.init(finalKey, encryptionIV); + if (!cipherStream.open(QIODevice::WriteOnly)) { + raiseError(cipherStream.errorString()); + return; + } m_device = &cipherStream; CHECK_RETURN(writeData(startBytes)); HashedBlockStream hashedStream(&cipherStream); - hashedStream.open(QIODevice::WriteOnly); + if (!hashedStream.open(QIODevice::WriteOnly)) { + raiseError(hashedStream.errorString()); + return; + } QScopedPointer<QtIOCompressor> ioCompressor; @@ -104,14 +111,25 @@ void KeePass2Writer::writeDatabase(QIODevice* device, Database* db) else { ioCompressor.reset(new QtIOCompressor(&hashedStream)); ioCompressor->setStreamFormat(QtIOCompressor::GzipFormat); - ioCompressor->open(QIODevice::WriteOnly); + if (!ioCompressor->open(QIODevice::WriteOnly)) { + raiseError(ioCompressor->errorString()); + return; + } m_device = ioCompressor.data(); } - KeePass2RandomStream randomStream(protectedStreamKey); + KeePass2RandomStream randomStream; + if (!randomStream.init(protectedStreamKey)) { + raiseError(randomStream.errorString()); + return; + } KeePass2XmlWriter xmlWriter; xmlWriter.writeDatabase(m_device, db, &randomStream, headerHash); + + if (xmlWriter.hasError()) { + raiseError(xmlWriter.errorString()); + } } bool KeePass2Writer::writeData(const QByteArray& data) diff --git a/src/format/KeePass2XmlReader.cpp b/src/format/KeePass2XmlReader.cpp index a5ceb2186..c38448861 100644 --- a/src/format/KeePass2XmlReader.cpp +++ b/src/format/KeePass2XmlReader.cpp @@ -809,7 +809,16 @@ void KeePass2XmlReader::parseEntryString(Entry* entry) if (isProtected && !value.isEmpty()) { if (m_randomStream) { - value = QString::fromUtf8(m_randomStream->process(QByteArray::fromBase64(value.toLatin1()))); + QByteArray ciphertext = QByteArray::fromBase64(value.toLatin1()); + bool ok; + QByteArray plaintext = m_randomStream->process(ciphertext, &ok); + if (!ok) { + value.clear(); + raiseError(m_randomStream->errorString()); + } + else { + value = QString::fromUtf8(plaintext); + } } else { raiseError("Unable to decrypt entry string"); diff --git a/src/format/KeePass2XmlWriter.cpp b/src/format/KeePass2XmlWriter.cpp index 603649812..dda98011c 100644 --- a/src/format/KeePass2XmlWriter.cpp +++ b/src/format/KeePass2XmlWriter.cpp @@ -28,6 +28,7 @@ KeePass2XmlWriter::KeePass2XmlWriter() : m_db(Q_NULLPTR) , m_meta(Q_NULLPTR) , m_randomStream(Q_NULLPTR) + , m_error(false) { m_xml.setAutoFormatting(true); m_xml.setAutoFormattingIndent(-1); // 1 tab @@ -65,6 +66,16 @@ void KeePass2XmlWriter::writeDatabase(const QString& filename, Database* db) writeDatabase(&file, db); } +bool KeePass2XmlWriter::hasError() +{ + return m_error; +} + +QString KeePass2XmlWriter::errorString() +{ + return m_errorStr; +} + void KeePass2XmlWriter::generateIdMap() { QList<Entry*> allEntries = m_db->rootGroup()->entriesRecursive(true); @@ -340,7 +351,11 @@ void KeePass2XmlWriter::writeEntry(const Entry* entry) if (protect) { if (m_randomStream) { m_xml.writeAttribute("Protected", "True"); - QByteArray rawData = m_randomStream->process(entry->attributes()->value(key).toUtf8()); + bool ok; + QByteArray rawData = m_randomStream->process(entry->attributes()->value(key).toUtf8(), &ok); + if (!ok) { + raiseError(m_randomStream->errorString()); + } value = QString::fromLatin1(rawData.toBase64()); } else { @@ -527,3 +542,9 @@ QString KeePass2XmlWriter::colorPartToString(int value) return str; } + +void KeePass2XmlWriter::raiseError(const QString& errorMessage) +{ + m_error = true; + m_errorStr = errorMessage; +} diff --git a/src/format/KeePass2XmlWriter.h b/src/format/KeePass2XmlWriter.h index 16812fb9c..ea6212448 100644 --- a/src/format/KeePass2XmlWriter.h +++ b/src/format/KeePass2XmlWriter.h @@ -39,7 +39,7 @@ public: void writeDatabase(QIODevice* device, Database* db, KeePass2RandomStream* randomStream = Q_NULLPTR, const QByteArray& headerHash = QByteArray()); void writeDatabase(const QString& filename, Database* db); - bool error(); + bool hasError(); QString errorString(); private: @@ -74,12 +74,16 @@ private: void writeTriState(const QString& qualifiedName, Group::TriState triState); QString colorPartToString(int value); + void raiseError(const QString& errorMessage); + QXmlStreamWriter m_xml; Database* m_db; Metadata* m_meta; KeePass2RandomStream* m_randomStream; QByteArray m_headerHash; QHash<QByteArray, int> m_idMap; + bool m_error; + QString m_errorStr; }; #endif // KEEPASSX_KEEPASS2XMLWRITER_H diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index 369c69037..8d79c1a92 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -599,8 +599,13 @@ void DatabaseWidget::updateMasterKey(bool accepted) { if (accepted) { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); - m_db->setKey(m_changeMasterKeyWidget->newMasterKey()); + bool result = m_db->setKey(m_changeMasterKeyWidget->newMasterKey()); QApplication::restoreOverrideCursor(); + + if (!result) { + MessageBox::critical(this, tr("Error"), tr("Unable to calculate master key")); + return; + } } else if (!m_db->hasKey()) { Q_EMIT closeRequest(); diff --git a/src/keys/CompositeKey.cpp b/src/keys/CompositeKey.cpp index 8f6c5319e..314851867 100644 --- a/src/keys/CompositeKey.cpp +++ b/src/keys/CompositeKey.cpp @@ -81,34 +81,62 @@ QByteArray CompositeKey::rawKey() const return cryptoHash.result(); } -QByteArray CompositeKey::transform(const QByteArray& seed, quint64 rounds) const +QByteArray CompositeKey::transform(const QByteArray& seed, quint64 rounds, + bool* ok, QString* errorString) const { Q_ASSERT(seed.size() == 32); Q_ASSERT(rounds > 0); + bool okLeft; + QString errorStringLeft; + bool okRight; + QString errorStringRight; + QByteArray key = rawKey(); - QFuture<QByteArray> future = QtConcurrent::run(transformKeyRaw, key.left(16), seed, rounds); - QByteArray result2 = transformKeyRaw(key.right(16), seed, rounds); + QFuture<QByteArray> future = QtConcurrent::run(transformKeyRaw, key.left(16), seed, rounds, &okLeft, &errorStringLeft); + QByteArray result2 = transformKeyRaw(key.right(16), seed, rounds, &okRight, &errorStringRight); QByteArray transformed; transformed.append(future.result()); transformed.append(result2); + *ok = (okLeft && okRight); + + if (!okLeft) { + *errorString = errorStringLeft; + return QByteArray(); + } + + if (!okRight) { + *errorString = errorStringRight; + return QByteArray(); + } + return CryptoHash::hash(transformed, CryptoHash::Sha256); } QByteArray CompositeKey::transformKeyRaw(const QByteArray& key, const QByteArray& seed, - quint64 rounds) + quint64 rounds, bool* ok, QString* errorString) { QByteArray iv(16, 0); SymmetricCipher cipher(SymmetricCipher::Aes256, SymmetricCipher::Ecb, - SymmetricCipher::Encrypt, seed, iv); + SymmetricCipher::Encrypt); + if (!cipher.init(seed, iv)) { + *ok = false; + *errorString = cipher.errorString(); + return QByteArray(); + } QByteArray result = key; - cipher.processInPlace(result, rounds); + if (!cipher.processInPlace(result, rounds)) { + *ok = false; + *errorString = cipher.errorString(); + return QByteArray(); + } + *ok = true; return result; } @@ -151,7 +179,8 @@ void TransformKeyBenchmarkThread::run() QByteArray iv(16, 0); SymmetricCipher cipher(SymmetricCipher::Aes256, SymmetricCipher::Ecb, - SymmetricCipher::Encrypt, seed, iv); + SymmetricCipher::Encrypt); + cipher.init(seed, iv); QTime t; t.start(); diff --git a/src/keys/CompositeKey.h b/src/keys/CompositeKey.h index ff738e61a..3290d3671 100644 --- a/src/keys/CompositeKey.h +++ b/src/keys/CompositeKey.h @@ -34,14 +34,15 @@ public: CompositeKey& operator=(const CompositeKey& key); QByteArray rawKey() const; - QByteArray transform(const QByteArray& seed, quint64 rounds) const; + QByteArray transform(const QByteArray& seed, quint64 rounds, + bool* ok, QString* errorString) const; void addKey(const Key& key); static int transformKeyBenchmark(int msec); private: static QByteArray transformKeyRaw(const QByteArray& key, const QByteArray& seed, - quint64 rounds); + quint64 rounds, bool* ok, QString* errorString); QList<Key*> m_keys; }; diff --git a/src/streams/LayeredStream.cpp b/src/streams/LayeredStream.cpp index b71eb228a..9f7783bd3 100644 --- a/src/streams/LayeredStream.cpp +++ b/src/streams/LayeredStream.cpp @@ -34,11 +34,6 @@ bool LayeredStream::isSequential() const return true; } -QString LayeredStream::errorString() const -{ - return m_baseDevice->errorString(); -} - bool LayeredStream::open(QIODevice::OpenMode mode) { if (isOpen()) { diff --git a/src/streams/LayeredStream.h b/src/streams/LayeredStream.h index 285c16ddf..b243e55b2 100644 --- a/src/streams/LayeredStream.h +++ b/src/streams/LayeredStream.h @@ -31,7 +31,6 @@ public: virtual ~LayeredStream(); bool isSequential() const Q_DECL_OVERRIDE; - virtual QString errorString() const; bool open(QIODevice::OpenMode mode) Q_DECL_OVERRIDE; protected: diff --git a/src/streams/StoreDataStream.cpp b/src/streams/StoreDataStream.cpp index da94b851f..18d7db980 100644 --- a/src/streams/StoreDataStream.cpp +++ b/src/streams/StoreDataStream.cpp @@ -41,6 +41,10 @@ QByteArray StoreDataStream::storedData() const qint64 StoreDataStream::readData(char* data, qint64 maxSize) { qint64 bytesRead = LayeredStream::readData(data, maxSize); + if (bytesRead == -1) { + setErrorString(m_baseDevice->errorString()); + return -1; + } m_storedData.append(data, bytesRead); diff --git a/src/streams/SymmetricCipherStream.cpp b/src/streams/SymmetricCipherStream.cpp index a6f5b1f5e..48ceb8f4d 100644 --- a/src/streams/SymmetricCipherStream.cpp +++ b/src/streams/SymmetricCipherStream.cpp @@ -18,10 +18,9 @@ #include "SymmetricCipherStream.h" SymmetricCipherStream::SymmetricCipherStream(QIODevice* baseDevice, SymmetricCipher::Algorithm algo, - SymmetricCipher::Mode mode, SymmetricCipher::Direction direction, - const QByteArray& key, const QByteArray& iv) + SymmetricCipher::Mode mode, SymmetricCipher::Direction direction) : LayeredStream(baseDevice) - , m_cipher(new SymmetricCipher(algo, mode, direction, key, iv)) + , m_cipher(new SymmetricCipher(algo, mode, direction)) , m_bufferPos(0) , m_bufferFilling(false) , m_error(false) @@ -33,6 +32,25 @@ SymmetricCipherStream::~SymmetricCipherStream() close(); } +bool SymmetricCipherStream::init(const QByteArray& key, const QByteArray& iv) +{ + m_isInitalized = m_cipher->init(key, iv); + if (!m_isInitalized) { + setErrorString(m_cipher->errorString()); + } + + return m_isInitalized; +} + +bool SymmetricCipherStream::open(QIODevice::OpenMode mode) +{ + if (!m_isInitalized) { + return false; + } + + return LayeredStream::open(mode); +} + bool SymmetricCipherStream::reset() { if (isWritable()) { @@ -108,7 +126,11 @@ bool SymmetricCipherStream::readBlock() return false; } else { - m_cipher->processInPlace(m_buffer); + if (!m_cipher->processInPlace(m_buffer)) { + m_error = true; + setErrorString(m_cipher->errorString()); + return false; + } m_bufferPos = 0; m_bufferFilling = false; @@ -187,7 +209,11 @@ bool SymmetricCipherStream::writeBlock(bool lastBlock) return true; } - m_cipher->processInPlace(m_buffer); + if (!m_cipher->processInPlace(m_buffer)) { + m_error = true; + setErrorString(m_cipher->errorString()); + return false; + } if (m_baseDevice->write(m_buffer) != m_buffer.size()) { m_error = true; diff --git a/src/streams/SymmetricCipherStream.h b/src/streams/SymmetricCipherStream.h index 53e252f24..c1865babc 100644 --- a/src/streams/SymmetricCipherStream.h +++ b/src/streams/SymmetricCipherStream.h @@ -29,11 +29,13 @@ class SymmetricCipherStream : public LayeredStream Q_OBJECT public: - SymmetricCipherStream(QIODevice* baseDevice, SymmetricCipher::Algorithm algo, SymmetricCipher::Mode mode, - SymmetricCipher::Direction direction, const QByteArray& key, const QByteArray& iv); + SymmetricCipherStream(QIODevice* baseDevice, SymmetricCipher::Algorithm algo, + SymmetricCipher::Mode mode, SymmetricCipher::Direction direction); ~SymmetricCipherStream(); - bool reset(); - void close(); + bool init(const QByteArray& key, const QByteArray& iv); + bool open(QIODevice::OpenMode mode) Q_DECL_OVERRIDE; + bool reset() Q_DECL_OVERRIDE; + void close() Q_DECL_OVERRIDE; protected: qint64 readData(char* data, qint64 maxSize) Q_DECL_OVERRIDE; @@ -48,6 +50,7 @@ private: int m_bufferPos; bool m_bufferFilling; bool m_error; + bool m_isInitalized; }; #endif // KEEPASSX_SYMMETRICCIPHERSTREAM_H diff --git a/tests/TestKeePass2RandomStream.cpp b/tests/TestKeePass2RandomStream.cpp index 7963e9af8..b41f1e87b 100644 --- a/tests/TestKeePass2RandomStream.cpp +++ b/tests/TestKeePass2RandomStream.cpp @@ -39,8 +39,8 @@ void TestKeePass2RandomStream::test() const int Size = 128; - SymmetricCipher cipher(SymmetricCipher::Salsa20, SymmetricCipher::Stream, SymmetricCipher::Encrypt, - CryptoHash::hash(key, CryptoHash::Sha256), KeePass2::INNER_STREAM_SALSA20_IV); + SymmetricCipher cipher(SymmetricCipher::Salsa20, SymmetricCipher::Stream, SymmetricCipher::Encrypt); + QVERIFY(cipher.init(CryptoHash::hash(key, CryptoHash::Sha256), KeePass2::INNER_STREAM_SALSA20_IV)); const QByteArray data(QByteArray::fromHex("601ec313775789a5b7a7f504bbf3d228f443e3ca4d62b59aca84e990cacaf5c5" "2b0930daa23de94ce87017ba2d84988ddfc9c58db67aada613c2dd08457941a6" @@ -59,20 +59,27 @@ void TestKeePass2RandomStream::test() } - KeePass2RandomStream randomStream(key); + KeePass2RandomStream randomStream; + bool ok; + QVERIFY(randomStream.init(key)); QByteArray randomStreamData; - randomStreamData.append(randomStream.process(data.mid(0, 7))); - randomStreamData.append(randomStream.process(data.mid(7, 1))); + randomStreamData.append(randomStream.process(data.mid(0, 7), &ok)); + QVERIFY(ok); + randomStreamData.append(randomStream.process(data.mid(7, 1), &ok)); + QVERIFY(ok); QByteArray tmpData = data.mid(8, 12); randomStream.processInPlace(tmpData); randomStreamData.append(tmpData); - randomStreamData.append(randomStream.process(data.mid(20, 44))); - randomStreamData.append(randomStream.process(data.mid(64, 64))); + randomStreamData.append(randomStream.process(data.mid(20, 44), &ok)); + QVERIFY(ok); + randomStreamData.append(randomStream.process(data.mid(64, 64), &ok)); + QVERIFY(ok); - SymmetricCipher cipherEncrypt(SymmetricCipher::Salsa20, SymmetricCipher::Stream, SymmetricCipher::Encrypt, - CryptoHash::hash(key, CryptoHash::Sha256), KeePass2::INNER_STREAM_SALSA20_IV); - QByteArray cipherDataEncrypt = cipherEncrypt.process(data); + SymmetricCipher cipherEncrypt(SymmetricCipher::Salsa20, SymmetricCipher::Stream, SymmetricCipher::Encrypt); + QVERIFY(cipherEncrypt.init(CryptoHash::hash(key, CryptoHash::Sha256), KeePass2::INNER_STREAM_SALSA20_IV)); + QByteArray cipherDataEncrypt = cipherEncrypt.process(data, &ok); + QVERIFY(ok); QCOMPARE(randomStreamData.size(), Size); diff --git a/tests/TestKeys.cpp b/tests/TestKeys.cpp index d6758d655..770af52de 100644 --- a/tests/TestKeys.cpp +++ b/tests/TestKeys.cpp @@ -43,6 +43,8 @@ void TestKeys::testComposite() CompositeKey* compositeKey1 = new CompositeKey(); PasswordKey* passwordKey1 = new PasswordKey(); PasswordKey* passwordKey2 = new PasswordKey("test"); + bool ok; + QString errorString; // make sure that addKey() creates a copy of the keys compositeKey1->addKey(*passwordKey1); @@ -50,13 +52,15 @@ void TestKeys::testComposite() delete passwordKey1; delete passwordKey2; - QByteArray transformed = compositeKey1->transform(QByteArray(32, '\0'), 1); + QByteArray transformed = compositeKey1->transform(QByteArray(32, '\0'), 1, &ok, &errorString); + QVERIFY(ok); QCOMPARE(transformed.size(), 32); // make sure the subkeys are copied CompositeKey* compositeKey2 = compositeKey1->clone(); delete compositeKey1; - QCOMPARE(compositeKey2->transform(QByteArray(32, '\0'), 1), transformed); + QCOMPARE(compositeKey2->transform(QByteArray(32, '\0'), 1, &ok, &errorString), transformed); + QVERIFY(ok); delete compositeKey2; CompositeKey* compositeKey3 = new CompositeKey(); @@ -130,7 +134,7 @@ void TestKeys::testCreateFileKey() compositeKey.addKey(fileKey); Database* dbOrg = new Database(); - dbOrg->setKey(compositeKey); + QVERIFY(dbOrg->setKey(compositeKey)); dbOrg->metadata()->setName(dbName); QBuffer dbBuffer; @@ -182,7 +186,10 @@ void TestKeys::benchmarkTransformKey() QByteArray seed(32, '\x4B'); + bool ok; + QString errorString; + QBENCHMARK { - compositeKey.transform(seed, 1e6); + compositeKey.transform(seed, 1e6, &ok, &errorString); } } diff --git a/tests/TestSymmetricCipher.cpp b/tests/TestSymmetricCipher.cpp index 6d4e94f6f..ec9badd90 100644 --- a/tests/TestSymmetricCipher.cpp +++ b/tests/TestSymmetricCipher.cpp @@ -42,17 +42,20 @@ void TestSymmetricCipher::testAes256CbcEncryption() plainText.append(QByteArray::fromHex("ae2d8a571e03ac9c9eb76fac45af8e51")); QByteArray cipherText = QByteArray::fromHex("f58c4c04d6e5f1ba779eabfb5f7bfbd6"); cipherText.append(QByteArray::fromHex("9cfc4e967edb808d679f777bc6702c7d")); + bool ok; - SymmetricCipher cipher(SymmetricCipher::Aes256, SymmetricCipher::Cbc, SymmetricCipher::Encrypt, - key, iv); + SymmetricCipher cipher(SymmetricCipher::Aes256, SymmetricCipher::Cbc, SymmetricCipher::Encrypt); + QVERIFY(cipher.init(key, iv)); QCOMPARE(cipher.blockSize(), 16); - QCOMPARE(cipher.process(plainText), + QCOMPARE(cipher.process(plainText, &ok), cipherText); + QVERIFY(ok); QBuffer buffer; SymmetricCipherStream stream(&buffer, SymmetricCipher::Aes256, SymmetricCipher::Cbc, - SymmetricCipher::Encrypt, key, iv); + SymmetricCipher::Encrypt); + QVERIFY(stream.init(key, iv)); buffer.open(QIODevice::WriteOnly); stream.open(QIODevice::WriteOnly); QVERIFY(stream.reset()); @@ -86,18 +89,22 @@ void TestSymmetricCipher::testAes256CbcDecryption() cipherText.append(QByteArray::fromHex("9cfc4e967edb808d679f777bc6702c7d")); QByteArray plainText = QByteArray::fromHex("6bc1bee22e409f96e93d7e117393172a"); plainText.append(QByteArray::fromHex("ae2d8a571e03ac9c9eb76fac45af8e51")); + bool ok; - SymmetricCipher cipher(SymmetricCipher::Aes256, SymmetricCipher::Cbc, SymmetricCipher::Decrypt, key, iv); + SymmetricCipher cipher(SymmetricCipher::Aes256, SymmetricCipher::Cbc, SymmetricCipher::Decrypt); + QVERIFY(cipher.init(key, iv)); QCOMPARE(cipher.blockSize(), 16); - QCOMPARE(cipher.process(cipherText), + QCOMPARE(cipher.process(cipherText, &ok), plainText); + QVERIFY(ok); // padded with 16 0x16 bytes QByteArray cipherTextPadded = cipherText + QByteArray::fromHex("3a3aa5e0213db1a9901f9036cf5102d2"); QBuffer buffer(&cipherTextPadded); SymmetricCipherStream stream(&buffer, SymmetricCipher::Aes256, SymmetricCipher::Cbc, - SymmetricCipher::Decrypt, key, iv); + SymmetricCipher::Decrypt); + QVERIFY(stream.init(key, iv)); buffer.open(QIODevice::ReadOnly); stream.open(QIODevice::ReadOnly); @@ -123,16 +130,20 @@ void TestSymmetricCipher::testSalsa20() QByteArray key = QByteArray::fromHex("F3F4F5F6F7F8F9FAFBFCFDFEFF000102030405060708090A0B0C0D0E0F101112"); QByteArray iv = QByteArray::fromHex("0000000000000000"); + bool ok; - SymmetricCipher cipher(SymmetricCipher::Salsa20, SymmetricCipher::Stream, SymmetricCipher::Encrypt, key, iv); + SymmetricCipher cipher(SymmetricCipher::Salsa20, SymmetricCipher::Stream, SymmetricCipher::Encrypt); + QVERIFY(cipher.init(key, iv)); QByteArray cipherTextA; for (int i = 0; i < 8; i++) { - cipherTextA.append(cipher.process(QByteArray(64, '\0'))); + cipherTextA.append(cipher.process(QByteArray(64, '\0'), &ok)); + QVERIFY(ok); } cipher.reset(); - QByteArray cipherTextB = cipher.process(QByteArray(512, '\0')); + QByteArray cipherTextB = cipher.process(QByteArray(512, '\0'), &ok); + QVERIFY(ok); cipher.reset(); QByteArray expectedCipherText1; @@ -180,7 +191,8 @@ void TestSymmetricCipher::testPadding() buffer.open(QIODevice::ReadWrite); SymmetricCipherStream streamEnc(&buffer, SymmetricCipher::Aes256, SymmetricCipher::Cbc, - SymmetricCipher::Encrypt, key, iv); + SymmetricCipher::Encrypt); + QVERIFY(streamEnc.init(key, iv)); streamEnc.open(QIODevice::WriteOnly); streamEnc.write(plainText); streamEnc.close(); @@ -189,7 +201,8 @@ void TestSymmetricCipher::testPadding() QCOMPARE(buffer.buffer().size(), 16); SymmetricCipherStream streamDec(&buffer, SymmetricCipher::Aes256, SymmetricCipher::Cbc, - SymmetricCipher::Decrypt, key, iv); + SymmetricCipher::Decrypt); + QVERIFY(streamDec.init(key, iv)); streamDec.open(QIODevice::ReadOnly); QByteArray decrypted = streamDec.readAll(); QCOMPARE(decrypted, plainText); |