Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/keepassxreboot/keepassxc.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Geyer <debfx@fobos.de>2015-05-09 20:47:53 +0300
committerFelix Geyer <debfx@fobos.de>2015-05-10 00:21:44 +0300
commita762cef0a93661fe6563c89da8f0cdfca713cdbb (patch)
tree9de727fe5dcb16eba41a7596390b81a2133e6ee9
parenta7f4e2d0cddba53167dc4ae02a28a7971f4b4e2f (diff)
Catch and handle all errors from libgcrypt.
-rw-r--r--src/core/Database.cpp31
-rw-r--r--src/core/Database.h7
-rw-r--r--src/crypto/Crypto.cpp120
-rw-r--r--src/crypto/Crypto.h5
-rw-r--r--src/crypto/SymmetricCipher.cpp37
-rw-r--r--src/crypto/SymmetricCipher.h22
-rw-r--r--src/crypto/SymmetricCipherBackend.h15
-rw-r--r--src/crypto/SymmetricCipherGcrypt.cpp119
-rw-r--r--src/crypto/SymmetricCipherGcrypt.h18
-rw-r--r--src/crypto/SymmetricCipherSalsa20.h13
-rw-r--r--src/format/KeePass1Reader.cpp38
-rw-r--r--src/format/KeePass2RandomStream.cpp54
-rw-r--r--src/format/KeePass2RandomStream.h12
-rw-r--r--src/format/KeePass2Reader.cpp38
-rw-r--r--src/format/KeePass2Writer.cpp28
-rw-r--r--src/format/KeePass2XmlReader.cpp11
-rw-r--r--src/format/KeePass2XmlWriter.cpp23
-rw-r--r--src/format/KeePass2XmlWriter.h6
-rw-r--r--src/gui/DatabaseWidget.cpp7
-rw-r--r--src/keys/CompositeKey.cpp43
-rw-r--r--src/keys/CompositeKey.h5
-rw-r--r--src/streams/LayeredStream.cpp5
-rw-r--r--src/streams/LayeredStream.h1
-rw-r--r--src/streams/StoreDataStream.cpp4
-rw-r--r--src/streams/SymmetricCipherStream.cpp36
-rw-r--r--src/streams/SymmetricCipherStream.h11
-rw-r--r--tests/TestKeePass2RandomStream.cpp27
-rw-r--r--tests/TestKeys.cpp15
-rw-r--r--tests/TestSymmetricCipher.cpp37
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);