diff --git a/src/cpp/Crypto/AuthenticatedEncryption.cpp b/src/cpp/Crypto/AuthenticatedEncryption.cpp index 6bfd74ddb..0a1625991 100644 --- a/src/cpp/Crypto/AuthenticatedEncryption.cpp +++ b/src/cpp/Crypto/AuthenticatedEncryption.cpp @@ -128,6 +128,34 @@ AuthenticatedEncryption::ResultType AuthenticatedEncryption::decrypt(const Memor return AUTH_DECRYPT_OK; } +AuthenticatedEncryption::ResultType AuthenticatedEncryption::decrypt(const std::vector& encryptedMessage, MemoryBin** message) const +{ + assert(message); + std::shared_lock _lock(mWorkingMutex); + + if (!mEncryptionKey) { + return AUTH_NO_KEY; + } + + size_t decryptSize = encryptedMessage.size() - crypto_secretbox_MACBYTES; + //unsigned char* decryptBuffer = (unsigned char*)malloc(decryptSize); + auto mm = MemoryManager::getInstance(); + //ObfusArray* decryptedData = new ObfusArray(decryptSize); + auto decryptedData = mm->getFreeMemory(decryptSize); + unsigned char nonce[crypto_secretbox_NONCEBYTES]; + // we use a hardcoded value for nonce + // TODO: use a dynamic value, save it along with the other parameters + memset(nonce, 31, crypto_secretbox_NONCEBYTES); + + if (crypto_secretbox_open_easy(*decryptedData, encryptedMessage.data(), encryptedMessage.size(), nonce, *mEncryptionKey)) { + mm->releaseMemory(decryptedData); + return AUTH_DECRYPT_MESSAGE_FAILED; + } + *message = decryptedData; + + return AUTH_DECRYPT_OK; +} + const char* AuthenticatedEncryption::getErrorMessage(ResultType type) { switch (type) { diff --git a/src/cpp/Crypto/AuthenticatedEncryption.h b/src/cpp/Crypto/AuthenticatedEncryption.h index 10eca34ec..735ed589d 100644 --- a/src/cpp/Crypto/AuthenticatedEncryption.h +++ b/src/cpp/Crypto/AuthenticatedEncryption.h @@ -5,6 +5,7 @@ #include "../SingletonManager/MemoryManager.h" #include +#include /*! * @@ -59,6 +60,11 @@ public: ResultType encrypt(const MemoryBin* message, MemoryBin** encryptedMessage) const; ResultType decrypt(const MemoryBin* encryptedMessage, MemoryBin** message) const; + //! \brief same as the other decrypt only in other format + //! \param encryptedMessage format from Poco Binary Data from DB, like returned from model/table/user for encrypted private key + //! + //! double code, I don't know how to prevent without unnecessary copy of encryptedMessage + ResultType decrypt(const std::vector& encryptedMessage, MemoryBin** message) const; static const char* getErrorMessage(ResultType type); diff --git a/src/cpp/Crypto/KeyPairEd25519.cpp b/src/cpp/Crypto/KeyPairEd25519.cpp index daf413c08..bb2235291 100644 --- a/src/cpp/Crypto/KeyPairEd25519.cpp +++ b/src/cpp/Crypto/KeyPairEd25519.cpp @@ -8,10 +8,12 @@ #include "Passphrase.h" -KeyPairEd25519::KeyPairEd25519(MemoryBin* privateKey, const unsigned char* publicKey) +KeyPairEd25519::KeyPairEd25519(MemoryBin* privateKey) : mSodiumSecret(privateKey) { - memcpy(mSodiumPublic, publicKey, crypto_sign_PUBLICKEYBYTES); + //memcpy(mSodiumPublic, publicKey, crypto_sign_PUBLICKEYBYTES); + // read pubkey from private key, so we are sure it is the correct pubkey for the private key + crypto_sign_ed25519_sk_to_pk(*privateKey, mSodiumPublic); } KeyPairEd25519::KeyPairEd25519(const unsigned char* publicKey) diff --git a/src/cpp/Crypto/KeyPairEd25519.h b/src/cpp/Crypto/KeyPairEd25519.h index 9b89d14db..839b1cfc0 100644 --- a/src/cpp/Crypto/KeyPairEd25519.h +++ b/src/cpp/Crypto/KeyPairEd25519.h @@ -21,7 +21,7 @@ class KeyPairEd25519 : public IKeyPair public: //! \param privateKey: take ownership, release after object destruction //! \param publicKey: copy - KeyPairEd25519(MemoryBin* privateKey, const unsigned char* publicKey); + KeyPairEd25519(MemoryBin* privateKey); KeyPairEd25519(const unsigned char* publicKey); ~KeyPairEd25519(); @@ -38,10 +38,16 @@ public: inline bool isTheSame(const KeyPairEd25519& b) const { return 0 == sodium_memcmp(mSodiumPublic, b.mSodiumPublic, crypto_sign_PUBLICKEYBYTES); } + inline bool isTheSame(const unsigned char* pubkey) const { + return 0 == sodium_memcmp(mSodiumPublic, pubkey, crypto_sign_PUBLICKEYBYTES); + } inline bool operator == (const KeyPairEd25519& b) const { return isTheSame(b); } inline bool operator != (const KeyPairEd25519& b) const { return !isTheSame(b); } + inline bool operator == (const unsigned char* b) const { return isTheSame(b); } + inline bool operator != (const unsigned char* b) const { return !isTheSame(b); } + inline bool hasPrivateKey() const { return mSodiumSecret != nullptr; } //! \brief only way to get a private key.. encrypted diff --git a/src/cpp/HTTPInterface/AdminUserPasswordReset.cpp b/src/cpp/HTTPInterface/AdminUserPasswordReset.cpp index 4ab46bf67..fe41d3143 100644 --- a/src/cpp/HTTPInterface/AdminUserPasswordReset.cpp +++ b/src/cpp/HTTPInterface/AdminUserPasswordReset.cpp @@ -207,7 +207,7 @@ void AdminUserPasswordReset::handleRequest(Poco::Net::HTTPServerRequest& request responseStream << "\n"; responseStream << "\t\t\t
  • Private Key verschlüsselt: "; #line 92 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminUserPasswordReset.cpsp" - responseStream << ( std::to_string(userModel->existPrivateKeyCrypted()) ); + responseStream << ( std::to_string(userModel->hasPrivateKeyEncrypted()) ); responseStream << "
  • \n"; responseStream << "\t\t\t
  • Passwort gesetzt: "; #line 93 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminUserPasswordReset.cpsp" diff --git a/src/cpp/controller/User.cpp b/src/cpp/controller/User.cpp index ddcbc9477..59e2d57dd 100644 --- a/src/cpp/controller/User.cpp +++ b/src/cpp/controller/User.cpp @@ -3,10 +3,12 @@ #include "sodium.h" #include "../SingletonManager/SessionManager.h" +#include "../lib/DataTypeConverter.h" + namespace controller { User::User(model::table::User* dbModel) - : mPassword(nullptr) + : mPassword(nullptr), mGradidoKeyPair(nullptr) { mDBModel = dbModel; } @@ -15,6 +17,11 @@ namespace controller { { if (mPassword) { delete mPassword; + mPassword = nullptr; + } + if (mGradidoKeyPair) { + delete mGradidoKeyPair; + mGradidoKeyPair = nullptr; } } @@ -115,4 +122,45 @@ namespace controller { return json; } + int User::setPassword(AuthenticatedEncryption* passwd) + { + std::unique_lock _lock(mSharedMutex); + auto model = getModel(); + const static char* function_name = "controller::User::setPassword"; + + if (mPassword) + { + if (mPassword == passwd) return 0; + // if password exist but gradido key pair not, try to load key pair + if ((!mGradidoKeyPair || !mGradidoKeyPair->hasPrivateKey()) && model->hasPrivateKeyEncrypted()) { + //if (!mGradidoKeyPair) mGradidoKeyPair = new KeyPairEd25519; + MemoryBin* clear_private_key = nullptr; + if (AuthenticatedEncryption::AUTH_DECRYPT_OK == mPassword->decrypt(model->getPrivateKeyEncrypted(), &clear_private_key)) { + if (mGradidoKeyPair) delete mGradidoKeyPair; + mGradidoKeyPair = new KeyPairEd25519(clear_private_key); + + // check if saved pubkey and from private key extracted pubkey match + if (*mGradidoKeyPair != model->getPublicKey()) { + delete mGradidoKeyPair; + mGradidoKeyPair = nullptr; + return -1; + } + } + } + + delete passwd; + } + // replace old password with new + mPassword = passwd; + + // set new encrypted password and hash + model->setPasswordHashed(mPassword->getKeyHashed()); + auto encryptedPrivateKey = mGradidoKeyPair->getCryptedPrivKey(mPassword); + model->setPrivateKey(encryptedPrivateKey); + MemoryManager::getInstance()->releaseMemory(encryptedPrivateKey); + + // save changes to db + return model->updatePrivkeyAndPasswordHash(); + } + } \ No newline at end of file diff --git a/src/cpp/controller/User.h b/src/cpp/controller/User.h index 929329157..06a62ca14 100644 --- a/src/cpp/controller/User.h +++ b/src/cpp/controller/User.h @@ -2,7 +2,8 @@ #define GRADIDO_LOGIN_SERVER_CONTROLLER_USER_INCLUDE #include "../model/table/User.h" -#include "../Crypto/AuthenticatedEncryption.h" +//#include "../Crypto/AuthenticatedEncryption.h" +#include "../Crypto/KeyPairEd25519.h" #include @@ -42,13 +43,12 @@ namespace controller { // *********************************************************************************** // password related - //! \brief + //! \brief set authenticated encryption and save hash in db, should also re encrypt private key if exist //! \param passwd take owner ship - inline void setPassword(AuthenticatedEncryption* passwd) { - std::unique_lock _lock(mSharedMutex); - if (mPassword) delete passwd; - mPassword = passwd; - } + //! \return 0 = new and current passwords are the same + //! \return 1 = password changed, private key re-encrypted and saved into db + //! \return -1 = stored pubkey and private key didn't match + int setPassword(AuthenticatedEncryption* passwd); inline const AuthenticatedEncryption* getPassword() { std::shared_lock _lock(mSharedMutex); @@ -60,6 +60,7 @@ namespace controller { std::string mPublicHex; AuthenticatedEncryption* mPassword; + KeyPairEd25519* mGradidoKeyPair; mutable std::shared_mutex mSharedMutex; }; diff --git a/src/cpp/model/User.cpp b/src/cpp/model/User.cpp index a36ba62b4..fdba4b0b3 100644 --- a/src/cpp/model/User.cpp +++ b/src/cpp/model/User.cpp @@ -426,8 +426,8 @@ User::User(Poco::AutoPtr ctrl_user) mPublicHex = std::string((char*)(*hexStringTemp)); mm->releaseMemory(hexStringTemp); } - if (model->existPrivateKeyCrypted()) { - auto privKeyVetor = model->getPrivateKeyCrypted(); + if (model->hasPrivateKeyEncrypted()) { + auto privKeyVetor = model->getPrivateKeyEncrypted(); mPrivateKey = mm->getFreeMemory(privKeyVetor.size()); memcpy(*mPrivateKey, privKeyVetor.data(), privKeyVetor.size()); } diff --git a/src/cpp/model/table/User.cpp b/src/cpp/model/table/User.cpp index ddc4b6c8c..a407c4cf7 100644 --- a/src/cpp/model/table/User.cpp +++ b/src/cpp/model/table/User.cpp @@ -143,7 +143,10 @@ namespace model { size_t User::updatePrivkey() { lock(); - if (mPrivateKey.isNull()) return 0; + if (mPrivateKey.isNull()) { + unlock(); + return 0; + } auto result = updateIntoDB("privkey", mPrivateKey.value()); unlock(); return result; @@ -151,12 +154,45 @@ namespace model { size_t User::updatePublickey() { lock(); - if (mPublicKey.isNull()) return 0; + if (mPublicKey.isNull()) { + unlock(); + return 0; + } auto result = updateIntoDB("pubkey", mPublicKey.value()); unlock(); return result; } + size_t User::updatePrivkeyAndPasswordHash() + { + lock(); + if (mPrivateKey.isNull() || !mPasswordHashed || !mID) { + unlock(); + return 0; + } + auto cm = ConnectionManager::getInstance(); + auto session = cm->getConnection(CONNECTION_MYSQL_LOGIN_SERVER); + + Poco::Data::Statement update(session); + + update << "UPDATE users SET password = ?, privkey = ? where id = ?;", + bind(mPasswordHashed), use(mPrivateKey), use(mID); + + + size_t resultCount = 0; + try { + return update.execute(); + } + catch (Poco::Exception& ex) { + lock("User::updatePrivkeyAndPasswordHash"); + addError(new ParamError(getTableName(), "mysql error by insert", ex.displayText().data())); + addError(new ParamError(getTableName(), "data set: ", toString().data())); + unlock(); + } + //printf("data valid: %s\n", toString().data()); + return 0; + } + /* std::string mEmail; diff --git a/src/cpp/model/table/User.h b/src/cpp/model/table/User.h index c211128cf..6e6b6f86f 100644 --- a/src/cpp/model/table/User.h +++ b/src/cpp/model/table/User.h @@ -45,7 +45,7 @@ namespace model { // specific db operation size_t updatePrivkey(); size_t updatePublickey(); - + size_t updatePrivkeyAndPasswordHash(); // default getter unlocked inline const std::string& getEmail() const { return mEmail; } @@ -56,8 +56,8 @@ namespace model { inline const unsigned char* getPublicKey() const { if (mPublicKey.isNull()) return nullptr; return mPublicKey.value().content().data(); } std::string getPublicKeyHex() const; - inline bool existPrivateKeyCrypted() const { return !mPrivateKey.isNull(); } - inline const std::vector& getPrivateKeyCrypted() const { return mPrivateKey.value().content(); } + inline bool hasPrivateKeyEncrypted() const { return !mPrivateKey.isNull(); } + inline const std::vector& getPrivateKeyEncrypted() const { return mPrivateKey.value().content(); } inline bool isEmailChecked() const { return mEmailChecked; } inline const std::string& getLanguageKey() const { return mLanguageKey; } diff --git a/src/cpp/tasks/AuthenticatedEncryptionCreateKeyTask.cpp b/src/cpp/tasks/AuthenticatedEncryptionCreateKeyTask.cpp index 6f17d8894..eea68d506 100644 --- a/src/cpp/tasks/AuthenticatedEncryptionCreateKeyTask.cpp +++ b/src/cpp/tasks/AuthenticatedEncryptionCreateKeyTask.cpp @@ -4,6 +4,8 @@ #include "../SingletonManager/SingletonTaskObserver.h" #include "../SingletonManager/ErrorManager.h" +#include "../lib/Profiler.h" + AuthenticatedEncryptionCreateKeyTask::AuthenticatedEncryptionCreateKeyTask(Poco::AutoPtr user, const std::string& passwd) : UniLib::controller::CPUTask(ServerConfig::g_CryptoCPUScheduler), mUser(user), mPassword(passwd) { @@ -20,6 +22,7 @@ int AuthenticatedEncryptionCreateKeyTask::run() auto em = ErrorManager::getInstance(); const static char* function_name = "AuthenticatedEncryptionCreateKeyTask::run"; auto authenticated_encryption = new AuthenticatedEncryption; + Profiler timeUsed; if (AuthenticatedEncryption::AUTH_ENCRYPT_OK != authenticated_encryption->createKey(mUser->getModel()->getEmail(), mPassword)) { em->addError(new Error(function_name, "error creating key")); em->addError(new ParamError(function_name, "for email", mUser->getModel()->getEmail())); @@ -27,7 +30,10 @@ int AuthenticatedEncryptionCreateKeyTask::run() em->sendErrorsAsEmail(); return -1; } + printf("create password time: %s\n", timeUsed.string().data()); + timeUsed.reset(); mUser->setPassword(authenticated_encryption); + printf("set password time: %s\n", timeUsed.string().data()); return 0; } \ No newline at end of file diff --git a/src/cpsp/adminUserPasswordReset.cpsp b/src/cpsp/adminUserPasswordReset.cpsp index 8b4b09b0b..648a18f61 100644 --- a/src/cpsp/adminUserPasswordReset.cpsp +++ b/src/cpsp/adminUserPasswordReset.cpsp @@ -89,7 +89,7 @@ enum PageState
  • <%= userModel->getEmail() %>
  • Public Key: <%= userModel->getPublicKeyHex() %>
  • E-Mail überprüft: <%= std::to_string(userModel->isEmailChecked()) %>
  • -
  • Private Key verschlüsselt: <%= std::to_string(userModel->existPrivateKeyCrypted()) %>
  • +
  • Private Key verschlüsselt: <%= std::to_string(userModel->hasPrivateKeyEncrypted()) %>
  • Passwort gesetzt: <%= std::to_string(userModel->getPasswordHashed() != 0) %>
  • <% } %>