From 405ecefbf81e144a29d2a96ded19025b52959ffe Mon Sep 17 00:00:00 2001 From: csoler Date: Fri, 19 Feb 2016 20:47:50 -0500 Subject: [PATCH] added proper decryption calls for partial decryption and possible re-try after loading keys. --- libretroshare/src/gxs/rsgxsnetservice.cc | 145 ++++++++++++++--------- libretroshare/src/gxs/rsgxsnetservice.h | 2 +- 2 files changed, 90 insertions(+), 57 deletions(-) diff --git a/libretroshare/src/gxs/rsgxsnetservice.cc b/libretroshare/src/gxs/rsgxsnetservice.cc index 6b6658880..6db351725 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.cc +++ b/libretroshare/src/gxs/rsgxsnetservice.cc @@ -306,7 +306,10 @@ RsGxsNetService::RsGxsNetService(uint16_t servType, RsGeneralDataService *gds, RsGixsReputation* reputations, RsGcxs* circles, RsGixs *gixs, PgpAuxUtils *pgpUtils, bool grpAutoSync,bool msgAutoSync) : p3ThreadedService(), p3Config(), mTransactionN(0), - mObserver(nxsObs),mGixs(gixs), mDataStore(gds), mServType(servType), + mObserver(nxsObs), + mDataStore(gds), + mServType(servType), + mGixs(gixs), mTransactionTimeOut(TRANSAC_TIMEOUT), mNetMgr(netMgr), mNxsMutex("RsGxsNetService"), mSyncTs(0), mLastKeyPublishTs(0),mLastCleanRejectedMessages(0), mSYNC_PERIOD(SYNC_PERIOD), mCircles(circles), mReputations(reputations), mPgpUtils(pgpUtils), @@ -2144,25 +2147,28 @@ void RsGxsNetService::processTransactions() // Try to decrypt the items that need to be decrypted. This function returns true if the transaction is not encrypted. if(decryptTransaction(tr)) - { + { #ifdef NXS_NET_DEBUG_7 - GXSNETDEBUG_P_(tr->mTransaction->PeerId()) << " successfully decrypted transaction " << transN << std::endl; + GXSNETDEBUG_P_(tr->mTransaction->PeerId()) << " successfully decrypted/processed transaction " << transN << ". Adding to completed list." << std::endl; #endif mComplTransactions.push_back(tr); - } -#ifdef NXS_NET_DEBUG_7 - else - GXSNETDEBUG_P_(tr->mTransaction->PeerId()) << " no decryption occurred in transaction " << transN << std::endl; -#endif - -#ifdef NXS_NET_DEBUG_1 - int total_transaction_time = (int)time(NULL) - (tr->mTimeOut - mTransactionTimeOut) ; - GXSNETDEBUG_P_(mit->first) << " incoming completed " << tr->mTransaction->nItems << " items transaction in " << total_transaction_time << " seconds." << std::endl; -#endif - // transaction processing done - // for this id, add to removal list - toRemove.push_back(mmit->first); + // transaction processing done + // for this id, add to removal list + toRemove.push_back(mmit->first); +#ifdef NXS_NET_DEBUG_1 + int total_transaction_time = (int)time(NULL) - (tr->mTimeOut - mTransactionTimeOut) ; + GXSNETDEBUG_P_(mit->first) << " incoming completed " << tr->mTransaction->nItems << " items transaction in " << total_transaction_time << " seconds." << std::endl; +#endif + } + else + { +#ifdef NXS_NET_DEBUG_7 + GXSNETDEBUG_P_(tr->mTransaction->PeerId()) << " no decryption occurred because of unloaded keys. Will retry later. TransN=" << transN << std::endl; +#endif + } + + } else if(flag & NxsTransaction::FLAG_STATE_STARTING) { @@ -3598,6 +3604,10 @@ bool RsGxsNetService::encryptTransaction(NxsTransaction *tr) return true ; } +// Tries to decrypt the transaction. First load the keys and process all items. +// If keys are loaded, encrypted items that cannot be decrypted are discarded. +// Otherwise the transaction is untouched for retry later. + bool RsGxsNetService::decryptTransaction(NxsTransaction *tr) { #ifdef NXS_NET_DEBUG_7 @@ -3709,70 +3719,93 @@ bool RsGxsNetService::decryptTransaction(NxsTransaction *tr) // get all private keys. Normally we should look into the circle name and only supply the keys that we have - std::list own_keys ; - - mGixs->getOwnIds(own_keys) ; - - for(std::list::const_iterator it(own_keys.begin());it!=own_keys.end();++it) - { - RsTlvSecurityKey private_key ; - - if(mGixs->getPrivateKey(*it,private_key)) - { - std::cerr << "(EE) Cannot retrieve private key for ID " << *it << std::endl; - return false ; - } - private_keys.push_back(private_key) ; - std::cerr << " retrived private key " << *it << std::endl; - } - - for(std::list::iterator it(tr->mItems.begin());it!=tr->mItems.end();++it) + for(std::list::iterator it(tr->mItems.begin());it!=tr->mItems.end();) { RsNxsEncryptedDataItem *encrypted_item = dynamic_cast(*it) ; if(encrypted_item == NULL) { std::cerr << " skipping unencrypted item..." << std::endl; + ++it ; continue ; } + + // we need the private keys to decrypt the item. First load them in! + bool key_loading_failed = false ; + + if(private_keys.empty()) + { + std::cerr << " need to retrieve private keys..." << std::endl; + + std::list own_keys ; + mGixs->getOwnIds(own_keys) ; + + for(std::list::const_iterator it(own_keys.begin());it!=own_keys.end();++it) + { + RsTlvSecurityKey private_key ; + + if(mGixs->getPrivateKey(*it,private_key)) + { + private_keys.push_back(private_key) ; + std::cerr << " retrieved private key " << *it << std::endl; + } + else + { + std::cerr << " (EE) Cannot retrieve private key for ID " << *it << std::endl; + key_loading_failed = true ; + break ; + } + } + } + if(key_loading_failed) + { + std::cerr << " Some keys not loaded.Returning false to retry later." << std::endl; + return false ; + } // we do this only when something actually needs to be decrypted. unsigned char *decrypted_mem = NULL; uint32_t decrypted_len =0; - std::cerr << " Trying to decrypt item..." ; + std::cerr << " Trying to decrypt item..." ; if(!GxsSecurity::decrypt(decrypted_mem,decrypted_len, (uint8_t*)encrypted_item->aes_encrypted_data.bin_data,encrypted_item->aes_encrypted_data.bin_len,private_keys)) { - std::cerr << "Failed! Cannot decrypt transaction. Giving up." << std::endl; - return false ; + std::cerr << "Failed! Cannot decrypt this item." << std::endl; + decrypted_mem = NULL ; // for safety } - std::cerr << "Succeeded! deserialising..." << std::endl; + std::cerr << " Succeeded! deserialising..." << std::endl; // deserialise the item - RsItem *ditem = RsNxsSerialiser(mServType).deserialise(decrypted_mem,&decrypted_len) ; + + RsItem *ditem = NULL ; + RsNxsItem *nxsitem = NULL ; - if(ditem == NULL) - { - std::cerr << " Cannot deserialise. Item encoding error!" << std::endl; - return false ; - } - RsNxsItem *nxsitem = dynamic_cast(ditem) ; - - if(nxsitem == NULL) - { - std::cerr << " Deserialised item is not an NxsItem. Weird. Dropping transaction." << std::endl; - return false ; - } - - // replace the encrypted item with the clear one - std::cerr << " Replacing the encrypted item with the clear one." << std::endl; + if(decrypted_mem!=NULL) + { + ditem = RsNxsSerialiser(mServType).deserialise(decrypted_mem,&decrypted_len) ; + + if(ditem == NULL) + std::cerr << " Cannot deserialise. Item encoding error!" << std::endl; + + nxsitem = dynamic_cast(ditem) ; + + if(nxsitem == NULL) + std::cerr << " (EE) Deserialised item is not an NxsItem. Weird. Dropping transaction." << std::endl; + } + // remove the encrypted item. After that it points to the next item to handle it = tr->mItems.erase(it) ; - tr->mItems.insert(it,nxsitem) ; - --it ; // this is to make sure the ++it in the for loop is not goign to skip the item just after the one being inserted + + if(nxsitem != NULL) + { + std::cerr << " Replacing the encrypted item with the clear one." << std::endl; + tr->mItems.insert(it,nxsitem) ; // inserts before it, so no need to ++it + } + + delete encrypted_item ; } #endif diff --git a/libretroshare/src/gxs/rsgxsnetservice.h b/libretroshare/src/gxs/rsgxsnetservice.h index 80fbfadbb..d2b8733d3 100644 --- a/libretroshare/src/gxs/rsgxsnetservice.h +++ b/libretroshare/src/gxs/rsgxsnetservice.h @@ -455,7 +455,7 @@ private: * encrypts/decrypts the transaction for the destination circle id. */ bool encryptTransaction(NxsTransaction *tr); - bool decryptTransaction(NxsTransaction *tr); + bool decryptTransaction(NxsTransaction *tr); // return false when the keys are not loaded => need retry later void cleanRejectedMessages(); void processObserverNotifications();