From 20e8e524a5ae4d9e053b7196c3b247664d266e69 Mon Sep 17 00:00:00 2001 From: jNullj <15849761+jNullj@users.noreply.github.com> Date: Sun, 12 Feb 2023 22:39:10 +0200 Subject: [PATCH 1/6] Fix/database settings spin box bug (#9101) Co-authored-by: jNullj --- src/gui/dbsettings/DatabaseSettingsWidgetGeneral.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/gui/dbsettings/DatabaseSettingsWidgetGeneral.cpp b/src/gui/dbsettings/DatabaseSettingsWidgetGeneral.cpp index ac883ac7a9..a146ebd7e1 100644 --- a/src/gui/dbsettings/DatabaseSettingsWidgetGeneral.cpp +++ b/src/gui/dbsettings/DatabaseSettingsWidgetGeneral.cpp @@ -50,14 +50,16 @@ void DatabaseSettingsWidgetGeneral::initialize() m_ui->historyMaxItemsCheckBox->setChecked(true); } else { m_ui->historyMaxItemsSpinBox->setValue(Metadata::DefaultHistoryMaxItems); + m_ui->historyMaxItemsSpinBox->setEnabled(false); m_ui->historyMaxItemsCheckBox->setChecked(false); } - int historyMaxSizeMiB = qRound(meta->historyMaxSize() / qreal(1048576)); + int historyMaxSizeMiB = qRound(meta->historyMaxSize() / qreal(1024 * 1024)); if (historyMaxSizeMiB > 0) { m_ui->historyMaxSizeSpinBox->setValue(historyMaxSizeMiB); m_ui->historyMaxSizeCheckBox->setChecked(true); } else { - m_ui->historyMaxSizeSpinBox->setValue(Metadata::DefaultHistoryMaxSize); + m_ui->historyMaxSizeSpinBox->setValue(qRound(Metadata::DefaultHistoryMaxSize / qreal(1024 * 1024))); + m_ui->historyMaxSizeSpinBox->setEnabled(false); m_ui->historyMaxSizeCheckBox->setChecked(false); } } From b4be71d9672b40bc39611282926ca8262cc73b7d Mon Sep 17 00:00:00 2001 From: Dmytro Maslenko Date: Thu, 9 Feb 2023 17:59:54 -0800 Subject: [PATCH 2/6] Fix arrows size when expand/collapse a group Change ratio from 0.7 to 0.9 to give a more coherent look and feel to the tree. --- src/gui/styles/base/BaseStyle.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/styles/base/BaseStyle.cpp b/src/gui/styles/base/BaseStyle.cpp index b74874bc1c..ae7a5de8bb 100644 --- a/src/gui/styles/base/BaseStyle.cpp +++ b/src/gui/styles/base/BaseStyle.cpp @@ -1049,7 +1049,7 @@ namespace Phantom // Expected time (release): 5usecs for regular-sized arrows Q_NEVER_INLINE void drawArrow(QPainter* p, QRect rect, Qt::ArrowType arrowDirection, const QBrush& brush) { - const qreal ArrowBaseRatio = 0.70; + const qreal ArrowBaseRatio = 0.9; qreal irx, iry, irw, irh; QRectF(rect).getRect(&irx, &iry, &irw, &irh); if (irw < 1.0 || irh < 1.0) From cc35bf20968110c514b8dbf5ff1b69bd94135a7b Mon Sep 17 00:00:00 2001 From: Akinori MUSHA Date: Mon, 6 Feb 2023 04:37:26 +0900 Subject: [PATCH 3/6] Select new entry after cloning Also fixes re-selecting entries during a search refresh --- src/gui/CloneDialog.cpp | 9 +++-- src/gui/CloneDialog.h | 3 ++ src/gui/CloneDialog.ui | 66 +++++++++++++++++++----------------- src/gui/DatabaseWidget.cpp | 8 +++++ src/gui/entry/EntryModel.cpp | 6 ++-- src/gui/entry/EntryView.cpp | 7 ++-- tests/gui/TestGui.cpp | 1 + 7 files changed, 59 insertions(+), 41 deletions(-) diff --git a/src/gui/CloneDialog.cpp b/src/gui/CloneDialog.cpp index 0ce2c5f2ec..3e3c853470 100644 --- a/src/gui/CloneDialog.cpp +++ b/src/gui/CloneDialog.cpp @@ -18,8 +18,6 @@ #include "CloneDialog.h" #include "ui_CloneDialog.h" -#include "config-keepassx.h" - CloneDialog::CloneDialog(DatabaseWidget* parent, Database* db, Entry* entry) : QDialog(parent) , m_ui(new Ui::CloneDialog()) @@ -29,8 +27,9 @@ CloneDialog::CloneDialog(DatabaseWidget* parent, Database* db, Entry* entry) m_parent = parent; m_ui->setupUi(this); - this->setFixedSize(this->sizeHint()); + window()->layout()->setSizeConstraint(QLayout::SetFixedSize); + setWindowFlag(Qt::WindowContextHelpButtonHint, false); setAttribute(Qt::WA_DeleteOnClose); connect(m_ui->buttonBox, SIGNAL(rejected()), SLOT(close())); @@ -54,10 +53,10 @@ void CloneDialog::cloneEntry() flags |= Entry::CloneIncludeHistory; } - Entry* entry = m_entry->clone(flags); + auto entry = m_entry->clone(flags); entry->setGroup(m_entry->group()); - m_parent->refreshSearch(); + emit entryCloned(entry); close(); } diff --git a/src/gui/CloneDialog.h b/src/gui/CloneDialog.h index fe2787e3da..febf9d480d 100644 --- a/src/gui/CloneDialog.h +++ b/src/gui/CloneDialog.h @@ -34,6 +34,9 @@ class CloneDialog : public QDialog explicit CloneDialog(DatabaseWidget* parent = nullptr, Database* db = nullptr, Entry* entry = nullptr); ~CloneDialog() override; +signals: + void entryCloned(Entry* clone); + private: QScopedPointer m_ui; diff --git a/src/gui/CloneDialog.ui b/src/gui/CloneDialog.ui index db0614dfac..80da0ee583 100644 --- a/src/gui/CloneDialog.ui +++ b/src/gui/CloneDialog.ui @@ -6,54 +6,56 @@ 0 0 - 347 - 136 + 319 + 132 Clone Entry Options + + true + - - - - - Append ' - Clone' to title - - - true - - - - - - - Replace username and password with references - - - - - - - Copy history - - - true - - - - + + + Append ' - Clone' to title + + + true + + + + + + + Replace username and password with references + + + + + + + Copy history + + + true + + Qt::Vertical + + QSizePolicy::Minimum + 20 - 40 + 6 diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index 882a87f491..9bb0ac475f 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -447,6 +447,11 @@ void DatabaseWidget::cloneEntry() } auto cloneDialog = new CloneDialog(this, m_db.data(), currentEntry); + connect(cloneDialog, &CloneDialog::entryCloned, this, [this](auto entry) { + refreshSearch(); + m_entryView->setCurrentEntry(entry); + }); + cloneDialog->show(); } @@ -1399,7 +1404,10 @@ void DatabaseWidget::performUnlockDatabase(const QString& password, const QStrin void DatabaseWidget::refreshSearch() { if (isSearchActive()) { + auto selectedEntry = m_entryView->currentEntry(); search(m_lastSearchText); + // Re-select the previous entry if it is still in the search + m_entryView->setCurrentEntry(selectedEntry); } } diff --git a/src/gui/entry/EntryModel.cpp b/src/gui/entry/EntryModel.cpp index b25b002ef2..877efe9d2b 100644 --- a/src/gui/entry/EntryModel.cpp +++ b/src/gui/entry/EntryModel.cpp @@ -50,8 +50,10 @@ Entry* EntryModel::entryFromIndex(const QModelIndex& index) const QModelIndex EntryModel::indexFromEntry(Entry* entry) const { int row = m_entries.indexOf(entry); - Q_ASSERT(row != -1); - return index(row, 1); + if (row >= 0) { + return index(row, 1); + } + return {}; } void EntryModel::setGroup(Group* group) diff --git a/src/gui/entry/EntryView.cpp b/src/gui/entry/EntryView.cpp index 67a9698b7f..c992ead7b5 100644 --- a/src/gui/entry/EntryView.cpp +++ b/src/gui/entry/EntryView.cpp @@ -279,8 +279,11 @@ int EntryView::numberOfSelectedEntries() void EntryView::setCurrentEntry(Entry* entry) { - selectionModel()->setCurrentIndex(m_sortModel->mapFromSource(m_model->indexFromEntry(entry)), - QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); + auto index = m_model->indexFromEntry(entry); + if (index.isValid()) { + selectionModel()->setCurrentIndex(m_sortModel->mapFromSource(index), + QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); + } } Entry* EntryView::entryFromIndex(const QModelIndex& index) diff --git a/tests/gui/TestGui.cpp b/tests/gui/TestGui.cpp index 6daec5645f..71cb7d7056 100644 --- a/tests/gui/TestGui.cpp +++ b/tests/gui/TestGui.cpp @@ -1230,6 +1230,7 @@ void TestGui::testCloneEntry() Entry* entryClone = entryView->entryFromIndex(entryView->model()->index(1, 1)); QVERIFY(entryOrg->uuid() != entryClone->uuid()); QCOMPARE(entryClone->title(), entryOrg->title() + QString(" - Clone")); + QVERIFY(m_dbWidget->currentSelectedEntry()->uuid() == entryClone->uuid()); } void TestGui::testEntryPlaceholders() From b84d38e7fb764ad2e9b228a62b3ac771de8a80cd Mon Sep 17 00:00:00 2001 From: Charlie Wang Date: Wed, 18 Jan 2023 19:06:06 -0500 Subject: [PATCH 4/6] Properly handle Windows Hello errors The KeyCredentialManager::RequestCreateAsync call can fail because we can end up in a situation where Windows Hello is initially available but then becomes unavailable, such as during a remote desktop session. This commit prevents a crash by moving the call into the try-catch. Fixes #7890 Also resets quick unlock if there is an unrecoverable error. This will not occur if the user merely canceled the Windows Hello dialog. --- share/translations/keepassxc_en.ts | 8 ++++---- src/gui/DatabaseOpenWidget.cpp | 7 ++++++- src/winhello/WindowsHello.cpp | 28 +++++++++++++++------------- 3 files changed, 25 insertions(+), 18 deletions(-) diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts index dbe5c95e01..fd7a60e000 100644 --- a/share/translations/keepassxc_en.ts +++ b/share/translations/keepassxc_en.ts @@ -1494,10 +1494,6 @@ To prevent this error from appearing, you must go to "Database Settings / S Retry with empty password - - Failed to authenticate with Windows Hello - - Failed to authenticate with Touch ID @@ -1555,6 +1551,10 @@ If you do not have a key file, please leave the field empty. authenticate to access the database + + Failed to authenticate with Windows Hello: %1 + + DatabaseSettingWidgetMetaData diff --git a/src/gui/DatabaseOpenWidget.cpp b/src/gui/DatabaseOpenWidget.cpp index 882d8d0572..f07e4b1afa 100644 --- a/src/gui/DatabaseOpenWidget.cpp +++ b/src/gui/DatabaseOpenWidget.cpp @@ -339,7 +339,12 @@ QSharedPointer DatabaseOpenWidget::buildDatabaseKey() #ifdef Q_CC_MSVC if (!getWindowsHello()->getKey(m_filename, keyData)) { // Failed to retrieve Quick Unlock data - m_ui->messageWidget->showMessage(tr("Failed to authenticate with Windows Hello"), MessageWidget::Error); + auto error = getWindowsHello()->errorString(); + if (!error.isEmpty()) { + m_ui->messageWidget->showMessage(tr("Failed to authenticate with Windows Hello: %1").arg(error), + MessageWidget::Error); + resetQuickUnlock(); + } return {}; } #elif defined(Q_OS_MACOS) diff --git a/src/winhello/WindowsHello.cpp b/src/winhello/WindowsHello.cpp index 99e798c501..bc244cc26c 100644 --- a/src/winhello/WindowsHello.cpp +++ b/src/winhello/WindowsHello.cpp @@ -64,22 +64,24 @@ namespace array_view(reinterpret_cast(challenge.data()), challenge.size())); return AsyncTask::runAndWaitForFuture([&] { - // The first time this is used a key-pair will be generated using the common name - auto result = - KeyCredentialManager::RequestCreateAsync(s_winHelloKeyName, KeyCredentialCreationOption::FailIfExists) - .get(); - - if (result.Status() == KeyCredentialStatus::CredentialAlreadyExists) { - result = KeyCredentialManager::OpenAsync(s_winHelloKeyName).get(); - } else if (result.Status() != KeyCredentialStatus::Success) { - error = QObject::tr("Failed to create Windows Hello credential."); - return false; - } - try { + // The first time this is used a key-pair will be generated using the common name + auto result = KeyCredentialManager::RequestCreateAsync(s_winHelloKeyName, + KeyCredentialCreationOption::FailIfExists) + .get(); + + if (result.Status() == KeyCredentialStatus::CredentialAlreadyExists) { + result = KeyCredentialManager::OpenAsync(s_winHelloKeyName).get(); + } else if (result.Status() != KeyCredentialStatus::Success) { + error = QObject::tr("Failed to create Windows Hello credential."); + return false; + } + const auto signature = result.Credential().RequestSignAsync(challengeBuffer).get(); if (signature.Status() != KeyCredentialStatus::Success) { - error = QObject::tr("Failed to sign challenge using Windows Hello."); + if (signature.Status() != KeyCredentialStatus::UserCanceled) { + error = QObject::tr("Failed to sign challenge using Windows Hello."); + } return false; } From f9d99fe8cac5a0306137b9679f3b292ceff5c156 Mon Sep 17 00:00:00 2001 From: Bernhard Kirchen Date: Mon, 4 Apr 2022 16:25:06 +0200 Subject: [PATCH 5/6] revise strings labeling history limit settings --- share/translations/keepassxc_en.ts | 37 +++++++++++++++---- .../DatabaseSettingsWidgetGeneral.ui | 20 ++++++++-- 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts index fd7a60e000..b0c1d25f16 100644 --- a/share/translations/keepassxc_en.ts +++ b/share/translations/keepassxc_en.ts @@ -1967,18 +1967,10 @@ If you keep this number, your database will not be protected from brute force at Maximum number of history items per entry - - Max. history items: - - Maximum size of history per entry - - Max. history size: - - MiB @@ -2008,6 +2000,35 @@ This action is not reversible. (old) + + When saving this setting or editing an entry +the oldest history items of an entry will be +removed such that only the specified amount +of entries remain at most. + + + + Limit the amount of history items per entry to: + + + + When saving this setting or editing an entry +the oldest history items of an entry will be +removed such that the remaining history items +add up to the specified amount at most. + + + + Limit the total size of history items per entry to: + + + + Move entries to a recycle bin group +instead of deleting them from the database. +Entries deleted from the recycle bin are +removed from the database. + + DatabaseSettingsWidgetKeeShare diff --git a/src/gui/dbsettings/DatabaseSettingsWidgetGeneral.ui b/src/gui/dbsettings/DatabaseSettingsWidgetGeneral.ui index 34185ad23f..952b444b1e 100644 --- a/src/gui/dbsettings/DatabaseSettingsWidgetGeneral.ui +++ b/src/gui/dbsettings/DatabaseSettingsWidgetGeneral.ui @@ -100,20 +100,26 @@ - Maximum number of history items per entry + When saving this setting or editing an entry +the oldest history items of an entry will be +removed such that only the specified amount +of entries remain at most. - Max. history items: + Limit the amount of history items per entry to: - Maximum size of history per entry + When saving this setting or editing an entry +the oldest history items of an entry will be +removed such that the remaining history items +add up to the specified amount at most. - Max. history size: + Limit the total size of history items per entry to: @@ -151,6 +157,12 @@ + + Move entries to a recycle bin group +instead of deleting them from the database. +Entries deleted from the recycle bin are +removed from the database. + Use recycle bin From ba15981700600ded62993ff50f824d99c71bdb6b Mon Sep 17 00:00:00 2001 From: Jonathan White Date: Mon, 2 Jan 2023 17:54:28 -0500 Subject: [PATCH 6/6] Translate Cipher and KDF strings * Fix #8952 - move translations for Cipher and KDF strings into evaluated code instead of globally defined code. The strings were being baked prior to the language being set resulting in only english being displayed. --- share/translations/keepassxc_en.ts | 8 ++++ src/cli/DatabaseInfo.cpp | 4 +- src/format/KeePass2.cpp | 40 ++++++++++++++----- src/format/KeePass2.h | 8 ++-- .../DatabaseSettingsWidgetEncryption.cpp | 6 +-- 5 files changed, 48 insertions(+), 18 deletions(-) diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts index b0c1d25f16..62db8cf5e8 100644 --- a/share/translations/keepassxc_en.ts +++ b/share/translations/keepassxc_en.ts @@ -7913,6 +7913,14 @@ Kernel: %3 %4 Failed to sign challenge using Windows Hello. + + Invalid Cipher + + + + Invalid KDF + + QtIOCompressor diff --git a/src/cli/DatabaseInfo.cpp b/src/cli/DatabaseInfo.cpp index b5569ae846..f0e5e0f033 100644 --- a/src/cli/DatabaseInfo.cpp +++ b/src/cli/DatabaseInfo.cpp @@ -39,8 +39,8 @@ int DatabaseInfo::executeWithDatabase(QSharedPointer database, QShared out << QObject::tr("Name: ") << database->metadata()->name() << endl; out << QObject::tr("Description: ") << database->metadata()->description() << endl; for (auto& cipher : asConst(KeePass2::CIPHERS)) { - if (cipher.first == database->cipher()) { - out << QObject::tr("Cipher: ") << cipher.second << endl; + if (cipher == database->cipher()) { + out << QObject::tr("Cipher: ") << KeePass2::cipherToString(cipher) << endl; } } out << QObject::tr("KDF: ") << database->kdf()->toString() << endl; diff --git a/src/format/KeePass2.cpp b/src/format/KeePass2.cpp index bf991f8805..b193167410 100644 --- a/src/format/KeePass2.cpp +++ b/src/format/KeePass2.cpp @@ -47,16 +47,12 @@ const QString KeePass2::KDFPARAM_ARGON2_VERSION("V"); const QString KeePass2::KDFPARAM_ARGON2_SECRET("K"); const QString KeePass2::KDFPARAM_ARGON2_ASSOCDATA("A"); -const QList> KeePass2::CIPHERS{ - qMakePair(KeePass2::CIPHER_AES256, QObject::tr("AES 256-bit")), - qMakePair(KeePass2::CIPHER_TWOFISH, QObject::tr("Twofish 256-bit")), - qMakePair(KeePass2::CIPHER_CHACHA20, QObject::tr("ChaCha20 256-bit"))}; +const QList KeePass2::CIPHERS{KeePass2::CIPHER_AES256, KeePass2::CIPHER_TWOFISH, KeePass2::CIPHER_CHACHA20}; -const QList> KeePass2::KDFS{ - 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_KDBX3, QObject::tr("AES-KDF (KDBX 3)"))}; +const QList KeePass2::KDFS{KeePass2::KDF_ARGON2D, + KeePass2::KDF_ARGON2ID, + KeePass2::KDF_AES_KDBX4, + KeePass2::KDF_AES_KDBX3}; QByteArray KeePass2::hmacKey(const QByteArray& masterSeed, const QByteArray& transformedMasterKey) { @@ -133,3 +129,29 @@ KeePass2::ProtectedStreamAlgo KeePass2::idToProtectedStreamAlgo(quint32 id) return KeePass2::ProtectedStreamAlgo::InvalidProtectedStreamAlgo; } } + +QString KeePass2::cipherToString(QUuid cipherUuid) +{ + if (cipherUuid == KeePass2::CIPHER_AES256) { + return QObject::tr("AES 256-bit"); + } else if (cipherUuid == KeePass2::CIPHER_TWOFISH) { + return QObject::tr("Twofish 256-bit"); + } else if (cipherUuid == KeePass2::CIPHER_CHACHA20) { + return QObject::tr("ChaCha20 256-bit"); + } + return QObject::tr("Invalid Cipher"); +} + +QString KeePass2::kdfToString(QUuid kdfUuid) +{ + if (kdfUuid == KeePass2::KDF_ARGON2D) { + return QObject::tr("Argon2d (KDBX 4 – recommended)"); + } else if (kdfUuid == KeePass2::KDF_ARGON2ID) { + return QObject::tr("Argon2id (KDBX 4)"); + } else if (kdfUuid == KeePass2::KDF_AES_KDBX4) { + return QObject::tr("AES-KDF (KDBX 4)"); + } else if (kdfUuid == KDF_AES_KDBX3) { + return QObject::tr("AES-KDF (KDBX 3)"); + } + return QObject::tr("Invalid KDF"); +} diff --git a/src/format/KeePass2.h b/src/format/KeePass2.h index 5aed903c3a..1d18a18ba9 100644 --- a/src/format/KeePass2.h +++ b/src/format/KeePass2.h @@ -26,7 +26,6 @@ class Kdf; namespace KeePass2 { - constexpr quint32 SIGNATURE_1 = 0x9AA2D903; constexpr quint32 SIGNATURE_2 = 0xB54BFB67; @@ -67,8 +66,8 @@ namespace KeePass2 extern const QString KDFPARAM_ARGON2_SECRET; extern const QString KDFPARAM_ARGON2_ASSOCDATA; - extern const QList> CIPHERS; - extern const QList> KDFS; + extern const QList CIPHERS; + extern const QList KDFS; enum class HeaderFieldID { @@ -130,7 +129,8 @@ namespace KeePass2 QVariantMap kdfToParameters(const QSharedPointer& kdf); QSharedPointer uuidToKdf(const QUuid& uuid); ProtectedStreamAlgo idToProtectedStreamAlgo(quint32 id); - + QString cipherToString(QUuid cipherUuid); + QString kdfToString(QUuid kdfUuid); } // namespace KeePass2 #endif // KEEPASSX_KEEPASS2_H diff --git a/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.cpp b/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.cpp index 3a3495dfc1..16db94d9f2 100644 --- a/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.cpp +++ b/src/gui/dbsettings/DatabaseSettingsWidgetEncryption.cpp @@ -141,7 +141,7 @@ void DatabaseSettingsWidgetEncryption::setupAlgorithmComboBox() { m_ui->algorithmComboBox->clear(); for (auto& cipher : asConst(KeePass2::CIPHERS)) { - m_ui->algorithmComboBox->addItem(cipher.second.toUtf8(), cipher.first.toByteArray()); + m_ui->algorithmComboBox->addItem(KeePass2::cipherToString(cipher), cipher.toByteArray()); } int cipherIndex = m_ui->algorithmComboBox->findData(m_db->cipher().toByteArray()); if (cipherIndex > -1) { @@ -155,8 +155,8 @@ void DatabaseSettingsWidgetEncryption::setupKdfComboBox(bool enableKdbx3) bool block = m_ui->kdfComboBox->blockSignals(true); m_ui->kdfComboBox->clear(); for (auto& kdf : asConst(KeePass2::KDFS)) { - if (kdf.first != KeePass2::KDF_AES_KDBX3 or enableKdbx3) { - m_ui->kdfComboBox->addItem(kdf.second.toUtf8(), kdf.first.toByteArray()); + if (kdf != KeePass2::KDF_AES_KDBX3 or enableKdbx3) { + m_ui->kdfComboBox->addItem(KeePass2::kdfToString(kdf), kdf.toByteArray()); } } m_ui->kdfComboBox->blockSignals(block);