mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2024-10-01 01:26:01 -04:00
Add Argon2Kdf and enable parameters in db settings
Note: This implementation is not yet connected to the database itself and will corrupt existing kdbx3 db's. * Implemented memory and parallelism parameters for Argon2Kdf * Using libargon2; libsodium does not support Argon2d algorithm * Moved basic rounds parameter into Kdf class * Reimplemented benchmark algorithm; previous was utterly broken
This commit is contained in:
parent
9140893cd3
commit
542ee42313
@ -261,8 +261,8 @@ endif()
|
||||
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_NONE QT_NO_DEBUG)
|
||||
|
||||
find_package(LibGPGError REQUIRED)
|
||||
|
||||
find_package(Gcrypt 1.7.0 REQUIRED)
|
||||
find_package(Argon2 REQUIRED)
|
||||
|
||||
find_package(ZLIB REQUIRED)
|
||||
|
||||
|
@ -26,6 +26,7 @@ The following libraries are required:
|
||||
* libmicrohttpd
|
||||
* libxi, libxtst, qtx11extras (optional for auto-type on X11)
|
||||
* libsodium (>= 1.0.12, optional for keepassxc-browser support)
|
||||
* libargon2
|
||||
|
||||
|
||||
Prepare the Building Environment
|
||||
|
21
cmake/FindArgon2.cmake
Normal file
21
cmake/FindArgon2.cmake
Normal file
@ -0,0 +1,21 @@
|
||||
# Copyright (C) 2017 KeePassXC Team
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 or (at your option)
|
||||
# version 3 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
find_path(ARGON2_INCLUDE_DIR argon2.h)
|
||||
find_library(ARGON2_LIBRARIES argon2)
|
||||
mark_as_advanced(ARGON2_LIBRARIES ARGON2_INCLUDE_DIR)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Argon2 DEFAULT_MSG ARGON2_LIBRARIES ARGON2_INCLUDE_DIR)
|
@ -78,6 +78,7 @@ set(keepassx_SOURCES
|
||||
crypto/kdf/Kdf.cpp
|
||||
crypto/kdf/Kdf_p.h
|
||||
crypto/kdf/AesKdf.cpp
|
||||
crypto/kdf/Argon2Kdf.cpp
|
||||
format/CsvExporter.cpp
|
||||
format/KeePass1.h
|
||||
format/KeePass1Reader.cpp
|
||||
@ -252,6 +253,7 @@ target_link_libraries(keepassx_core
|
||||
Qt5::Network
|
||||
Qt5::Concurrent
|
||||
Qt5::Widgets
|
||||
${ARGON2_LIBRARIES}
|
||||
${GCRYPT_LIBRARIES}
|
||||
${GPGERROR_LIBRARIES}
|
||||
${ZLIB_LIBRARIES})
|
||||
|
@ -46,6 +46,7 @@ target_link_libraries(keepassxc-cli
|
||||
keepassx_core
|
||||
Qt5::Core
|
||||
${GCRYPT_LIBRARIES}
|
||||
${ARGON2_LIBRARIES}
|
||||
${GPGERROR_LIBRARIES}
|
||||
${ZLIB_LIBRARIES}
|
||||
${ZXCVBN_LIBRARIES})
|
||||
|
@ -45,7 +45,7 @@ Database::Database()
|
||||
m_data.cipher = KeePass2::CIPHER_AES;
|
||||
m_data.compressionAlgo = CompressionGZip;
|
||||
m_data.kdf = QSharedPointer<AesKdf>::create();
|
||||
m_data.kdf->randomizeTransformSalt();
|
||||
m_data.kdf->randomizeSeed();
|
||||
m_data.hasKey = false;
|
||||
|
||||
setRootGroup(new Group());
|
||||
@ -258,7 +258,7 @@ void Database::setCompressionAlgo(Database::CompressionAlgorithm algo)
|
||||
bool Database::setKey(const CompositeKey& key, bool updateChangedTime, bool updateTransformSalt)
|
||||
{
|
||||
if (updateTransformSalt) {
|
||||
m_data.kdf->randomizeTransformSalt();
|
||||
m_data.kdf->randomizeSeed();
|
||||
}
|
||||
|
||||
QByteArray transformedMasterKey;
|
||||
@ -490,7 +490,7 @@ void Database::setKdf(QSharedPointer<Kdf> kdf)
|
||||
|
||||
bool Database::changeKdf(QSharedPointer<Kdf> kdf)
|
||||
{
|
||||
kdf->randomizeTransformSalt();
|
||||
kdf->randomizeSeed();
|
||||
QByteArray transformedMasterKey;
|
||||
if (!m_data.key.transform(*kdf, transformedMasterKey)) {
|
||||
return false;
|
||||
|
@ -15,12 +15,17 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "AesKdf.h"
|
||||
|
||||
#include <QtConcurrent>
|
||||
|
||||
#include "format/KeePass2.h"
|
||||
#include "crypto/CryptoHash.h"
|
||||
#include "crypto/Random.h"
|
||||
#include "AesKdf.h"
|
||||
|
||||
AesKdf::AesKdf()
|
||||
: Kdf::Kdf(KeePass2::KDF_AES)
|
||||
{
|
||||
}
|
||||
|
||||
bool AesKdf::transform(const QByteArray& raw, QByteArray& result) const
|
||||
{
|
||||
@ -44,7 +49,7 @@ bool AesKdf::transform(const QByteArray& raw, QByteArray& result) const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AesKdf::transformKeyRaw(const QByteArray& key, const QByteArray& seed, quint64 rounds, QByteArray* result)
|
||||
bool AesKdf::transformKeyRaw(const QByteArray& key, const QByteArray& seed, int rounds, QByteArray* result)
|
||||
{
|
||||
QByteArray iv(16, 0);
|
||||
SymmetricCipher cipher(SymmetricCipher::Aes256, SymmetricCipher::Ecb,
|
||||
@ -65,44 +70,6 @@ bool AesKdf::transformKeyRaw(const QByteArray& key, const QByteArray& seed, quin
|
||||
return true;
|
||||
}
|
||||
|
||||
AesKdf::AesKdf()
|
||||
: Kdf::Kdf(KeePass2::KDF_AES)
|
||||
, m_rounds(100000ull)
|
||||
, m_seed(QByteArray(32, 0))
|
||||
{
|
||||
}
|
||||
|
||||
quint64 AesKdf::rounds() const
|
||||
{
|
||||
return m_rounds;
|
||||
}
|
||||
|
||||
QByteArray AesKdf::seed() const
|
||||
{
|
||||
return m_seed;
|
||||
}
|
||||
|
||||
bool AesKdf::setRounds(quint64 rounds)
|
||||
{
|
||||
m_rounds = rounds;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AesKdf::setSeed(const QByteArray& seed)
|
||||
{
|
||||
if (seed.size() != 32) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_seed = seed;
|
||||
return true;
|
||||
}
|
||||
|
||||
void AesKdf::randomizeTransformSalt()
|
||||
{
|
||||
setSeed(randomGen()->randomArray(32));
|
||||
}
|
||||
|
||||
QSharedPointer<Kdf> AesKdf::clone() const
|
||||
{
|
||||
return QSharedPointer<AesKdf>::create(*this);
|
||||
@ -117,17 +84,13 @@ int AesKdf::benchmarkImpl(int msec) const
|
||||
SymmetricCipher cipher(SymmetricCipher::Aes256, SymmetricCipher::Ecb, SymmetricCipher::Encrypt);
|
||||
cipher.init(seed, iv);
|
||||
|
||||
int rounds = 0;
|
||||
quint64 rounds = 1000000;
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
do {
|
||||
if (!cipher.processInPlace(key, 10000)) {
|
||||
rounds = -1;
|
||||
break;
|
||||
}
|
||||
rounds += 10000;
|
||||
}
|
||||
while (!timer.hasExpired(msec));
|
||||
|
||||
return rounds;
|
||||
if (!cipher.processInPlace(key, rounds)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return static_cast<int>(rounds * (static_cast<float>(msec) / timer.elapsed()));
|
||||
}
|
||||
|
@ -26,25 +26,15 @@ public:
|
||||
AesKdf();
|
||||
|
||||
bool transform(const QByteArray& raw, QByteArray& result) const override;
|
||||
void randomizeTransformSalt() override;
|
||||
QSharedPointer<Kdf> clone() const override;
|
||||
|
||||
quint64 rounds() const override;
|
||||
QByteArray seed() const override;
|
||||
|
||||
bool setRounds(quint64 rounds) override;
|
||||
bool setSeed(const QByteArray& seed) override;
|
||||
|
||||
protected:
|
||||
int benchmarkImpl(int msec) const override;
|
||||
|
||||
private:
|
||||
quint64 m_rounds;
|
||||
QByteArray m_seed;
|
||||
|
||||
static bool transformKeyRaw(const QByteArray& key,
|
||||
const QByteArray& seed,
|
||||
quint64 rounds,
|
||||
int rounds,
|
||||
QByteArray* result) Q_REQUIRED_RESULT;
|
||||
};
|
||||
|
||||
|
116
src/crypto/kdf/Argon2Kdf.cpp
Normal file
116
src/crypto/kdf/Argon2Kdf.cpp
Normal file
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (C) 2017 KeePassXC Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 or (at your option)
|
||||
* version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Argon2Kdf.h"
|
||||
|
||||
#include <QtConcurrent>
|
||||
#include <argon2.h>
|
||||
|
||||
#include "format/KeePass2.h"
|
||||
#include "crypto/CryptoHash.h"
|
||||
|
||||
/**
|
||||
* KeePass' Argon2 implementation supports all parameters that are defined in the official specification,
|
||||
* but only the number of iterations, the memory size and the degree of parallelism can be configured by
|
||||
* the user in the database settings dialog. For the other parameters, KeePass chooses reasonable defaults:
|
||||
* a 256-bit salt is generated each time the database is saved, the tag length is 256 bits, no secret key
|
||||
* or associated data. KeePass uses the latest version of Argon2, v1.3.
|
||||
*/
|
||||
Argon2Kdf::Argon2Kdf()
|
||||
: Kdf::Kdf(KeePass2::KDF_ARGON2)
|
||||
, m_memory(1<<16)
|
||||
, m_parallelism(2)
|
||||
{
|
||||
m_rounds = 1;
|
||||
}
|
||||
|
||||
quint32 Argon2Kdf::memory() const
|
||||
{
|
||||
// Convert to Megabytes
|
||||
return m_memory / (1<<10);
|
||||
}
|
||||
|
||||
bool Argon2Kdf::setMemory(quint32 memoryMegabytes)
|
||||
{
|
||||
// TODO: add bounds check
|
||||
// Convert to Kibibytes
|
||||
m_memory = (1<<10) * memoryMegabytes;
|
||||
return true;
|
||||
}
|
||||
|
||||
quint32 Argon2Kdf::parallelism() const
|
||||
{
|
||||
return m_parallelism;
|
||||
}
|
||||
|
||||
bool Argon2Kdf::setParallelism(quint32 threads)
|
||||
{
|
||||
// TODO: add bounds check
|
||||
m_parallelism = threads;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Argon2Kdf::transform(const QByteArray& raw, QByteArray& result) const
|
||||
{
|
||||
result.clear();
|
||||
result.resize(32);
|
||||
|
||||
if (!transformKeyRaw(raw, seed(), rounds(), memory(), parallelism(), result)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
result = CryptoHash::hash(result, CryptoHash::Sha256);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Argon2Kdf::transformKeyRaw(const QByteArray& key, const QByteArray& seed, int rounds,
|
||||
quint32 memory, quint32 parallelism, QByteArray& result)
|
||||
{
|
||||
// Time Cost, Mem Cost, Threads/Lanes, Password, length, Salt, length, out, length
|
||||
int rc = argon2d_hash_raw(rounds, memory, parallelism, key.data(), key.size(),
|
||||
seed.data(), seed.size(), result.data(), result.size());
|
||||
if (rc != ARGON2_OK) {
|
||||
qWarning("Argon2 error: %s", argon2_error_message(rc));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QSharedPointer<Kdf> Argon2Kdf::clone() const
|
||||
{
|
||||
return QSharedPointer<Argon2Kdf>::create(*this);
|
||||
}
|
||||
|
||||
int Argon2Kdf::benchmarkImpl(int msec) const
|
||||
{
|
||||
QByteArray key = QByteArray(16, '\x7E');
|
||||
QByteArray seed = QByteArray(32, '\x4B');
|
||||
|
||||
QElapsedTimer timer;
|
||||
timer.start();
|
||||
|
||||
int rounds = 4;
|
||||
|
||||
int rc = argon2d_hash_raw(rounds, m_memory, m_parallelism, key.data(), key.size(), seed.data(), seed.size(), key.data(), key.size());
|
||||
if (rc != ARGON2_OK) {
|
||||
qWarning("Argon2 error: %s", argon2_error_message(rc));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return static_cast<int>(rounds * (static_cast<float>(msec) / timer.elapsed()));
|
||||
}
|
50
src/crypto/kdf/Argon2Kdf.h
Normal file
50
src/crypto/kdf/Argon2Kdf.h
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2017 KeePassXC Team
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 or (at your option)
|
||||
* version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef KEEPASSX_ARGON2KDF_H
|
||||
#define KEEPASSX_ARGON2KDF_H
|
||||
|
||||
#include "Kdf.h"
|
||||
|
||||
class Argon2Kdf : public Kdf {
|
||||
public:
|
||||
Argon2Kdf();
|
||||
|
||||
bool transform(const QByteArray& raw, QByteArray& result) const override;
|
||||
QSharedPointer<Kdf> clone() const override;
|
||||
|
||||
quint32 memory() const;
|
||||
bool setMemory(quint32 memory_kb);
|
||||
quint32 parallelism() const;
|
||||
bool setParallelism(quint32 threads);
|
||||
|
||||
protected:
|
||||
int benchmarkImpl(int msec) const override;
|
||||
|
||||
quint32 m_memory;
|
||||
quint32 m_parallelism;
|
||||
|
||||
private:
|
||||
static bool transformKeyRaw(const QByteArray& key,
|
||||
const QByteArray& seed,
|
||||
int rounds,
|
||||
quint32 memory,
|
||||
quint32 parallelism,
|
||||
QByteArray& result) Q_REQUIRED_RESULT;
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_ARGON2KDF_H
|
@ -20,8 +20,12 @@
|
||||
|
||||
#include <QtConcurrent>
|
||||
|
||||
#include "crypto/Random.h"
|
||||
|
||||
Kdf::Kdf(Uuid uuid)
|
||||
: m_uuid(uuid)
|
||||
: m_rounds(KDF_DEFAULT_ROUNDS)
|
||||
, m_seed(QByteArray(KDF_DEFAULT_SEED_SIZE, 0))
|
||||
, m_uuid(uuid)
|
||||
{
|
||||
}
|
||||
|
||||
@ -30,6 +34,37 @@ Uuid Kdf::uuid() const
|
||||
return m_uuid;
|
||||
}
|
||||
|
||||
int Kdf::rounds() const
|
||||
{
|
||||
return m_rounds;
|
||||
}
|
||||
|
||||
QByteArray Kdf::seed() const
|
||||
{
|
||||
return m_seed;
|
||||
}
|
||||
|
||||
bool Kdf::setRounds(int rounds)
|
||||
{
|
||||
m_rounds = rounds;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Kdf::setSeed(const QByteArray& seed)
|
||||
{
|
||||
if (seed.size() != m_seed.size()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
m_seed = seed;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Kdf::randomizeSeed()
|
||||
{
|
||||
setSeed(randomGen()->randomArray(m_seed.size()));
|
||||
}
|
||||
|
||||
int Kdf::benchmark(int msec) const
|
||||
{
|
||||
BenchmarkThread thread1(msec, this);
|
||||
@ -41,7 +76,7 @@ int Kdf::benchmark(int msec) const
|
||||
thread1.wait();
|
||||
thread2.wait();
|
||||
|
||||
return qMin(thread1.rounds(), thread2.rounds());
|
||||
return qMax(1, qMin(thread1.rounds(), thread2.rounds()));
|
||||
}
|
||||
|
||||
Kdf::BenchmarkThread::BenchmarkThread(int msec, const Kdf* kdf)
|
||||
|
@ -22,6 +22,9 @@
|
||||
|
||||
#include "core/Uuid.h"
|
||||
|
||||
#define KDF_DEFAULT_SEED_SIZE 32
|
||||
#define KDF_DEFAULT_ROUNDS 100000ull
|
||||
|
||||
class Kdf
|
||||
{
|
||||
public:
|
||||
@ -30,12 +33,13 @@ public:
|
||||
|
||||
Uuid uuid() const;
|
||||
|
||||
virtual quint64 rounds() const = 0;
|
||||
virtual bool setRounds(quint64 rounds) = 0;
|
||||
virtual QByteArray seed() const = 0;
|
||||
virtual bool setSeed(const QByteArray& seed) = 0;
|
||||
int rounds() const;
|
||||
virtual bool setRounds(int rounds);
|
||||
QByteArray seed() const;
|
||||
virtual bool setSeed(const QByteArray& seed);
|
||||
virtual void randomizeSeed();
|
||||
|
||||
virtual bool transform(const QByteArray& raw, QByteArray& result) const = 0;
|
||||
virtual void randomizeTransformSalt() = 0;
|
||||
virtual QSharedPointer<Kdf> clone() const = 0;
|
||||
|
||||
int benchmark(int msec) const;
|
||||
@ -43,6 +47,9 @@ public:
|
||||
protected:
|
||||
virtual int benchmarkImpl(int msec) const = 0;
|
||||
|
||||
int m_rounds;
|
||||
QByteArray m_seed;
|
||||
|
||||
private:
|
||||
class BenchmarkThread;
|
||||
const Uuid m_uuid;
|
||||
|
@ -16,15 +16,16 @@
|
||||
*/
|
||||
|
||||
#include "KeePass2.h"
|
||||
#include "crypto/kdf/AesKdf.h"
|
||||
#include <QSharedPointer>
|
||||
|
||||
#include "crypto/kdf/AesKdf.h"
|
||||
#include "crypto/kdf/Argon2Kdf.h"
|
||||
|
||||
const Uuid KeePass2::CIPHER_AES = Uuid(QByteArray::fromHex("31c1f2e6bf714350be5805216afc5aff"));
|
||||
const Uuid KeePass2::CIPHER_TWOFISH = Uuid(QByteArray::fromHex("ad68f29f576f4bb9a36ad47af965346c"));
|
||||
const Uuid KeePass2::CIPHER_CHACHA20 = Uuid(QByteArray::fromHex("D6038A2B8B6F4CB5A524339A31DBB59A"));
|
||||
|
||||
const Uuid KeePass2::KDF_AES = Uuid(QByteArray::fromHex("C9D9F39A628A4460BF740D08C18A4FEA"));
|
||||
const Uuid KeePass2::KDF_ARGON2 = Uuid(QByteArray::fromHex("EF636DDF8C29444B91F7A9A403E30A0C"));
|
||||
|
||||
const QByteArray KeePass2::INNER_STREAM_SALSA20_IV("\xE8\x30\x09\x4B\x97\x20\x5D\x2A");
|
||||
|
||||
@ -35,12 +36,15 @@ const QList<QPair<Uuid, QString>> KeePass2::CIPHERS {
|
||||
};
|
||||
const QList<QPair<Uuid, QString>> KeePass2::KDFS {
|
||||
qMakePair(KeePass2::KDF_AES, QObject::tr("AES-KDF")),
|
||||
qMakePair(KeePass2::KDF_ARGON2, QObject::tr("Argon2")),
|
||||
};
|
||||
|
||||
QSharedPointer<Kdf> KeePass2::uuidToKdf(const Uuid& uuid)
|
||||
{
|
||||
if (uuid == KDF_AES) {
|
||||
return QSharedPointer<AesKdf>::create();
|
||||
} else if (uuid == KDF_ARGON2) {
|
||||
return QSharedPointer<Argon2Kdf>::create();
|
||||
}
|
||||
|
||||
Q_ASSERT_X(false, "uuidToKdf", "Invalid UUID");
|
||||
|
@ -40,6 +40,7 @@ namespace KeePass2
|
||||
extern const Uuid CIPHER_CHACHA20;
|
||||
|
||||
extern const Uuid KDF_AES;
|
||||
extern const Uuid KDF_ARGON2;
|
||||
|
||||
extern const QByteArray INNER_STREAM_SALSA20_IV;
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "core/Group.h"
|
||||
#include "core/Metadata.h"
|
||||
#include "crypto/SymmetricCipher.h"
|
||||
#include "crypto/kdf/Argon2Kdf.h"
|
||||
#include "MessageBox.h"
|
||||
|
||||
DatabaseSettingsWidget::DatabaseSettingsWidget(QWidget* parent)
|
||||
@ -42,6 +43,7 @@ DatabaseSettingsWidget::DatabaseSettingsWidget(QWidget* parent)
|
||||
connect(m_ui->historyMaxSizeCheckBox, SIGNAL(toggled(bool)),
|
||||
m_ui->historyMaxSizeSpinBox, SLOT(setEnabled(bool)));
|
||||
connect(m_ui->transformBenchmarkButton, SIGNAL(clicked()), SLOT(transformRoundsBenchmark()));
|
||||
connect(m_ui->kdfComboBox, SIGNAL(currentIndexChanged(int)), SLOT(kdfChanged(int)));
|
||||
}
|
||||
|
||||
DatabaseSettingsWidget::~DatabaseSettingsWidget()
|
||||
@ -83,19 +85,29 @@ void DatabaseSettingsWidget::load(Database* db)
|
||||
m_ui->algorithmComboBox->setCurrentIndex(cipherIndex);
|
||||
}
|
||||
|
||||
bool blockSignals = m_ui->kdfComboBox->signalsBlocked();
|
||||
// Setup kdf combo box
|
||||
m_ui->kdfComboBox->blockSignals(true);
|
||||
|
||||
m_ui->kdfComboBox->clear();
|
||||
for (auto& kdf: asConst(KeePass2::KDFS)) {
|
||||
m_ui->kdfComboBox->addItem(kdf.second, kdf.first.toByteArray());
|
||||
}
|
||||
int kdfIndex = m_ui->kdfComboBox->findData(m_db->kdf()->uuid().toByteArray());
|
||||
m_ui->kdfComboBox->blockSignals(false);
|
||||
|
||||
auto kdfUuid = m_db->kdf()->uuid();
|
||||
int kdfIndex = m_ui->kdfComboBox->findData(kdfUuid.toByteArray());
|
||||
if (kdfIndex > -1) {
|
||||
m_ui->kdfComboBox->setCurrentIndex(kdfIndex);
|
||||
kdfChanged(kdfIndex);
|
||||
}
|
||||
|
||||
// Setup kdf parameters
|
||||
auto kdf = m_db->kdf();
|
||||
m_ui->transformRoundsSpinBox->setValue(kdf->rounds());
|
||||
if (kdfUuid == KeePass2::KDF_ARGON2) {
|
||||
auto argon2Kdf = kdf.staticCast<Argon2Kdf>();
|
||||
m_ui->memorySpinBox->setValue(argon2Kdf->memory());
|
||||
m_ui->parallelismSpinBox->setValue(argon2Kdf->parallelism());
|
||||
}
|
||||
m_ui->kdfComboBox->blockSignals(blockSignals);
|
||||
m_ui->transformRoundsSpinBox->setValue(static_cast<unsigned>(m_db->kdf()->rounds()));
|
||||
|
||||
m_ui->dbNameEdit->setFocus();
|
||||
}
|
||||
@ -139,8 +151,14 @@ void DatabaseSettingsWidget::save()
|
||||
|
||||
m_db->setCipher(Uuid(m_ui->algorithmComboBox->currentData().toByteArray()));
|
||||
|
||||
// Save kdf parameters
|
||||
auto kdf = KeePass2::uuidToKdf(Uuid(m_ui->kdfComboBox->currentData().toByteArray()));
|
||||
kdf->setRounds(static_cast<quint64>(qMax(0, m_ui->transformRoundsSpinBox->value())));
|
||||
kdf->setRounds(m_ui->transformRoundsSpinBox->value());
|
||||
if (kdf->uuid() == KeePass2::KDF_ARGON2) {
|
||||
auto argon2Kdf = kdf.staticCast<Argon2Kdf>();
|
||||
argon2Kdf->setMemory(m_ui->memorySpinBox->value());
|
||||
argon2Kdf->setParallelism(m_ui->parallelismSpinBox->value());
|
||||
}
|
||||
|
||||
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
||||
// TODO: we should probably use AsyncTask::runAndWaitForFuture() here,
|
||||
@ -164,11 +182,26 @@ void DatabaseSettingsWidget::reject()
|
||||
void DatabaseSettingsWidget::transformRoundsBenchmark()
|
||||
{
|
||||
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
|
||||
m_ui->transformRoundsSpinBox->setValue(AsyncTask::runAndWaitForFuture([this]() {
|
||||
int rounds = m_db->kdf()->benchmark(1000);
|
||||
QApplication::restoreOverrideCursor();
|
||||
return rounds;
|
||||
}));
|
||||
m_ui->transformBenchmarkButton->setEnabled(false);
|
||||
|
||||
// Create a new kdf with the current parameters
|
||||
auto kdf = KeePass2::uuidToKdf(Uuid(m_ui->kdfComboBox->currentData().toByteArray()));
|
||||
kdf->setRounds(m_ui->transformRoundsSpinBox->value());
|
||||
if (kdf->uuid() == KeePass2::KDF_ARGON2) {
|
||||
auto argon2Kdf = kdf.staticCast<Argon2Kdf>();
|
||||
argon2Kdf->setMemory(m_ui->memorySpinBox->value());
|
||||
argon2Kdf->setParallelism(m_ui->parallelismSpinBox->value());
|
||||
}
|
||||
|
||||
// Determine the number of rounds required to meet 1 second delay
|
||||
int rounds = AsyncTask::runAndWaitForFuture([this, kdf]() {
|
||||
return kdf->benchmark(1000);
|
||||
});
|
||||
|
||||
m_ui->transformRoundsSpinBox->setValue(rounds);
|
||||
|
||||
QApplication::restoreOverrideCursor();
|
||||
m_ui->transformBenchmarkButton->setEnabled(true);
|
||||
}
|
||||
|
||||
void DatabaseSettingsWidget::truncateHistories()
|
||||
@ -178,3 +211,15 @@ void DatabaseSettingsWidget::truncateHistories()
|
||||
entry->truncateHistory();
|
||||
}
|
||||
}
|
||||
|
||||
void DatabaseSettingsWidget::kdfChanged(int index)
|
||||
{
|
||||
Uuid id(m_ui->kdfComboBox->itemData(index).toByteArray());
|
||||
if (id == KeePass2::KDF_ARGON2) {
|
||||
m_ui->memorySpinBox->setEnabled(true);
|
||||
m_ui->parallelismSpinBox->setEnabled(true);
|
||||
} else {
|
||||
m_ui->memorySpinBox->setEnabled(false);
|
||||
m_ui->parallelismSpinBox->setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
@ -51,6 +51,7 @@ private slots:
|
||||
void save();
|
||||
void reject();
|
||||
void transformRoundsBenchmark();
|
||||
void kdfChanged(int index);
|
||||
|
||||
private:
|
||||
void truncateHistories();
|
||||
|
@ -2,6 +2,14 @@
|
||||
<ui version="4.0">
|
||||
<class>DatabaseSettingsWidget</class>
|
||||
<widget class="QWidget" name="DatabaseSettingsWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1082</width>
|
||||
<height>506</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout" stretch="1,2,5,1">
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
@ -35,39 +43,36 @@
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>800</width>
|
||||
<width>400</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="4" column="2">
|
||||
<item row="11" column="1">
|
||||
<widget class="QCheckBox" name="historyMaxSizeCheckBox">
|
||||
<property name="text">
|
||||
<string>Max. history size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLineEdit" name="dbNameEdit"/>
|
||||
</item>
|
||||
<item row="7" column="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="transformRoundsSpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
<widget class="QSpinBox" name="memorySpinBox">
|
||||
<property name="suffix">
|
||||
<string> MB</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000000000</number>
|
||||
<number>1048576</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="transformBenchmarkButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Benchmark</string>
|
||||
<property name="value">
|
||||
<number>64</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -80,31 +85,55 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QCheckBox" name="historyMaxSizeCheckBox">
|
||||
<property name="text">
|
||||
<string>Max. history size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1" alignment="Qt::AlignRight">
|
||||
<widget class="QLabel" name="transformRoundsLabel">
|
||||
<property name="text">
|
||||
<string>Transform rounds:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<item row="10" column="1">
|
||||
<widget class="QCheckBox" name="historyMaxItemsCheckBox">
|
||||
<property name="text">
|
||||
<string>Max. history items:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLineEdit" name="dbNameEdit"/>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLabel" name="kdfLabel">
|
||||
<property name="text">
|
||||
<string>Key Derivation Function</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="2">
|
||||
<item row="3" column="2">
|
||||
<widget class="QComboBox" name="algorithmComboBox">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>AES: 256 Bit (default)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Twofish: 256 Bit</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1" alignment="Qt::AlignRight">
|
||||
<widget class="QLabel" name="algorithmLabel">
|
||||
<property name="text">
|
||||
<string>Encryption Algorithm:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" alignment="Qt::AlignRight">
|
||||
<widget class="QLabel" name="dbDescriptionLabel">
|
||||
<property name="text">
|
||||
<string>Database description:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLineEdit" name="dbDescriptionEdit"/>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<widget class="QComboBox" name="kdfComboBox"/>
|
||||
</item>
|
||||
<item row="10" column="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="historyMaxItemsSpinBox">
|
||||
@ -121,17 +150,7 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="5" column="1" alignment="Qt::AlignRight">
|
||||
<widget class="QLabel" name="defaultUsernameLabel">
|
||||
<property name="text">
|
||||
<string>Default username:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLineEdit" name="dbDescriptionEdit"/>
|
||||
</item>
|
||||
<item row="8" column="2">
|
||||
<item row="11" column="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="historyMaxSizeSpinBox">
|
||||
@ -155,54 +174,101 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item row="6" column="2">
|
||||
<widget class="QCheckBox" name="recycleBinEnabledCheckBox">
|
||||
<property name="text">
|
||||
<string>Use recycle bin</string>
|
||||
<widget class="QSpinBox" name="transformRoundsSpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1000000000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="2">
|
||||
<widget class="QToolButton" name="transformBenchmarkButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Benchmark 1-second delay</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QLineEdit" name="defaultUsernameEdit">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" alignment="Qt::AlignRight">
|
||||
<widget class="QLabel" name="dbDescriptionLabel">
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="defaultUsernameLabel">
|
||||
<property name="text">
|
||||
<string>Database description:</string>
|
||||
<string>Default username:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QComboBox" name="algorithmComboBox">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>AES: 256 Bit (default)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Twofish: 256 Bit</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" alignment="Qt::AlignRight">
|
||||
<widget class="QLabel" name="algorithmLabel">
|
||||
<item row="6" column="1">
|
||||
<widget class="QLabel" name="transformRoundsLabel">
|
||||
<property name="text">
|
||||
<string>Encryption Algorithm:</string>
|
||||
<string>Transform rounds:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QComboBox" name="kdfComboBox"/>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLabel" name="kdfLabel">
|
||||
<item row="7" column="1">
|
||||
<widget class="QLabel" name="memoryUsageLabel">
|
||||
<property name="text">
|
||||
<string>Key Derivation Function</string>
|
||||
<string>Memory Usage:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<widget class="QLabel" name="parallelismLabel">
|
||||
<property name="text">
|
||||
<string>Parallelism:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="2">
|
||||
<widget class="QSpinBox" name="parallelismSpinBox">
|
||||
<property name="suffix">
|
||||
<string> thread</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>128</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QCheckBox" name="recycleBinEnabledCheckBox">
|
||||
<property name="text">
|
||||
<string>Use recycle bin</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -249,10 +315,6 @@
|
||||
<tabstops>
|
||||
<tabstop>dbNameEdit</tabstop>
|
||||
<tabstop>dbDescriptionEdit</tabstop>
|
||||
<tabstop>transformRoundsSpinBox</tabstop>
|
||||
<tabstop>transformBenchmarkButton</tabstop>
|
||||
<tabstop>defaultUsernameEdit</tabstop>
|
||||
<tabstop>recycleBinEnabledCheckBox</tabstop>
|
||||
<tabstop>historyMaxItemsCheckBox</tabstop>
|
||||
<tabstop>historyMaxItemsSpinBox</tabstop>
|
||||
<tabstop>historyMaxSizeCheckBox</tabstop>
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include "crypto/Crypto.h"
|
||||
#include "gui/Application.h"
|
||||
#include "gui/MainWindow.h"
|
||||
#include "gui/csvImport/CsvImportWizard.h"
|
||||
#include "gui/MessageBox.h"
|
||||
|
||||
#if defined(WITH_ASAN) && defined(WITH_LSAN)
|
||||
|
Loading…
Reference in New Issue
Block a user