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:
Jonathan White 2018-01-01 13:21:02 -05:00
parent 9140893cd3
commit 542ee42313
No known key found for this signature in database
GPG Key ID: 440FC65F2E0C6E01
18 changed files with 468 additions and 170 deletions

View File

@ -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)

View File

@ -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
View 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)

View File

@ -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})

View File

@ -46,6 +46,7 @@ target_link_libraries(keepassxc-cli
keepassx_core
Qt5::Core
${GCRYPT_LIBRARIES}
${ARGON2_LIBRARIES}
${GPGERROR_LIBRARIES}
${ZLIB_LIBRARIES}
${ZXCVBN_LIBRARIES})

View File

@ -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;

View File

@ -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()));
}

View File

@ -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;
};

View 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()));
}

View 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

View File

@ -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)

View File

@ -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;

View File

@ -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");

View File

@ -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;

View File

@ -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);
}
}

View File

@ -51,6 +51,7 @@ private slots:
void save();
void reject();
void transformRoundsBenchmark();
void kdfChanged(int index);
private:
void truncateHistories();

View File

@ -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>

View File

@ -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)