diff --git a/src/cpp/controller/User.cpp b/src/cpp/controller/User.cpp index 2579b5472..209237877 100644 --- a/src/cpp/controller/User.cpp +++ b/src/cpp/controller/User.cpp @@ -4,6 +4,7 @@ #include "../SingletonManager/SessionManager.h" #include "../SingletonManager/ErrorManager.h" +#include "../SingletonManager/SingletonTaskObserver.h" #include "../lib/DataTypeConverter.h" @@ -15,7 +16,7 @@ namespace controller { User::User(model::table::User* dbModel) - : mPassword(nullptr), mGradidoKeyPair(nullptr) + : mPassword(nullptr), mGradidoKeyPair(nullptr), mCanDecryptPrivateKey(false) { mDBModel = dbModel; } @@ -130,15 +131,23 @@ namespace controller { if (!mPassword.isNull() && mPassword->hasKey()) { return 2; } + auto observer = SingletonTaskObserver::getInstance(); std::unique_lock _lock(mSharedMutex); assert(mPassword.isNull()); - Poco::AutoPtr authenticated_encryption(new AuthenticatedEncryption); auto model = getModel(); + auto email_hash = observer->makeHash(model->getEmail()); + if (observer->getTaskCount(email_hash, TASK_OBSERVER_PASSWORD_CREATION) > 0) { + return -3; + } + observer->addTask(email_hash, TASK_OBSERVER_PASSWORD_CREATION); + Poco::AutoPtr authenticated_encryption(new AuthenticatedEncryption); assert(!authenticated_encryption.isNull() && model); - authenticated_encryption->createKey(model->getEmail(), password); + + observer->removeTask(email_hash, TASK_OBSERVER_PASSWORD_CREATION); + if (authenticated_encryption->getKeyHashed() == model->getPasswordHashed()) { // printf("[User::login] password key hashed is the same as saved password hash\n"); @@ -155,6 +164,7 @@ namespace controller { if (mGradidoKeyPair) { if (mGradidoKeyPair->isTheSame(clear_private_key) == 0) { mPassword = authenticated_encryption; + mCanDecryptPrivateKey = true; return 1; } else { @@ -171,6 +181,7 @@ namespace controller { } //printf("correct pwd\n"); mPassword = authenticated_encryption; + mCanDecryptPrivateKey = true; return 1; } else { @@ -193,16 +204,30 @@ namespace controller { std::unique_lock _lock(mSharedMutex); if (mGradidoKeyPair) delete mGradidoKeyPair; mGradidoKeyPair = gradidoKeyPair; - getModel()->setPublicKey(mGradidoKeyPair->getPublicKey()); + auto model = getModel(); + model->setPublicKey(mGradidoKeyPair->getPublicKey()); if (mPassword && mPassword->hasKey()) { - auto model = getModel(); model->setPrivateKey(mGradidoKeyPair->getCryptedPrivKey(mPassword)); return 1; } return 0; } + int User::setNewPassword(const std::string& password) + { + auto observer = SingletonTaskObserver::getInstance(); + auto model = getModel(); + auto email_hash = observer->makeHash(model->getEmail()); - int User::setPassword(Poco::AutoPtr passwd) + observer->addTask(email_hash, TASK_OBSERVER_PASSWORD_CREATION); + Poco::AutoPtr authenticated_encryption(new AuthenticatedEncryption); + assert(!authenticated_encryption.isNull() && model); + authenticated_encryption->createKey(model->getEmail(), password); + + observer->removeTask(email_hash, TASK_OBSERVER_PASSWORD_CREATION); + return setNewPassword(authenticated_encryption); + } + + int User::setNewPassword(Poco::AutoPtr passwd) { std::unique_lock _lock(mSharedMutex); auto model = getModel(); @@ -232,6 +257,7 @@ namespace controller { if (*mGradidoKeyPair != model->getPublicKey()) { delete mGradidoKeyPair; mGradidoKeyPair = nullptr; + mCanDecryptPrivateKey = false; return -1; } } @@ -249,6 +275,7 @@ namespace controller { MemoryManager::getInstance()->releaseMemory(encryptedPrivateKey); result = model->updatePrivkeyAndPasswordHash(); + mCanDecryptPrivateKey = true; } else { model->updateIntoDB("password", mPassword->getKeyHashed()); diff --git a/src/cpp/controller/User.h b/src/cpp/controller/User.h index 280ca0e7e..2dd247dab 100644 --- a/src/cpp/controller/User.h +++ b/src/cpp/controller/User.h @@ -50,12 +50,13 @@ namespace controller { std::string getEmailWithNames(); const std::string& getPublicHex(); - //! \brief check if password match saved password, long duration + //! \brief check if password match saved password, long duration, load Key pair //! \return 1 logged in //! \return 2 already logged in //! \return 0 password didn't match //! \return -1 error saved public key didn't match with private key //! \return -2 error decrypting private key + //! \return -3 password key creation already running //! - create authenticated encryption key from password and email //! - compare hash with in db saved hash @@ -69,7 +70,16 @@ namespace controller { //! \return 1 = password changed, private key re-encrypted and saved into db //! \return 2 = password changed, only hash stored in db, couldn't load private key for re-encryption //! \return -1 = stored pubkey and private key didn't match - int setPassword(Poco::AutoPtr passwd); + int setNewPassword(Poco::AutoPtr passwd); + + + //! \brief set authenticated encryption and save hash in db, also re encrypt private key if exist + //! \param password as string + //! \return 0 = new and current passwords are the same + //! \return 1 = password changed, private key re-encrypted and saved into db + //! \return 2 = password changed, only hash stored in db, couldn't load private key for re-encryption + //! \return -1 = stored pubkey and private key didn't match + int setNewPassword(const std::string& password); //! \brief return AuthenticatedEncryption Auto Pointer inline const Poco::AutoPtr getPassword() { @@ -80,10 +90,14 @@ namespace controller { std::shared_lock _lock(mSharedMutex); return !mPassword.isNull(); } + inline bool canDecryptPrivateKey() { + std::shared_lock _lock(mSharedMutex); + return mCanDecryptPrivateKey; + } inline bool hasPublicKey() { return getModel()->getPublicKey(); } - //! \brief set key pair, public in model, private if password exist else with next setPassword call into model + //! \brief set key pair, public in model, private if password exist else with next setPassword call into model, overwrite existing key pair, not saving into db //! \param gradidoKeyPair take owner ship //! \param return 0 if public key set //! \param return 1 if also private key set (and password exist) @@ -104,6 +118,8 @@ namespace controller { Poco::AutoPtr mPassword; KeyPairEd25519* mGradidoKeyPair; + bool mCanDecryptPrivateKey; + mutable std::shared_mutex mSharedMutex; }; } diff --git a/src/cpp/controller/UserBackups.cpp b/src/cpp/controller/UserBackups.cpp index 9d683f758..bf7096442 100644 --- a/src/cpp/controller/UserBackups.cpp +++ b/src/cpp/controller/UserBackups.cpp @@ -1,5 +1,7 @@ #include "UserBackups.h" +#include "../Crypto/Passphrase.h" + namespace controller { UserBackups::UserBackups(model::table::UserBackups* dbModel) { @@ -61,7 +63,12 @@ namespace controller { KeyPairEd25519* UserBackups::createGradidoKeyPair() { - + auto model = getModel(); + auto mnemonicType = model->getMnemonicType(); + assert(mnemonicType >= 0 && mnemonicType < ServerConfig::MNEMONIC_MAX); + auto wordSource = &ServerConfig::g_Mnemonic_WordLists[mnemonicType]; + Poco::AutoPtr passphrase = new Passphrase(model->getPassphrase(), wordSource); + return KeyPairEd25519::create(passphrase); } std::string UserBackups::getPassphrase(ServerConfig::Mnemonic_Types type) diff --git a/src/cpp/model/Session.cpp b/src/cpp/model/Session.cpp index 1fbe1f04c..4de342bdb 100644 --- a/src/cpp/model/Session.cpp +++ b/src/cpp/model/Session.cpp @@ -665,7 +665,7 @@ void Session::finalizeTransaction(bool sign, bool reject) if (!reject) { if (sign) { - Poco::AutoPtr signingTransaction(new SigningTransaction(mCurrentActiveProcessingTransaction, mSessionUser)); + Poco::AutoPtr signingTransaction(new SigningTransaction(mCurrentActiveProcessingTransaction, mNewUser)); signingTransaction->scheduleTask(signingTransaction); } } @@ -745,7 +745,27 @@ UserStates Session::loadUser(const std::string& email, const std::string& passwo } // error decrypting private key if (-2 == loginResult) { - + // check if we have access to the passphrase, if so we can reencrypt the private key + auto user_model = mNewUser->getModel(); + auto user_backups = controller::UserBackups::load(user_model->getID()); + for (auto it = user_backups.begin(); it != user_backups.end(); it++) { + auto key = (*it)->createGradidoKeyPair(); + if (key->isTheSame(user_model->getPublicKey())) { + auto crypted_private_key = key->getCryptedPrivKey(mNewUser->getPassword()); + if (crypted_private_key) { + user_model->setPrivateKey(crypted_private_key); + MemoryManager::getInstance()->releaseMemory(crypted_private_key); + } + else { + auto em = ErrorManager::getInstance(); + em->addError(new Error(functionName, "error reencrypt private key")); + em->addError(new ParamError(functionName, "for user with email", user_model->getEmail())); + em->sendErrorsAsEmail(); + } + break; + } + delete key; + } } // can be removed if session user isn't used any more if (mNewUser->getModel()->getPasswordHashed() && !mSessionUser->validatePwd(password, this)) { @@ -1103,7 +1123,7 @@ bool Session::generateKeys(bool savePrivkey, bool savePassphrase) } if (savePassphrase) { - auto user_backup = controller::UserBackups::create(user_model->getID(), passphrase->getString()); + auto user_backup = controller::UserBackups::create(user_model->getID(), passphrase->getString(), mnemonic_type); // sync version //user_backup->getModel()->insertIntoDB(false); diff --git a/src/cpp/model/Session.h b/src/cpp/model/Session.h index fc7f0e83a..67a7deb83 100644 --- a/src/cpp/model/Session.h +++ b/src/cpp/model/Session.h @@ -125,9 +125,12 @@ public: // ------------------------ Passphrase functions ---------------------------- + inline void setPassphrase(Poco::AutoPtr passphrase) { mNewPassphrase = passphrase; } + inline Poco::AutoPtr getPassphrase() { return mNewPassphrase; } + inline void setPassphrase(const std::string& passphrase) { mPassphrase = passphrase; } - inline const std::string& getPassphrase() { return mPassphrase; } + inline const std::string& getOldPassphrase() { return mPassphrase; } bool generatePassphrase(); bool generateKeys(bool savePrivkey, bool savePassphrase); @@ -187,6 +190,7 @@ private: Poco::AutoPtr mSessionUser; Poco::AutoPtr mNewUser; std::string mPassphrase; + Poco::AutoPtr mNewPassphrase; Poco::DateTime mLastActivity; Poco::Net::IPAddress mClientLoginIP; std::string mLastExternReferer;