diff --git a/src/core/Database.cpp b/src/core/Database.cpp index 667a6a169..9ffd5a157 100644 --- a/src/core/Database.cpp +++ b/src/core/Database.cpp @@ -410,6 +410,9 @@ bool Database::performSave(const QString& filePath, SaveAction action, const QSt bool Database::writeDatabase(QIODevice* device, QString* error) { + Q_ASSERT(m_data.key); + Q_ASSERT(m_data.transformedDatabaseKey); + PasswordKey oldTransformedKey; if (m_data.key->isEmpty()) { oldTransformedKey.setRawKey(m_data.transformedDatabaseKey->rawKey()); @@ -765,18 +768,29 @@ Database::CompressionAlgorithm Database::compressionAlgorithm() const QByteArray Database::transformedDatabaseKey() const { + Q_ASSERT(m_data.transformedDatabaseKey); + if (!m_data.transformedDatabaseKey) { + return {}; + } return m_data.transformedDatabaseKey->rawKey(); } QByteArray Database::challengeResponseKey() const { + Q_ASSERT(m_data.challengeResponseKey); + if (!m_data.challengeResponseKey) { + return {}; + } return m_data.challengeResponseKey->rawKey(); } bool Database::challengeMasterSeed(const QByteArray& masterSeed) { + Q_ASSERT(m_data.key); + Q_ASSERT(m_data.masterSeed); + m_keyError.clear(); - if (m_data.key) { + if (m_data.key && m_data.masterSeed) { m_data.masterSeed->setRawKey(masterSeed); QByteArray response; bool ok = m_data.key->challenge(masterSeed, response, &m_keyError); @@ -822,8 +836,7 @@ bool Database::setKey(const QSharedPointer& key, m_keyError.clear(); if (!key) { - m_data.key.reset(); - m_data.transformedDatabaseKey.reset(new PasswordKey()); + m_data.resetKeys(); return true; } diff --git a/src/core/Database.h b/src/core/Database.h index 45e5140fd..35546f743 100644 --- a/src/core/Database.h +++ b/src/core/Database.h @@ -187,30 +187,33 @@ private: QScopedPointer challengeResponseKey; QSharedPointer key; - QSharedPointer kdf = QSharedPointer::create(true); + QSharedPointer kdf; QVariantMap publicCustomData; DatabaseData() - : masterSeed(new PasswordKey()) - , transformedDatabaseKey(new PasswordKey()) - , challengeResponseKey(new PasswordKey()) { - kdf->randomizeSeed(); + clear(); } void clear() { + resetKeys(); filePath.clear(); + publicCustomData.clear(); + } - masterSeed.reset(); - transformedDatabaseKey.reset(); - challengeResponseKey.reset(); + void resetKeys() + { + masterSeed.reset(new PasswordKey()); + transformedDatabaseKey.reset(new PasswordKey()); + challengeResponseKey.reset(new PasswordKey()); key.reset(); - kdf.reset(); - publicCustomData.clear(); + // Default to AES KDF, KDBX4 databases overwrite this + kdf.reset(new AesKdf(true)); + kdf->randomizeSeed(); } }; diff --git a/src/gui/DatabaseOpenWidget.cpp b/src/gui/DatabaseOpenWidget.cpp index 33aa2fdee..c3a04134d 100644 --- a/src/gui/DatabaseOpenWidget.cpp +++ b/src/gui/DatabaseOpenWidget.cpp @@ -270,9 +270,7 @@ void DatabaseOpenWidget::clearForms() m_ui->hardwareKeyCombo->clear(); toggleQuickUnlockScreen(); - QString error; - m_db.reset(new Database()); - m_db->open(m_filename, nullptr, &error); + m_db.reset(new Database(m_filename)); } QSharedPointer DatabaseOpenWidget::database() diff --git a/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.cpp b/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.cpp index a782d4136..2cc21da1e 100644 --- a/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.cpp +++ b/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.cpp @@ -103,22 +103,23 @@ void DatabaseSettingsWidgetEncryption::initialize() } auto version = KDBX4; - if (m_db->kdf()) { + if (m_db->key() && m_db->kdf()) { version = (m_db->kdf()->uuid() == KeePass2::KDF_AES_KDBX3) ? KDBX3 : KDBX4; } m_ui->compatibilitySelection->setCurrentIndex(version); bool isNewDatabase = false; - if (!m_db->kdf()) { + if (!m_db->key()) { + m_db->setKey(QSharedPointer::create(), true, false, false); + m_db->setKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2D)); + m_db->setCipher(KeePass2::CIPHER_AES256); + isNewDatabase = true; + } else if (!m_db->kdf()) { m_db->setKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2D)); isNewDatabase = true; } - if (!m_db->key()) { - m_db->setKey(QSharedPointer::create(), true, false, false); - m_db->setCipher(KeePass2::CIPHER_AES256); - isNewDatabase = true; - } + bool kdbx3Enabled = KeePass2Writer::kdbxVersionRequired(m_db.data(), true, true) <= KeePass2::FILE_VERSION_3_1; // check if the DB's custom data has a decryption time setting stored diff --git a/tests/TestKeePass2Format.cpp b/tests/TestKeePass2Format.cpp index a1c7b20d4..5451fb62b 100644 --- a/tests/TestKeePass2Format.cpp +++ b/tests/TestKeePass2Format.cpp @@ -582,7 +582,9 @@ void TestKeePass2Format::testKdbxKeyChange() db->setKey(key1); writeKdbx(&buffer, db.data(), hasError, errorString); - QVERIFY(!hasError); + if (hasError) { + QFAIL(qPrintable(QStringLiteral("Error while reading database: ").append(errorString))); + } // read database db = QSharedPointer::create(); @@ -599,7 +601,9 @@ void TestKeePass2Format::testKdbxKeyChange() // write database buffer.seek(0); writeKdbx(&buffer, db.data(), hasError, errorString); - QVERIFY(!hasError); + if (hasError) { + QFAIL(qPrintable(QStringLiteral("Error while reading database: ").append(errorString))); + } // read database db = QSharedPointer::create();