[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [KSecretService] b3688d3: Make the test for unlocking the collection
From: Michael Leupold <lemma () confuego ! org>
Date: 2010-11-09 19:14:30
Message-ID: 20101109191430.4BC54A60F1 () git ! kde ! org
[Download RAW message or body]
commit b3688d3cc806c6e48a92330801619b168f05cd07
branch master
Author: Michael Leupold <lemma@confuego.org>
Date: Mon Sep 27 18:54:25 2010 +0000
Make the test for unlocking the collection work.
svn path=/trunk/playground/base/ksecretservice/; revision=1180349
diff --git a/backend/backendjob.h b/backend/backendjob.h
index 12563ba..452a8f1 100644
--- a/backend/backendjob.h
+++ b/backend/backendjob.h
@@ -370,7 +370,7 @@ public:
/**
* Constructor.
*/
- explicit UnlockCollectionJob(BackendCollection *collection);
+ UnlockCollectionJob(BackendCollection *collection);
/**
* Get the collection to unlock.
diff --git a/backend/ksecret/ksecretcollection.cpp b/backend/ksecret/ksecretcollection.cpp
index e90b3f3..5bdc23c 100644
--- a/backend/ksecret/ksecretcollection.cpp
+++ b/backend/ksecret/ksecretcollection.cpp
@@ -95,6 +95,19 @@ KSecretCollection *KSecretCollection::create(const QString &id, const QCA::Secur
key->m_key.append(keyCipher->update(*coll->m_symmetricKey).toByteArray());
key->m_key.append(keyCipher->final().toByteArray());
coll->m_encryptedSymKeys.append(key);
+
+ // build the verifier
+ coll->m_verInitVector = QCA::InitializationVector(coll->m_cipher->blockSize());
+ // get random data and compute its hash
+ QCA::SecureArray randomData = QCA::Random::randomArray(VERIFIER_LENGTH);
+ coll->m_hash->clear();
+ coll->m_hash->update(randomData);
+ randomData.append(coll->m_hash->final());
+ // now encrypt randomData
+ coll->m_cipher->setup(QCA::Encode, *coll->m_symmetricKey, coll->m_verInitVector);
+ coll->m_verEncryptedRandom = coll->m_cipher->update(randomData);
+ coll->m_verEncryptedRandom.append(coll->m_cipher->final());
+
return coll;
}
@@ -192,7 +205,8 @@ BackendReturn<QList<BackendItem*> > KSecretCollection::searchItems(
UnlockCollectionJob *KSecretCollection::createUnlockJob()
{
- return new KSecretUnlockCollectionJob(this);
+ UnlockCollectionJob *job = new KSecretUnlockCollectionJob(this);
+ return job;
}
LockCollectionJob *KSecretCollection::createLockJob()
@@ -357,18 +371,10 @@ KSecretCollection *KSecretCollection::deserialize(const QString &path,
return coll;
}
-const QList<EncryptedKey*> &KSecretCollection::encryptedSymKeys() const
-{
- return m_encryptedSymKeys;
-}
-
-void KSecretCollection::setSymKey(QCA::SymmetricKey *key)
-{
- m_symmetricKey = key;
-}
-
bool KSecretCollection::tryUnlock()
{
+ // TODO: after unlocking, check integrity by verifying the MACs.
+
// before actually trying to unlock, check if the key matches by decrypting
// the verifier.
m_cipher->setup(QCA::Decode, *m_symmetricKey, m_verInitVector);
@@ -405,9 +411,38 @@ bool KSecretCollection::tryUnlock()
}
}
+ emit collectionChanged(this);
+
return true;
}
+BackendReturn<bool> KSecretCollection::tryUnlockPassword(const QCA::SecureArray &password)
+{
+ // TODO: reference/open counting?
+
+ bool unlocked = false;
+
+ QCA::Cipher *keyCipher = m_cipher;
+ int keyLength = keyCipher->keyLength().minimum();
+ QCA::SymmetricKey keyUnlockKey = createKeyFromPassword(password, keyLength);
+ // try decrypting any of the symmetric keys using the keyUnlockKey
+ Q_FOREACH(EncryptedKey *key, m_encryptedSymKeys) {
+ if (key->m_type == KSecretFile::KeyPassword) {
+ keyCipher->setup(QCA::Decode, keyUnlockKey, key->m_iv);
+ QCA::SecureArray unlockedKey = keyCipher->update(key->m_key);
+ unlockedKey.append(keyCipher->final());
+ m_symmetricKey = new QCA::SymmetricKey(unlockedKey);
+
+ unlocked = tryUnlock();
+ if (unlocked) {
+ break;
+ }
+ }
+ }
+
+ return unlocked;
+}
+
BackendReturn<bool> KSecretCollection::lock()
{
// TODO: reference/open counting?
@@ -423,12 +458,6 @@ BackendReturn<bool> KSecretCollection::lock()
return BackendReturn<bool>(false, ErrorOther, errorMessage);
}
- // then remove the key
- delete m_hash;
- m_hash = 0;
- delete m_cipher;
- m_cipher = 0;
-
// remove individual item secrets
QHash<QString, KSecretItem*>::iterator it = m_items.begin();
QHash<QString, KSecretItem*>::iterator end = m_items.end();
@@ -516,7 +545,7 @@ bool KSecretCollection::deserializeHeader(KSecretFile &file, QString &errorMessa
}
// verifier
- if (!file.readBytearray(&m_verInitVector) || !file.readBytearray(&m_verEncryptedRandom)) {
+ if (!file.readSecret(&m_verInitVector) || !file.readSecret(&m_verEncryptedRandom)) {
errorMessage = genericLoadingErrorMessage();
return false;
}
@@ -919,20 +948,7 @@ bool KSecretCollection::serializeHeader(KSecretFile &file) const
}
// verifier
- QCA::InitializationVector iv(m_cipher->blockSize());
- if (!file.writeSecret(iv)) {
- return false;
- }
- // get random data and compute its hash
- QCA::SecureArray randomData = QCA::Random::randomArray(VERIFIER_LENGTH);
- m_hash->clear();
- m_hash->update(randomData);
- randomData.append(m_hash->final());
- // now encrypt randomData
- m_cipher->setup(QCA::Encode, *m_symmetricKey, iv);
- QCA::SecureArray verifier = m_cipher->update(randomData);
- verifier.append(m_cipher->final());
- if (!file.writeSecret(verifier)) {
+ if (!file.writeSecret(m_verInitVector) && !file.writeSecret(m_verEncryptedRandom)) {
return false;
}
diff --git a/backend/ksecret/ksecretcollection.h b/backend/ksecret/ksecretcollection.h
index 72175a4..d98c89c 100644
--- a/backend/ksecret/ksecretcollection.h
+++ b/backend/ksecret/ksecretcollection.h
@@ -230,26 +230,12 @@ public:
protected:
/**
- * Get the encrypted symmetric keys.
- *
- * @remarks this is used by KSecretUnlockCollectionJob
- */
- const QList<EncryptedKey*> &encryptedSymKeys() const;
-
- /**
- * Set the (unencrypted) symmetric key to use for encryption/decryption.
- *
- * @remarks this is used by KSecretUnlockCollectionJob
- */
- void setSymKey(QCA::SymmetricKey *key);
-
- /**
- * Try to unlock using the symmetric key set using setSymKey().
- *
- * @return true if unlocking succeeded, false if it failed
+ * Try to unlock the collection using the password provided.
+ *
+ * @return true if unlocking succeeded, false else
* @remarks this is used by KSecretUnlockCollectionJob
*/
- bool tryUnlock();
+ BackendReturn<bool> tryUnlockPassword(const QCA::SecureArray &password);
/**
* Lock this collection. This is implemented here for convenience purposes.
@@ -274,7 +260,7 @@ protected:
* @remarks this is used by KSecretDeleteCollectionJob
*/
BackendReturn<bool> deleteCollection();
-
+
private:
friend class KSecretUnlockCollectionJob;
friend class KSecretLockCollectionJob;
@@ -291,6 +277,14 @@ private:
};
/**
+ * Try to unlock using the currently set symmetric key.
+ *
+ * @return true if unlocking succeeded, false if it failed
+ * @remarks this is used by KSecretUnlockCollectionJob
+ */
+ bool tryUnlock();
+
+ /**
* Set-up the encryption to be used by the secret collection.
* This creates hash and cipher functors as configured.
*
@@ -483,8 +477,8 @@ private:
QString m_path; // path of the ksecret file on disk
// verifier
- QByteArray m_verInitVector; // initialization vector of the verifier
- QByteArray m_verEncryptedRandom; // encrypted random data of the verifier
+ QCA::InitializationVector m_verInitVector; // initialization vector of the verifier
+ QCA::SecureArray m_verEncryptedRandom; // encrypted random data of the verifier
// configuration values
bool m_cfgCloseScreensaver; // close when the screensaver starts
diff --git a/backend/ksecret/ksecretjobs.cpp b/backend/ksecret/ksecretjobs.cpp
index 7f365aa..d79cdd7 100644
--- a/backend/ksecret/ksecretjobs.cpp
+++ b/backend/ksecret/ksecretjobs.cpp
@@ -27,6 +27,8 @@
#include <QtCore/QTimer>
#include <klocalizedstring.h>
+#include <QtCore/QDebug>
+
KSecretCreateCollectionJob::KSecretCreateCollectionJob(const QString &label, bool locked,
KSecretCollectionManager *manager)
: CreateCollectionJob(label, locked, manager), m_manager(manager)
@@ -62,7 +64,7 @@ void KSecretCreateCollectionJob::newPasswordJobResult(QueuedJob *job)
if (npj->cancelled()) {
setCollection(0);
- setError(ErrorOther, i18n("Creating the collection was cancelled by the uesr."));
+ setError(ErrorOther, i18n("Creating the collection was cancelled by the user."));
emitResult();
return;
}
@@ -93,7 +95,7 @@ void KSecretCreateCollectionJob::newPasswordJobResult(QueuedJob *job)
}
KSecretUnlockCollectionJob::KSecretUnlockCollectionJob(KSecretCollection *coll)
- : UnlockCollectionJob(coll), m_collection(coll)
+ : UnlockCollectionJob(coll), m_collection(coll), m_firstTry(true)
{
}
@@ -116,49 +118,47 @@ void KSecretUnlockCollectionJob::exec()
void KSecretUnlockCollectionJob::start()
{
- QTimer::singleShot(0, this, SLOT(doWork()));
-}
-
-void KSecretUnlockCollectionJob::doWork()
-{
if (!collection()->isLocked()) {
setResult(true);
emitResult();
return;
}
- // TODO: make it actually unlock, needs UI
-
- // TODO: check authenticated parts
-
- // TODO: check if the key is actually correct
+ // start a job for getting a new password for the collection from the user.
+ AbstractUiManager *uiManager = BackendMaster::instance()->uiManager();
+ AbstractAskPasswordJob *subJob = uiManager->createAskPasswordJob(m_collection->label().value(),
+ !m_firstTry);
+ connect(subJob, SIGNAL(result(QueuedJob*)), SLOT(askPasswordJobResult(QueuedJob*)));
+ m_firstTry = false;
- // FIXME: this is bogus
+ // if this is not the first try, enqueue in front so the dialog gets shown again
+ // right away.
+ subJob->enqueue(!m_firstTry);
+}
+
+void KSecretUnlockCollectionJob::askPasswordJobResult(QueuedJob *job)
+{
+ AbstractAskPasswordJob *apj = qobject_cast<AbstractAskPasswordJob*>(job);
+ Q_ASSERT(apj);
- // create a key to unlock the actual symmetric key
- QCA::SymmetricKey *symkey = new QCA::SymmetricKey;
- QCA::SymmetricKey *keyUnlockKey = new QCA::SymmetricKey(QByteArray("12345678901234567890"));
- Q_FOREACH(EncryptedKey *key, m_collection->encryptedSymKeys()) {
- if (key->m_type == KSecretFile::KeyBogus) {
- QCA::Cipher keyCipher("blowfish", QCA::Cipher::CBC);
- keyCipher.setup(QCA::Decode, *keyUnlockKey);
- *symkey += QCA::SecureArray(keyCipher.update(key->m_key));
- *symkey += QCA::SecureArray(keyCipher.final());
- break;
- }
+ if (apj->cancelled()) {
+ setResult(false);
+ setError(ErrorOther, i18n("Unlocking the collection was cancelled by the user."));
+ emitResult();
+ return;
}
- Q_ASSERT(symkey);
- m_collection->setSymKey(symkey);
- // clear symmetric key if unlocking failed
- if (m_collection->tryUnlock()) {
- setResult(true);
- } else {
- m_collection->setSymKey(0);
- delete symkey;
+ BackendReturn<bool> rc = m_collection->tryUnlockPassword(apj->password());
+ if (rc.isError()) {
setResult(false);
+ setError(rc.error(), rc.errorMessage());
+ emitResult();
+ } else if (!rc.value()) {
+ start();
+ } else {
+ setResult(true);
+ emitResult();
}
- emitResult();
}
KSecretLockCollectionJob::KSecretLockCollectionJob(KSecretCollection *coll)
diff --git a/backend/ksecret/ksecretjobs.h b/backend/ksecret/ksecretjobs.h
index cf5cad6..c7eeaf6 100644
--- a/backend/ksecret/ksecretjobs.h
+++ b/backend/ksecret/ksecretjobs.h
@@ -69,10 +69,11 @@ protected:
virtual void start();
private Q_SLOTS:
- void doWork();
+ void askPasswordJobResult(QueuedJob *job);
private:
KSecretCollection *m_collection;
+ bool m_firstTry;
};
/**
diff --git a/backend/tests/ksecrettest.cpp b/backend/tests/ksecrettest.cpp
index d79b6d2..13d9090 100644
--- a/backend/tests/ksecrettest.cpp
+++ b/backend/tests/ksecrettest.cpp
@@ -107,6 +107,31 @@ void KSecretTest::testLockCollectionAsync()
void KSecretTest::testUnlockCollectionAsync()
{
+ UnlockCollectionJob *unlockColl = m_collection->createUnlockJob();
+ BackendMaster *master = BackendMaster::instance();
+ QSignalSpy masterSpy(master, SIGNAL(collectionChanged(BackendCollection*)));
+ QSignalSpy managerSpy(m_manager, SIGNAL(collectionChanged(BackendCollection*)));
+ QSignalSpy collSpy(m_collection, SIGNAL(collectionChanged(BackendCollection*)));
+ QTestEventLoop loop;
+ QVERIFY(loop.connect(unlockColl, SIGNAL(result(QueuedJob*)), SLOT(exitLoop())));
+ unlockColl->enqueue();
+ if (!unlockColl->isFinished()) {
+ loop.enterLoop(5);
+ }
+
+ QVERIFY(unlockColl->isFinished());
+ QCOMPARE(unlockColl->error(), NoError);
+ QVERIFY(!unlockColl->isDismissed());
+ QVERIFY(unlockColl->result());
+ QVERIFY(!m_collection->isLocked());
+
+ // Verify signals
+ QCOMPARE(managerSpy.count(), 1);
+ QCOMPARE(managerSpy.takeFirst().at(0).value<BackendCollection*>(), m_collection);
+ QCOMPARE(masterSpy.count(), 1);
+ QCOMPARE(masterSpy.takeFirst().at(0).value<BackendCollection*>(), m_collection);
+ QCOMPARE(collSpy.count(), 1);
+ QCOMPARE(collSpy.takeFirst().at(0).value<BackendCollection*>(), m_collection);
}
void KSecretTest::testCreateItemAsync()
diff --git a/backend/tests/ksecrettest.h b/backend/tests/ksecrettest.h
index 0ea2a63..da9d064 100644
--- a/backend/tests/ksecrettest.h
+++ b/backend/tests/ksecrettest.h
@@ -47,6 +47,9 @@ private Q_SLOTS:
private:
BackendCollectionManager *m_manager;
BackendCollection *m_collection;
+
+ QDateTime m_collCreated;
+ QDateTime m_collModified;
};
#endif
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic