Add Argon2id KDF (backport of #5726)

This commit is contained in:
Janek Bevendorff 2020-11-20 21:49:56 +01:00
parent 9cb36abe91
commit 3f7e79cdf3
10 changed files with 94 additions and 55 deletions

View file

@ -83,7 +83,7 @@ int Import::execute(const QStringList& arguments)
QString errorMessage; QString errorMessage;
Database db; Database db;
db.setKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2)); db.setKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2D));
db.setKey(key); db.setKey(key);
if (!db.import(xmlExportPath, &errorMessage)) { if (!db.import(xmlExportPath, &errorMessage)) {

View file

@ -29,8 +29,9 @@
* a 256-bit salt is generated each time the database is saved, the tag length is 256 bits, no secret key * 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. * or associated data. KeePass uses the latest version of Argon2, v1.3.
*/ */
Argon2Kdf::Argon2Kdf() Argon2Kdf::Argon2Kdf(Type type)
: Kdf::Kdf(KeePass2::KDF_ARGON2) : Kdf::Kdf(KeePass2::KDF_ARGON2D)
, m_type(type)
, m_version(0x13) , m_version(0x13)
, m_memory(1 << 16) , m_memory(1 << 16)
, m_parallelism(static_cast<quint32>(QThread::idealThreadCount())) , m_parallelism(static_cast<quint32>(QThread::idealThreadCount()))
@ -54,6 +55,16 @@ bool Argon2Kdf::setVersion(quint32 version)
return false; return false;
} }
Argon2Kdf::Type Argon2Kdf::type() const
{
return m_type;
}
void Argon2Kdf::setType(Type type)
{
m_type = type;
}
quint64 Argon2Kdf::memory() const quint64 Argon2Kdf::memory() const
{ {
return m_memory; return m_memory;
@ -133,7 +144,11 @@ bool Argon2Kdf::processParameters(const QVariantMap& p)
QVariantMap Argon2Kdf::writeParameters() QVariantMap Argon2Kdf::writeParameters()
{ {
QVariantMap p; QVariantMap p;
p.insert(KeePass2::KDFPARAM_UUID, KeePass2::KDF_ARGON2.toRfc4122()); if (type() == Type::Argon2d) {
p.insert(KeePass2::KDFPARAM_UUID, KeePass2::KDF_ARGON2D.toRfc4122());
} else {
p.insert(KeePass2::KDFPARAM_UUID, KeePass2::KDF_ARGON2ID.toRfc4122());
}
p.insert(KeePass2::KDFPARAM_ARGON2_VERSION, version()); p.insert(KeePass2::KDFPARAM_ARGON2_VERSION, version());
p.insert(KeePass2::KDFPARAM_ARGON2_PARALLELISM, parallelism()); p.insert(KeePass2::KDFPARAM_ARGON2_PARALLELISM, parallelism());
p.insert(KeePass2::KDFPARAM_ARGON2_MEMORY, memory() * 1024); p.insert(KeePass2::KDFPARAM_ARGON2_MEMORY, memory() * 1024);
@ -158,18 +173,20 @@ bool Argon2Kdf::transform(const QByteArray& raw, QByteArray& result) const
{ {
result.clear(); result.clear();
result.resize(32); result.resize(32);
return transformKeyRaw(raw, seed(), version(), rounds(), memory(), parallelism(), result); return transformKeyRaw(raw, seed(), version(), type(), rounds(), memory(), parallelism(), result);
} }
bool Argon2Kdf::transformKeyRaw(const QByteArray& key, bool Argon2Kdf::transformKeyRaw(const QByteArray& key,
const QByteArray& seed, const QByteArray& seed,
quint32 version, quint32 version,
Type type,
quint32 rounds, quint32 rounds,
quint64 memory, quint64 memory,
quint32 parallelism, quint32 parallelism,
QByteArray& result) QByteArray& result)
{ {
// Time Cost, Mem Cost, Threads/Lanes, Password, length, Salt, length, out, length // Time Cost, Mem Cost, Threads/Lanes, Password, length, Salt, length, out, length
int rc = argon2_hash(rounds, int rc = argon2_hash(rounds,
memory, memory,
parallelism, parallelism,
@ -181,7 +198,7 @@ bool Argon2Kdf::transformKeyRaw(const QByteArray& key,
result.size(), result.size(),
nullptr, nullptr,
0, 0,
Argon2_d, type == Type::Argon2d ? Argon2_d : Argon2_id,
version); version);
if (rc != ARGON2_OK) { if (rc != ARGON2_OK) {
qWarning("Argon2 error: %s", argon2_error_message(rc)); qWarning("Argon2 error: %s", argon2_error_message(rc));
@ -205,7 +222,7 @@ int Argon2Kdf::benchmarkImpl(int msec) const
timer.start(); timer.start();
int rounds = 4; int rounds = 4;
if (transformKeyRaw(key, seed, version(), rounds, memory(), parallelism(), key)) { if (transformKeyRaw(key, seed, version(), type(), rounds, memory(), parallelism(), key)) {
return static_cast<int>(rounds * (static_cast<float>(msec) / timer.elapsed())); return static_cast<int>(rounds * (static_cast<float>(msec) / timer.elapsed()));
} }
@ -214,5 +231,6 @@ int Argon2Kdf::benchmarkImpl(int msec) const
QString Argon2Kdf::toString() const QString Argon2Kdf::toString() const
{ {
return QObject::tr("Argon2 (%1 rounds, %2 KB)").arg(QString::number(rounds()), QString::number(memory())); return QObject::tr("Argon2%1 (%2 rounds, %3 KB)")
.arg(type() == Type::Argon2d ? "d" : "id", QString::number(rounds()), QString::number(memory()));
} }

View file

@ -23,7 +23,13 @@
class Argon2Kdf : public Kdf class Argon2Kdf : public Kdf
{ {
public: public:
Argon2Kdf(); enum class Type
{
Argon2d,
Argon2id
};
Argon2Kdf(Type type);
bool processParameters(const QVariantMap& p) override; bool processParameters(const QVariantMap& p) override;
QVariantMap writeParameters() override; QVariantMap writeParameters() override;
@ -32,6 +38,8 @@ public:
quint32 version() const; quint32 version() const;
bool setVersion(quint32 version); bool setVersion(quint32 version);
Type type() const;
void setType(Type type);
quint64 memory() const; quint64 memory() const;
bool setMemory(quint64 kibibytes); bool setMemory(quint64 kibibytes);
quint32 parallelism() const; quint32 parallelism() const;
@ -41,6 +49,7 @@ public:
protected: protected:
int benchmarkImpl(int msec) const override; int benchmarkImpl(int msec) const override;
Type m_type;
quint32 m_version; quint32 m_version;
quint64 m_memory; quint64 m_memory;
quint32 m_parallelism; quint32 m_parallelism;
@ -49,6 +58,7 @@ private:
Q_REQUIRED_RESULT static bool transformKeyRaw(const QByteArray& key, Q_REQUIRED_RESULT static bool transformKeyRaw(const QByteArray& key,
const QByteArray& seed, const QByteArray& seed,
quint32 version, quint32 version,
Type type,
quint32 rounds, quint32 rounds,
quint64 memory, quint64 memory,
quint32 parallelism, quint32 parallelism,

View file

@ -30,7 +30,8 @@ const QUuid KeePass2::CIPHER_CHACHA20 = QUuid("d6038a2b-8b6f-4cb5-a524-339a31dbb
const QUuid KeePass2::KDF_AES_KDBX3 = QUuid("c9d9f39a-628a-4460-bf74-0d08c18a4fea"); const QUuid KeePass2::KDF_AES_KDBX3 = QUuid("c9d9f39a-628a-4460-bf74-0d08c18a4fea");
const QUuid KeePass2::KDF_AES_KDBX4 = QUuid("7c02bb82-79a7-4ac0-927d-114a00648238"); const QUuid KeePass2::KDF_AES_KDBX4 = QUuid("7c02bb82-79a7-4ac0-927d-114a00648238");
const QUuid KeePass2::KDF_ARGON2 = QUuid("ef636ddf-8c29-444b-91f7-a9a403e30a0c"); const QUuid KeePass2::KDF_ARGON2D = QUuid("ef636ddf-8c29-444b-91f7-a9a403e30a0c");
const QUuid KeePass2::KDF_ARGON2ID = QUuid("9e298b19-56db-4773-b23d-fc3ec6f0a1e6");
const QByteArray KeePass2::INNER_STREAM_SALSA20_IV("\xe8\x30\x09\x4b\x97\x20\x5d\x2a"); const QByteArray KeePass2::INNER_STREAM_SALSA20_IV("\xe8\x30\x09\x4b\x97\x20\x5d\x2a");
@ -53,7 +54,8 @@ const QList<QPair<QUuid, QString>> KeePass2::CIPHERS{
qMakePair(KeePass2::CIPHER_CHACHA20, QObject::tr("ChaCha20 256-bit"))}; qMakePair(KeePass2::CIPHER_CHACHA20, QObject::tr("ChaCha20 256-bit"))};
const QList<QPair<QUuid, QString>> KeePass2::KDFS{ const QList<QPair<QUuid, QString>> KeePass2::KDFS{
qMakePair(KeePass2::KDF_ARGON2, QObject::tr("Argon2 (KDBX 4 – recommended)")), qMakePair(KeePass2::KDF_ARGON2D, QObject::tr("Argon2d (KDBX 4 – recommended)")),
qMakePair(KeePass2::KDF_ARGON2ID, QObject::tr("Argon2id (KDBX 4)")),
qMakePair(KeePass2::KDF_AES_KDBX4, QObject::tr("AES-KDF (KDBX 4)")), qMakePair(KeePass2::KDF_AES_KDBX4, QObject::tr("AES-KDF (KDBX 4)")),
qMakePair(KeePass2::KDF_AES_KDBX3, QObject::tr("AES-KDF (KDBX 3.1)"))}; qMakePair(KeePass2::KDF_AES_KDBX3, QObject::tr("AES-KDF (KDBX 3.1)"))};
@ -109,8 +111,11 @@ QSharedPointer<Kdf> KeePass2::uuidToKdf(const QUuid& uuid)
if (uuid == KDF_AES_KDBX4) { if (uuid == KDF_AES_KDBX4) {
return QSharedPointer<AesKdf>::create(); return QSharedPointer<AesKdf>::create();
} }
if (uuid == KDF_ARGON2) { if (uuid == KDF_ARGON2D) {
return QSharedPointer<Argon2Kdf>::create(); return QSharedPointer<Argon2Kdf>::create(Argon2Kdf::Type::Argon2d);
}
if (uuid == KDF_ARGON2ID) {
return QSharedPointer<Argon2Kdf>::create(Argon2Kdf::Type::Argon2id);
} }
return {}; return {};

View file

@ -53,7 +53,8 @@ namespace KeePass2
extern const QUuid KDF_AES_KDBX3; extern const QUuid KDF_AES_KDBX3;
extern const QUuid KDF_AES_KDBX4; extern const QUuid KDF_AES_KDBX4;
extern const QUuid KDF_ARGON2; extern const QUuid KDF_ARGON2D;
extern const QUuid KDF_ARGON2ID;
extern const QByteArray INNER_STREAM_SALSA20_IV; extern const QByteArray INNER_STREAM_SALSA20_IV;

View file

@ -72,7 +72,7 @@ Database* OpVaultReader::readDatabase(QDir& opdataDir, const QString& password)
key->addKey(QSharedPointer<PasswordKey>::create(password)); key->addKey(QSharedPointer<PasswordKey>::create(password));
QScopedPointer<Database> db(new Database()); QScopedPointer<Database> db(new Database());
db->setKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2)); db->setKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2D));
db->setCipher(KeePass2::CIPHER_AES256); db->setCipher(KeePass2::CIPHER_AES256);
db->setKey(key, true, false); db->setKey(key, true, false);
db->metadata()->setName(vaultName); db->metadata()->setName(vaultName);

View file

@ -43,7 +43,7 @@ DatabaseSettingsWidgetEncryption::DatabaseSettingsWidgetEncryption(QWidget* pare
connect(m_ui->memorySpinBox, SIGNAL(valueChanged(int)), this, SLOT(memoryChanged(int))); connect(m_ui->memorySpinBox, SIGNAL(valueChanged(int)), this, SLOT(memoryChanged(int)));
connect(m_ui->parallelismSpinBox, SIGNAL(valueChanged(int)), this, SLOT(parallelismChanged(int))); connect(m_ui->parallelismSpinBox, SIGNAL(valueChanged(int)), this, SLOT(parallelismChanged(int)));
m_ui->compatibilitySelection->addItem(tr("KDBX 4.0 (recommended)"), KeePass2::KDF_ARGON2.toByteArray()); m_ui->compatibilitySelection->addItem(tr("KDBX 4.0 (recommended)"), KeePass2::KDF_ARGON2D.toByteArray());
m_ui->compatibilitySelection->addItem(tr("KDBX 3.1"), KeePass2::KDF_AES_KDBX3.toByteArray()); m_ui->compatibilitySelection->addItem(tr("KDBX 3.1"), KeePass2::KDF_AES_KDBX3.toByteArray());
m_ui->decryptionTimeSlider->setMinimum(Kdf::MIN_ENCRYPTION_TIME / 100); m_ui->decryptionTimeSlider->setMinimum(Kdf::MIN_ENCRYPTION_TIME / 100);
m_ui->decryptionTimeSlider->setMaximum(Kdf::MAX_ENCRYPTION_TIME / 100); m_ui->decryptionTimeSlider->setMaximum(Kdf::MAX_ENCRYPTION_TIME / 100);
@ -75,6 +75,9 @@ DatabaseSettingsWidgetEncryption::~DatabaseSettingsWidgetEncryption()
{ {
} }
#define IS_ARGON2(uuid) (uuid == KeePass2::KDF_ARGON2D || uuid == KeePass2::KDF_ARGON2ID)
#define IS_AES_KDF(uuid) (uuid == KeePass2::KDF_AES_KDBX3 || uuid == KeePass2::KDF_AES_KDBX4)
void DatabaseSettingsWidgetEncryption::initialize() void DatabaseSettingsWidgetEncryption::initialize()
{ {
Q_ASSERT(m_db); Q_ASSERT(m_db);
@ -85,7 +88,7 @@ void DatabaseSettingsWidgetEncryption::initialize()
bool isDirty = false; bool isDirty = false;
if (!m_db->kdf()) { if (!m_db->kdf()) {
m_db->setKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2)); m_db->setKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2D));
isDirty = true; isDirty = true;
} }
if (!m_db->key()) { if (!m_db->key()) {
@ -175,7 +178,7 @@ void DatabaseSettingsWidgetEncryption::loadKdfParameters()
} }
m_ui->transformRoundsSpinBox->setValue(kdf->rounds()); m_ui->transformRoundsSpinBox->setValue(kdf->rounds());
if (m_db->kdf()->uuid() == KeePass2::KDF_ARGON2) { if (IS_ARGON2(m_db->kdf()->uuid())) {
auto argon2Kdf = kdf.staticCast<Argon2Kdf>(); auto argon2Kdf = kdf.staticCast<Argon2Kdf>();
m_ui->memorySpinBox->setValue(static_cast<int>(argon2Kdf->memory()) / (1 << 10)); m_ui->memorySpinBox->setValue(static_cast<int>(argon2Kdf->memory()) / (1 << 10));
m_ui->parallelismSpinBox->setValue(argon2Kdf->parallelism()); m_ui->parallelismSpinBox->setValue(argon2Kdf->parallelism());
@ -188,13 +191,10 @@ void DatabaseSettingsWidgetEncryption::updateKdfFields()
{ {
QUuid id = m_db->kdf()->uuid(); QUuid id = m_db->kdf()->uuid();
bool memoryVisible = (id == KeePass2::KDF_ARGON2); m_ui->memoryUsageLabel->setVisible(IS_ARGON2(id));
m_ui->memoryUsageLabel->setVisible(memoryVisible); m_ui->memorySpinBox->setVisible(IS_ARGON2(id));
m_ui->memorySpinBox->setVisible(memoryVisible); m_ui->parallelismLabel->setVisible(IS_ARGON2(id));
m_ui->parallelismSpinBox->setVisible(IS_ARGON2(id));
bool parallelismVisible = (id == KeePass2::KDF_ARGON2);
m_ui->parallelismLabel->setVisible(parallelismVisible);
m_ui->parallelismSpinBox->setVisible(parallelismVisible);
} }
void DatabaseSettingsWidgetEncryption::activateChangeDecryptionTime() void DatabaseSettingsWidgetEncryption::activateChangeDecryptionTime()
@ -253,7 +253,7 @@ bool DatabaseSettingsWidgetEncryption::save()
m_db->metadata()->customData()->remove(CD_DECRYPTION_TIME_PREFERENCE_KEY); m_db->metadata()->customData()->remove(CD_DECRYPTION_TIME_PREFERENCE_KEY);
// first perform safety check for KDF rounds // first perform safety check for KDF rounds
if (kdf->uuid() == KeePass2::KDF_ARGON2 && m_ui->transformRoundsSpinBox->value() > 10000) { if (IS_ARGON2(kdf->uuid()) && m_ui->transformRoundsSpinBox->value() > 10000) {
QMessageBox warning; QMessageBox warning;
warning.setIcon(QMessageBox::Warning); warning.setIcon(QMessageBox::Warning);
warning.setWindowTitle(tr("Number of rounds too high", "Key transformation rounds")); warning.setWindowTitle(tr("Number of rounds too high", "Key transformation rounds"));
@ -266,8 +266,7 @@ bool DatabaseSettingsWidgetEncryption::save()
if (warning.clickedButton() != ok) { if (warning.clickedButton() != ok) {
return false; return false;
} }
} else if ((kdf->uuid() == KeePass2::KDF_AES_KDBX3 || kdf->uuid() == KeePass2::KDF_AES_KDBX4) } else if (IS_AES_KDF(kdf->uuid()) && m_ui->transformRoundsSpinBox->value() < 100000) {
&& m_ui->transformRoundsSpinBox->value() < 100000) {
QMessageBox warning; QMessageBox warning;
warning.setIcon(QMessageBox::Warning); warning.setIcon(QMessageBox::Warning);
warning.setWindowTitle(tr("Number of rounds too low", "Key transformation rounds")); warning.setWindowTitle(tr("Number of rounds too low", "Key transformation rounds"));
@ -286,7 +285,7 @@ bool DatabaseSettingsWidgetEncryption::save()
// Save kdf parameters // Save kdf parameters
kdf->setRounds(m_ui->transformRoundsSpinBox->value()); kdf->setRounds(m_ui->transformRoundsSpinBox->value());
if (kdf->uuid() == KeePass2::KDF_ARGON2) { if (IS_ARGON2(kdf->uuid())) {
auto argon2Kdf = kdf.staticCast<Argon2Kdf>(); auto argon2Kdf = kdf.staticCast<Argon2Kdf>();
argon2Kdf->setMemory(static_cast<quint64>(m_ui->memorySpinBox->value()) * (1 << 10)); argon2Kdf->setMemory(static_cast<quint64>(m_ui->memorySpinBox->value()) * (1 << 10));
argon2Kdf->setParallelism(static_cast<quint32>(m_ui->parallelismSpinBox->value())); argon2Kdf->setParallelism(static_cast<quint32>(m_ui->parallelismSpinBox->value()));
@ -317,7 +316,7 @@ void DatabaseSettingsWidgetEncryption::benchmarkTransformRounds(int millisecs)
// Create a new kdf with the current parameters // Create a new kdf with the current parameters
auto kdf = KeePass2::uuidToKdf(QUuid(m_ui->kdfComboBox->currentData().toByteArray())); auto kdf = KeePass2::uuidToKdf(QUuid(m_ui->kdfComboBox->currentData().toByteArray()));
kdf->setRounds(m_ui->transformRoundsSpinBox->value()); kdf->setRounds(m_ui->transformRoundsSpinBox->value());
if (kdf->uuid() == KeePass2::KDF_ARGON2) { if (IS_ARGON2(kdf->uuid())) {
auto argon2Kdf = kdf.staticCast<Argon2Kdf>(); auto argon2Kdf = kdf.staticCast<Argon2Kdf>();
if (!argon2Kdf->setMemory(static_cast<quint64>(m_ui->memorySpinBox->value()) * (1 << 10))) { if (!argon2Kdf->setMemory(static_cast<quint64>(m_ui->memorySpinBox->value()) * (1 << 10))) {
m_ui->memorySpinBox->setValue(static_cast<int>(argon2Kdf->memory() / (1 << 10))); m_ui->memorySpinBox->setValue(static_cast<int>(argon2Kdf->memory() / (1 << 10)));
@ -402,7 +401,7 @@ void DatabaseSettingsWidgetEncryption::updateFormatCompatibility(int index, bool
auto kdf = KeePass2::uuidToKdf(kdfUuid); auto kdf = KeePass2::uuidToKdf(kdfUuid);
m_db->setKdf(kdf); m_db->setKdf(kdf);
if (kdf->uuid() == KeePass2::KDF_ARGON2) { if (IS_ARGON2(kdf->uuid())) {
auto argon2Kdf = kdf.staticCast<Argon2Kdf>(); auto argon2Kdf = kdf.staticCast<Argon2Kdf>();
// Default to 64 MiB of memory and 2 threads // Default to 64 MiB of memory and 2 threads
// these settings are safe for desktop and mobile devices // these settings are safe for desktop and mobile devices

View file

@ -42,8 +42,8 @@ int main(int argc, char* argv[])
void TestKdbx4Argon2::initTestCaseImpl() void TestKdbx4Argon2::initTestCaseImpl()
{ {
m_xmlDb->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2))); m_xmlDb->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2D)));
m_kdbxSourceDb->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2))); m_kdbxSourceDb->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2D)));
} }
QSharedPointer<Database> QSharedPointer<Database>
@ -108,7 +108,7 @@ void TestKdbx4Argon2::readKdbx(const QString& path,
void TestKdbx4Argon2::writeKdbx(QIODevice* device, Database* db, bool& hasError, QString& errorString) void TestKdbx4Argon2::writeKdbx(QIODevice* device, Database* db, bool& hasError, QString& errorString)
{ {
if (db->kdf()->uuid() == KeePass2::KDF_AES_KDBX3) { if (db->kdf()->uuid() == KeePass2::KDF_AES_KDBX3) {
db->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2))); db->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2D)));
} }
KeePass2Writer writer; KeePass2Writer writer;
hasError = writer.writeDatabase(device, db); hasError = writer.writeDatabase(device, db);
@ -213,26 +213,32 @@ void TestKdbx4Argon2::testFormat400Upgrade_data()
auto constexpr kdbx3 = KeePass2::FILE_VERSION_3_1 & KeePass2::FILE_VERSION_CRITICAL_MASK; auto constexpr kdbx3 = KeePass2::FILE_VERSION_3_1 & KeePass2::FILE_VERSION_CRITICAL_MASK;
auto constexpr kdbx4 = KeePass2::FILE_VERSION_4 & KeePass2::FILE_VERSION_CRITICAL_MASK; auto constexpr kdbx4 = KeePass2::FILE_VERSION_4 & KeePass2::FILE_VERSION_CRITICAL_MASK;
QTest::newRow("Argon2 + AES") << KeePass2::KDF_ARGON2 << KeePass2::CIPHER_AES256 << false << kdbx4; QTest::newRow("Argon2d + AES") << KeePass2::KDF_ARGON2D << KeePass2::CIPHER_AES256 << false << kdbx4;
QTest::newRow("AES-KDF + AES") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_AES256 << false << kdbx4; QTest::newRow("Argon2id + AES") << KeePass2::KDF_ARGON2ID << KeePass2::CIPHER_AES256 << false << kdbx4;
QTest::newRow("AES-KDF (legacy) + AES") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_AES256 << false << kdbx3; QTest::newRow("AES-KDF + AES") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_AES256 << false << kdbx4;
QTest::newRow("Argon2 + AES + CustomData") << KeePass2::KDF_ARGON2 << KeePass2::CIPHER_AES256 << true << kdbx4; QTest::newRow("AES-KDF (legacy) + AES") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_AES256 << false << kdbx3;
QTest::newRow("AES-KDF + AES + CustomData") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_AES256 << true << kdbx4; QTest::newRow("Argon2d + AES + CustomData") << KeePass2::KDF_ARGON2D << KeePass2::CIPHER_AES256 << true << kdbx4;
QTest::newRow("AES-KDF (legacy) + AES + CustomData") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_AES256 << true << kdbx4; QTest::newRow("Argon2id + AES + CustomData") << KeePass2::KDF_ARGON2ID << KeePass2::CIPHER_AES256 << true << kdbx4;
QTest::newRow("AES-KDF + AES + CustomData") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_AES256 << true << kdbx4;
QTest::newRow("AES-KDF (legacy) + AES + CustomData") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_AES256 << true << kdbx4;
QTest::newRow("Argon2 + ChaCha20") << KeePass2::KDF_ARGON2 << KeePass2::CIPHER_CHACHA20 << false << kdbx4; QTest::newRow("Argon2d + ChaCha20") << KeePass2::KDF_ARGON2D << KeePass2::CIPHER_CHACHA20 << false << kdbx4;
QTest::newRow("AES-KDF + ChaCha20") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_CHACHA20 << false << kdbx4; QTest::newRow("Argon2id + ChaCha20") << KeePass2::KDF_ARGON2ID << KeePass2::CIPHER_CHACHA20 << false << kdbx4;
QTest::newRow("AES-KDF (legacy) + ChaCha20") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_CHACHA20 << false << kdbx3; QTest::newRow("AES-KDF + ChaCha20") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_CHACHA20 << false << kdbx4;
QTest::newRow("Argon2 + ChaCha20 + CustomData") << KeePass2::KDF_ARGON2 << KeePass2::CIPHER_CHACHA20 << true << kdbx4; QTest::newRow("AES-KDF (legacy) + ChaCha20") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_CHACHA20 << false << kdbx3;
QTest::newRow("AES-KDF + ChaCha20 + CustomData") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_CHACHA20 << true << kdbx4; QTest::newRow("Argon2d + ChaCha20 + CustomData") << KeePass2::KDF_ARGON2D << KeePass2::CIPHER_CHACHA20 << true << kdbx4;
QTest::newRow("AES-KDF (legacy) + ChaCha20 + CustomData") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_CHACHA20 << true << kdbx4; QTest::newRow("Argon2id + ChaCha20 + CustomData") << KeePass2::KDF_ARGON2ID << KeePass2::CIPHER_CHACHA20 << true << kdbx4;
QTest::newRow("AES-KDF + ChaCha20 + CustomData") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_CHACHA20 << true << kdbx4;
QTest::newRow("AES-KDF (legacy) + ChaCha20 + CustomData") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_CHACHA20 << true << kdbx4;
QTest::newRow("Argon2 + Twofish") << KeePass2::KDF_ARGON2 << KeePass2::CIPHER_TWOFISH << false << kdbx4; QTest::newRow("Argon2d + Twofish") << KeePass2::KDF_ARGON2D << KeePass2::CIPHER_TWOFISH << false << kdbx4;
QTest::newRow("AES-KDF + Twofish") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_TWOFISH << false << kdbx4; QTest::newRow("Argon2id + Twofish") << KeePass2::KDF_ARGON2ID << KeePass2::CIPHER_TWOFISH << false << kdbx4;
QTest::newRow("AES-KDF (legacy) + Twofish") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_TWOFISH << false << kdbx3; QTest::newRow("AES-KDF + Twofish") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_TWOFISH << false << kdbx4;
QTest::newRow("Argon2 + Twofish + CustomData") << KeePass2::KDF_ARGON2 << KeePass2::CIPHER_TWOFISH << true << kdbx4; QTest::newRow("AES-KDF (legacy) + Twofish") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_TWOFISH << false << kdbx3;
QTest::newRow("AES-KDF + Twofish + CustomData") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_TWOFISH << true << kdbx4; QTest::newRow("Argon2d + Twofish + CustomData") << KeePass2::KDF_ARGON2D << KeePass2::CIPHER_TWOFISH << true << kdbx4;
QTest::newRow("AES-KDF (legacy) + Twofish + CustomData") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_TWOFISH << true << kdbx4; QTest::newRow("Argon2id + Twofish + CustomData") << KeePass2::KDF_ARGON2ID << KeePass2::CIPHER_TWOFISH << true << kdbx4;
QTest::newRow("AES-KDF + Twofish + CustomData") << KeePass2::KDF_AES_KDBX4 << KeePass2::CIPHER_TWOFISH << true << kdbx4;
QTest::newRow("AES-KDF (legacy) + Twofish + CustomData") << KeePass2::KDF_AES_KDBX3 << KeePass2::CIPHER_TWOFISH << true << kdbx4;
} }
// clang-format on // clang-format on
@ -270,7 +276,7 @@ void TestKdbx4Argon2::testUpgradeMasterKeyIntegrity()
} else if (upgradeAction == "kdf-aes-kdbx3") { } else if (upgradeAction == "kdf-aes-kdbx3") {
db->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_AES_KDBX3))); db->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_AES_KDBX3)));
} else if (upgradeAction == "kdf-argon2") { } else if (upgradeAction == "kdf-argon2") {
db->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2))); db->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_ARGON2D)));
} else if (upgradeAction == "kdf-aes-kdbx4") { } else if (upgradeAction == "kdf-aes-kdbx4") {
db->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_AES_KDBX4))); db->changeKdf(fastKdf(KeePass2::uuidToKdf(KeePass2::KDF_AES_KDBX4)));
} else if (upgradeAction == "public-customdata") { } else if (upgradeAction == "public-customdata") {

View file

@ -809,7 +809,7 @@ QSharedPointer<Kdf> TestKeePass2Format::fastKdf(QSharedPointer<Kdf> kdf) const
{ {
kdf->setRounds(1); kdf->setRounds(1);
if (kdf->uuid() == KeePass2::KDF_ARGON2) { if (kdf->uuid() == KeePass2::KDF_ARGON2D) {
kdf->processParameters({{KeePass2::KDFPARAM_ARGON2_MEMORY, 1024}, {KeePass2::KDFPARAM_ARGON2_PARALLELISM, 1}}); kdf->processParameters({{KeePass2::KDFPARAM_ARGON2_MEMORY, 1024}, {KeePass2::KDFPARAM_ARGON2_PARALLELISM, 1}});
} }

View file

@ -302,7 +302,7 @@ void TestGui::testCreateDatabase()
// check key and encryption // check key and encryption
QCOMPARE(m_db->key()->keys().size(), 2); QCOMPARE(m_db->key()->keys().size(), 2);
QCOMPARE(m_db->kdf()->rounds(), 2); QCOMPARE(m_db->kdf()->rounds(), 2);
QCOMPARE(m_db->kdf()->uuid(), KeePass2::KDF_ARGON2); QCOMPARE(m_db->kdf()->uuid(), KeePass2::KDF_ARGON2D);
QCOMPARE(m_db->cipher(), KeePass2::CIPHER_AES256); QCOMPARE(m_db->cipher(), KeePass2::CIPHER_AES256);
auto compositeKey = QSharedPointer<CompositeKey>::create(); auto compositeKey = QSharedPointer<CompositeKey>::create();
compositeKey->addKey(QSharedPointer<PasswordKey>::create("test")); compositeKey->addKey(QSharedPointer<PasswordKey>::create("test"));