[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