mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-01-14 00:39:53 -05:00
Use QSharedPointer instead of cloning YkChallengeResponseKey and make it a QObject to allow emitting signals
This commit is contained in:
parent
e93e4a9931
commit
093fe5c7ef
@ -257,18 +257,16 @@ bool Database::verifyKey(const CompositeKey& key) const
|
|||||||
{
|
{
|
||||||
Q_ASSERT(hasKey());
|
Q_ASSERT(hasKey());
|
||||||
|
|
||||||
/* If the database has challenge response keys, then the the verification
|
|
||||||
* key better as well */
|
|
||||||
if (!m_data.challengeResponseKey.isEmpty()) {
|
if (!m_data.challengeResponseKey.isEmpty()) {
|
||||||
QByteArray result;
|
QByteArray result;
|
||||||
|
|
||||||
if (!key.challenge(m_data.masterSeed, result)) {
|
if (!key.challenge(m_data.masterSeed, result)) {
|
||||||
/* Challenge failed, (YubiKey?) removed? */
|
// challenge failed, (YubiKey?) removed?
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_data.challengeResponseKey != result) {
|
if (m_data.challengeResponseKey != result) {
|
||||||
/* Wrong response from challenged device(s) */
|
// wrong response from challenged device(s)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -115,7 +115,7 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke
|
|||||||
|
|
||||||
if (m_db->challengeMasterSeed(m_masterSeed) == false) {
|
if (m_db->challengeMasterSeed(m_masterSeed) == false) {
|
||||||
raiseError(tr("Unable to issue challenge-response."));
|
raiseError(tr("Unable to issue challenge-response."));
|
||||||
return Q_NULLPTR;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
CryptoHash hash(CryptoHash::Sha256);
|
CryptoHash hash(CryptoHash::Sha256);
|
||||||
|
@ -15,8 +15,6 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <QtConcurrentRun>
|
|
||||||
|
|
||||||
#include "ChangeMasterKeyWidget.h"
|
#include "ChangeMasterKeyWidget.h"
|
||||||
#include "ui_ChangeMasterKeyWidget.h"
|
#include "ui_ChangeMasterKeyWidget.h"
|
||||||
|
|
||||||
@ -30,6 +28,9 @@
|
|||||||
|
|
||||||
#include "config-keepassx.h"
|
#include "config-keepassx.h"
|
||||||
|
|
||||||
|
#include <QtConcurrentRun>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
|
||||||
ChangeMasterKeyWidget::ChangeMasterKeyWidget(QWidget* parent)
|
ChangeMasterKeyWidget::ChangeMasterKeyWidget(QWidget* parent)
|
||||||
: DialogyWidget(parent)
|
: DialogyWidget(parent)
|
||||||
, m_ui(new Ui::ChangeMasterKeyWidget())
|
, m_ui(new Ui::ChangeMasterKeyWidget())
|
||||||
@ -172,9 +173,9 @@ void ChangeMasterKeyWidget::generateKey()
|
|||||||
MessageWidget::Error);
|
MessageWidget::Error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
bool blocking = i & true;
|
||||||
YkChallengeResponseKey key(i);
|
int slot = i >> 1;
|
||||||
|
auto key = QSharedPointer<YkChallengeResponseKey>(new YkChallengeResponseKey(slot, blocking));
|
||||||
m_key.addChallengeResponseKey(key);
|
m_key.addChallengeResponseKey(key);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -210,7 +211,7 @@ void ChangeMasterKeyWidget::pollYubikey()
|
|||||||
void ChangeMasterKeyWidget::yubikeyDetected(int slot, bool blocking)
|
void ChangeMasterKeyWidget::yubikeyDetected(int slot, bool blocking)
|
||||||
{
|
{
|
||||||
YkChallengeResponseKey yk(slot, blocking);
|
YkChallengeResponseKey yk(slot, blocking);
|
||||||
m_ui->comboChallengeResponse->addItem(yk.getName(), QVariant(slot));
|
m_ui->comboChallengeResponse->addItem(yk.getName(), QVariant((slot << 1) | blocking));
|
||||||
m_ui->comboChallengeResponse->setEnabled(m_ui->challengeResponseGroup->isChecked());
|
m_ui->comboChallengeResponse->setEnabled(m_ui->challengeResponseGroup->isChecked());
|
||||||
m_ui->buttonRedetectYubikey->setEnabled(m_ui->challengeResponseGroup->isChecked());
|
m_ui->buttonRedetectYubikey->setEnabled(m_ui->challengeResponseGroup->isChecked());
|
||||||
m_ui->yubikeyProgress->setVisible(false);
|
m_ui->yubikeyProgress->setVisible(false);
|
||||||
|
@ -15,8 +15,6 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <QtConcurrentRun>
|
|
||||||
|
|
||||||
#include "DatabaseOpenWidget.h"
|
#include "DatabaseOpenWidget.h"
|
||||||
#include "ui_DatabaseOpenWidget.h"
|
#include "ui_DatabaseOpenWidget.h"
|
||||||
|
|
||||||
@ -34,6 +32,9 @@
|
|||||||
|
|
||||||
#include "config-keepassx.h"
|
#include "config-keepassx.h"
|
||||||
|
|
||||||
|
#include <QtConcurrentRun>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
|
||||||
|
|
||||||
DatabaseOpenWidget::DatabaseOpenWidget(QWidget* parent)
|
DatabaseOpenWidget::DatabaseOpenWidget(QWidget* parent)
|
||||||
: DialogyWidget(parent),
|
: DialogyWidget(parent),
|
||||||
@ -156,7 +157,7 @@ void DatabaseOpenWidget::openDatabase()
|
|||||||
if (m_ui->messageWidget->isVisible()) {
|
if (m_ui->messageWidget->isVisible()) {
|
||||||
m_ui->messageWidget->animatedHide();
|
m_ui->messageWidget->animatedHide();
|
||||||
}
|
}
|
||||||
Q_EMIT editFinished(true);
|
emit editFinished(true);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_ui->messageWidget->showMessage(tr("Unable to open the database.")
|
m_ui->messageWidget->showMessage(tr("Unable to open the database.")
|
||||||
@ -209,8 +210,10 @@ CompositeKey DatabaseOpenWidget::databaseKey()
|
|||||||
if (m_ui->checkChallengeResponse->isChecked()) {
|
if (m_ui->checkChallengeResponse->isChecked()) {
|
||||||
int i = m_ui->comboChallengeResponse->currentIndex();
|
int i = m_ui->comboChallengeResponse->currentIndex();
|
||||||
i = m_ui->comboChallengeResponse->itemData(i).toInt();
|
i = m_ui->comboChallengeResponse->itemData(i).toInt();
|
||||||
YkChallengeResponseKey key(i);
|
|
||||||
|
|
||||||
|
bool blocking = i & true;
|
||||||
|
int slot = i >> 1;
|
||||||
|
auto key = QSharedPointer<YkChallengeResponseKey>(new YkChallengeResponseKey(slot, blocking));
|
||||||
masterKey.addChallengeResponseKey(key);
|
masterKey.addChallengeResponseKey(key);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -250,20 +253,21 @@ void DatabaseOpenWidget::browseKeyFile()
|
|||||||
|
|
||||||
void DatabaseOpenWidget::pollYubikey()
|
void DatabaseOpenWidget::pollYubikey()
|
||||||
{
|
{
|
||||||
// YubiKey init is slow, detect asynchronously to not block the UI
|
|
||||||
m_ui->buttonRedetectYubikey->setEnabled(false);
|
m_ui->buttonRedetectYubikey->setEnabled(false);
|
||||||
m_ui->checkChallengeResponse->setEnabled(false);
|
m_ui->checkChallengeResponse->setEnabled(false);
|
||||||
m_ui->checkChallengeResponse->setChecked(false);
|
m_ui->checkChallengeResponse->setChecked(false);
|
||||||
m_ui->comboChallengeResponse->setEnabled(false);
|
m_ui->comboChallengeResponse->setEnabled(false);
|
||||||
m_ui->comboChallengeResponse->clear();
|
m_ui->comboChallengeResponse->clear();
|
||||||
m_ui->yubikeyProgress->setVisible(true);
|
m_ui->yubikeyProgress->setVisible(true);
|
||||||
|
|
||||||
|
// YubiKey init is slow, detect asynchronously to not block the UI
|
||||||
QtConcurrent::run(YubiKey::instance(), &YubiKey::detect);
|
QtConcurrent::run(YubiKey::instance(), &YubiKey::detect);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DatabaseOpenWidget::yubikeyDetected(int slot, bool blocking)
|
void DatabaseOpenWidget::yubikeyDetected(int slot, bool blocking)
|
||||||
{
|
{
|
||||||
YkChallengeResponseKey yk(slot, blocking);
|
YkChallengeResponseKey yk(slot, blocking);
|
||||||
m_ui->comboChallengeResponse->addItem(yk.getName(), QVariant(slot));
|
m_ui->comboChallengeResponse->addItem(yk.getName(), QVariant((slot << 1) | blocking));
|
||||||
m_ui->comboChallengeResponse->setEnabled(true);
|
m_ui->comboChallengeResponse->setEnabled(true);
|
||||||
m_ui->checkChallengeResponse->setEnabled(true);
|
m_ui->checkChallengeResponse->setEnabled(true);
|
||||||
m_ui->buttonRedetectYubikey->setEnabled(true);
|
m_ui->buttonRedetectYubikey->setEnabled(true);
|
||||||
|
@ -25,7 +25,6 @@ class ChallengeResponseKey
|
|||||||
public:
|
public:
|
||||||
virtual ~ChallengeResponseKey() {}
|
virtual ~ChallengeResponseKey() {}
|
||||||
virtual QByteArray rawKey() const = 0;
|
virtual QByteArray rawKey() const = 0;
|
||||||
virtual ChallengeResponseKey* clone() const = 0;
|
|
||||||
virtual bool challenge(const QByteArray& challenge) = 0;
|
virtual bool challenge(const QByteArray& challenge) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -46,7 +46,6 @@ CompositeKey::~CompositeKey()
|
|||||||
void CompositeKey::clear()
|
void CompositeKey::clear()
|
||||||
{
|
{
|
||||||
qDeleteAll(m_keys);
|
qDeleteAll(m_keys);
|
||||||
qDeleteAll(m_challengeResponseKeys);
|
|
||||||
m_keys.clear();
|
m_keys.clear();
|
||||||
m_challengeResponseKeys.clear();
|
m_challengeResponseKeys.clear();
|
||||||
}
|
}
|
||||||
@ -73,8 +72,8 @@ CompositeKey& CompositeKey::operator=(const CompositeKey& key)
|
|||||||
for (const Key* subKey : asConst(key.m_keys)) {
|
for (const Key* subKey : asConst(key.m_keys)) {
|
||||||
addKey(*subKey);
|
addKey(*subKey);
|
||||||
}
|
}
|
||||||
for (const ChallengeResponseKey* subKey : asConst(key.m_challengeResponseKeys)) {
|
for (const auto subKey : asConst(key.m_challengeResponseKeys)) {
|
||||||
addChallengeResponseKey(*subKey);
|
addChallengeResponseKey(subKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
@ -176,9 +175,8 @@ QByteArray CompositeKey::transformKeyRaw(const QByteArray& key, const QByteArray
|
|||||||
|
|
||||||
bool CompositeKey::challenge(const QByteArray& seed, QByteArray& result) const
|
bool CompositeKey::challenge(const QByteArray& seed, QByteArray& result) const
|
||||||
{
|
{
|
||||||
/* If no challenge response was requested, return nothing to
|
// if no challenge response was requested, return nothing to
|
||||||
* maintain backwards compatability with regular databases.
|
// maintain backwards compatibility with regular databases.
|
||||||
*/
|
|
||||||
if (m_challengeResponseKeys.length() == 0) {
|
if (m_challengeResponseKeys.length() == 0) {
|
||||||
result.clear();
|
result.clear();
|
||||||
return true;
|
return true;
|
||||||
@ -186,9 +184,9 @@ bool CompositeKey::challenge(const QByteArray& seed, QByteArray& result) const
|
|||||||
|
|
||||||
CryptoHash cryptoHash(CryptoHash::Sha256);
|
CryptoHash cryptoHash(CryptoHash::Sha256);
|
||||||
|
|
||||||
for (ChallengeResponseKey* key : m_challengeResponseKeys) {
|
for (const auto key : m_challengeResponseKeys) {
|
||||||
/* If the device isn't present or fails, return an error */
|
// if the device isn't present or fails, return an error
|
||||||
if (key->challenge(seed) == false) {
|
if (!key->challenge(seed)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
cryptoHash.addData(key->rawKey());
|
cryptoHash.addData(key->rawKey());
|
||||||
@ -203,11 +201,12 @@ void CompositeKey::addKey(const Key& key)
|
|||||||
m_keys.append(key.clone());
|
m_keys.append(key.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompositeKey::addChallengeResponseKey(const ChallengeResponseKey& key)
|
void CompositeKey::addChallengeResponseKey(QSharedPointer<ChallengeResponseKey> key)
|
||||||
{
|
{
|
||||||
m_challengeResponseKeys.append(key.clone());
|
m_challengeResponseKeys.append(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int CompositeKey::transformKeyBenchmark(int msec)
|
int CompositeKey::transformKeyBenchmark(int msec)
|
||||||
{
|
{
|
||||||
TransformKeyBenchmarkThread thread1(msec);
|
TransformKeyBenchmarkThread thread1(msec);
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
|
||||||
#include "keys/Key.h"
|
#include "keys/Key.h"
|
||||||
#include "keys/ChallengeResponseKey.h"
|
#include "keys/ChallengeResponseKey.h"
|
||||||
@ -41,7 +42,7 @@ public:
|
|||||||
bool challenge(const QByteArray& seed, QByteArray &result) const;
|
bool challenge(const QByteArray& seed, QByteArray &result) const;
|
||||||
|
|
||||||
void addKey(const Key& key);
|
void addKey(const Key& key);
|
||||||
void addChallengeResponseKey(const ChallengeResponseKey& key);
|
void addChallengeResponseKey(QSharedPointer<ChallengeResponseKey> key);
|
||||||
|
|
||||||
static int transformKeyBenchmark(int msec);
|
static int transformKeyBenchmark(int msec);
|
||||||
static CompositeKey readFromLine(QString line);
|
static CompositeKey readFromLine(QString line);
|
||||||
@ -51,7 +52,7 @@ private:
|
|||||||
quint64 rounds, bool* ok, QString* errorString);
|
quint64 rounds, bool* ok, QString* errorString);
|
||||||
|
|
||||||
QList<Key*> m_keys;
|
QList<Key*> m_keys;
|
||||||
QList<ChallengeResponseKey*> m_challengeResponseKeys;
|
QList<QSharedPointer<ChallengeResponseKey>> m_challengeResponseKeys;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // KEEPASSX_COMPOSITEKEY_H
|
#endif // KEEPASSX_COMPOSITEKEY_H
|
||||||
|
@ -15,7 +15,6 @@
|
|||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QXmlStreamReader>
|
#include <QXmlStreamReader>
|
||||||
|
|
||||||
@ -26,11 +25,7 @@
|
|||||||
#include "keys/YkChallengeResponseKey.h"
|
#include "keys/YkChallengeResponseKey.h"
|
||||||
#include "keys/drivers/YubiKey.h"
|
#include "keys/drivers/YubiKey.h"
|
||||||
|
|
||||||
#include <QDebug>
|
YkChallengeResponseKey::YkChallengeResponseKey(int slot, bool blocking)
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
YkChallengeResponseKey::YkChallengeResponseKey(int slot,
|
|
||||||
bool blocking)
|
|
||||||
: m_slot(slot),
|
: m_slot(slot),
|
||||||
m_blocking(blocking)
|
m_blocking(blocking)
|
||||||
{
|
{
|
||||||
@ -41,40 +36,41 @@ QByteArray YkChallengeResponseKey::rawKey() const
|
|||||||
return m_key;
|
return m_key;
|
||||||
}
|
}
|
||||||
|
|
||||||
YkChallengeResponseKey* YkChallengeResponseKey::clone() const
|
/**
|
||||||
{
|
* Assumes yubikey()->init() was called
|
||||||
return new YkChallengeResponseKey(*this);
|
*/
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** Assumes yubikey()->init() was called */
|
|
||||||
bool YkChallengeResponseKey::challenge(const QByteArray& chal)
|
bool YkChallengeResponseKey::challenge(const QByteArray& chal)
|
||||||
{
|
{
|
||||||
return challenge(chal, 1);
|
return challenge(chal, 1);
|
||||||
}
|
}
|
||||||
|
#include <QDebug>
|
||||||
bool YkChallengeResponseKey::challenge(const QByteArray& chal, int retries)
|
bool YkChallengeResponseKey::challenge(const QByteArray& chal, unsigned retries)
|
||||||
{
|
{
|
||||||
if (YubiKey::instance()->challenge(m_slot, true, chal, m_key) != YubiKey::ERROR) {
|
Q_ASSERT(retries > 0);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If challenge failed, retry to detect YubiKeys in the event the YubiKey
|
do {
|
||||||
* was un-plugged and re-plugged */
|
--retries;
|
||||||
while (retries > 0) {
|
|
||||||
#ifdef QT_DEBUG
|
|
||||||
qDebug() << "Attempt" << retries << "to re-detect YubiKey(s)";
|
|
||||||
#endif
|
|
||||||
retries--;
|
|
||||||
|
|
||||||
if (YubiKey::instance()->init() != true) {
|
if (m_blocking) {
|
||||||
|
emit userInteractionRequired();
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result = YubiKey::instance()->challenge(m_slot, true, chal, m_key);
|
||||||
|
|
||||||
|
if (m_blocking) {
|
||||||
|
emit userConfirmed();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != YubiKey::ERROR) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if challenge failed, retry to detect YubiKeys in the event the YubiKey was un-plugged and re-plugged
|
||||||
|
if (retries > 0 && YubiKey::instance()->init() != true) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (YubiKey::instance()->challenge(m_slot, true, chal, m_key) != YubiKey::ERROR) {
|
} while (retries > 0);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -22,20 +22,34 @@
|
|||||||
#include "keys/ChallengeResponseKey.h"
|
#include "keys/ChallengeResponseKey.h"
|
||||||
#include "keys/drivers/YubiKey.h"
|
#include "keys/drivers/YubiKey.h"
|
||||||
|
|
||||||
class YkChallengeResponseKey : public ChallengeResponseKey
|
#include <QObject>
|
||||||
|
|
||||||
|
class YkChallengeResponseKey : public QObject, public ChallengeResponseKey
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
YkChallengeResponseKey(int slot = -1,
|
YkChallengeResponseKey(int slot = -1, bool blocking = false);
|
||||||
bool blocking = false);
|
|
||||||
|
|
||||||
QByteArray rawKey() const;
|
QByteArray rawKey() const;
|
||||||
YkChallengeResponseKey* clone() const;
|
|
||||||
bool challenge(const QByteArray& chal);
|
bool challenge(const QByteArray& chal);
|
||||||
bool challenge(const QByteArray& chal, int retries);
|
bool challenge(const QByteArray& chal, unsigned retries);
|
||||||
QString getName() const;
|
QString getName() const;
|
||||||
bool isBlocking() const;
|
bool isBlocking() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/**
|
||||||
|
* Emitted whenever user interaction is required to proceed with the challenge-response protocol.
|
||||||
|
* You can use this to show a helpful dialog informing the user that his assistance is required.
|
||||||
|
*/
|
||||||
|
void userInteractionRequired();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emitted when the user has provided their required input.
|
||||||
|
*/
|
||||||
|
void userConfirmed();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QByteArray m_key;
|
QByteArray m_key;
|
||||||
int m_slot;
|
int m_slot;
|
||||||
|
Loading…
Reference in New Issue
Block a user