update code to work together for setting new password and update encrypted privkey and password hash in db

This commit is contained in:
Dario 2020-06-08 18:30:29 +02:00
parent e7624382ae
commit c44184f823
12 changed files with 153 additions and 20 deletions

View File

@ -128,6 +128,34 @@ AuthenticatedEncryption::ResultType AuthenticatedEncryption::decrypt(const Memor
return AUTH_DECRYPT_OK; return AUTH_DECRYPT_OK;
} }
AuthenticatedEncryption::ResultType AuthenticatedEncryption::decrypt(const std::vector<unsigned char>& encryptedMessage, MemoryBin** message) const
{
assert(message);
std::shared_lock<std::shared_mutex> _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) const char* AuthenticatedEncryption::getErrorMessage(ResultType type)
{ {
switch (type) { switch (type) {

View File

@ -5,6 +5,7 @@
#include "../SingletonManager/MemoryManager.h" #include "../SingletonManager/MemoryManager.h"
#include <shared_mutex> #include <shared_mutex>
#include <vector>
/*! /*!
* *
@ -59,6 +60,11 @@ public:
ResultType encrypt(const MemoryBin* message, MemoryBin** encryptedMessage) const; ResultType encrypt(const MemoryBin* message, MemoryBin** encryptedMessage) const;
ResultType decrypt(const MemoryBin* encryptedMessage, MemoryBin** message) 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<unsigned char>& encryptedMessage, MemoryBin** message) const;
static const char* getErrorMessage(ResultType type); static const char* getErrorMessage(ResultType type);

View File

@ -8,10 +8,12 @@
#include "Passphrase.h" #include "Passphrase.h"
KeyPairEd25519::KeyPairEd25519(MemoryBin* privateKey, const unsigned char* publicKey) KeyPairEd25519::KeyPairEd25519(MemoryBin* privateKey)
: mSodiumSecret(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) KeyPairEd25519::KeyPairEd25519(const unsigned char* publicKey)

View File

@ -21,7 +21,7 @@ class KeyPairEd25519 : public IKeyPair
public: public:
//! \param privateKey: take ownership, release after object destruction //! \param privateKey: take ownership, release after object destruction
//! \param publicKey: copy //! \param publicKey: copy
KeyPairEd25519(MemoryBin* privateKey, const unsigned char* publicKey); KeyPairEd25519(MemoryBin* privateKey);
KeyPairEd25519(const unsigned char* publicKey); KeyPairEd25519(const unsigned char* publicKey);
~KeyPairEd25519(); ~KeyPairEd25519();
@ -38,10 +38,16 @@ public:
inline bool isTheSame(const KeyPairEd25519& b) const { inline bool isTheSame(const KeyPairEd25519& b) const {
return 0 == sodium_memcmp(mSodiumPublic, b.mSodiumPublic, crypto_sign_PUBLICKEYBYTES); 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 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; } inline bool hasPrivateKey() const { return mSodiumSecret != nullptr; }
//! \brief only way to get a private key.. encrypted //! \brief only way to get a private key.. encrypted

View File

@ -207,7 +207,7 @@ void AdminUserPasswordReset::handleRequest(Poco::Net::HTTPServerRequest& request
responseStream << "</li>\n"; responseStream << "</li>\n";
responseStream << "\t\t\t<li>Private Key verschlüsselt: "; responseStream << "\t\t\t<li>Private Key verschlüsselt: ";
#line 92 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminUserPasswordReset.cpsp" #line 92 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminUserPasswordReset.cpsp"
responseStream << ( std::to_string(userModel->existPrivateKeyCrypted()) ); responseStream << ( std::to_string(userModel->hasPrivateKeyEncrypted()) );
responseStream << "</li>\n"; responseStream << "</li>\n";
responseStream << "\t\t\t<li>Passwort gesetzt: "; responseStream << "\t\t\t<li>Passwort gesetzt: ";
#line 93 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminUserPasswordReset.cpsp" #line 93 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminUserPasswordReset.cpsp"

View File

@ -3,10 +3,12 @@
#include "sodium.h" #include "sodium.h"
#include "../SingletonManager/SessionManager.h" #include "../SingletonManager/SessionManager.h"
#include "../lib/DataTypeConverter.h"
namespace controller { namespace controller {
User::User(model::table::User* dbModel) User::User(model::table::User* dbModel)
: mPassword(nullptr) : mPassword(nullptr), mGradidoKeyPair(nullptr)
{ {
mDBModel = dbModel; mDBModel = dbModel;
} }
@ -15,6 +17,11 @@ namespace controller {
{ {
if (mPassword) { if (mPassword) {
delete mPassword; delete mPassword;
mPassword = nullptr;
}
if (mGradidoKeyPair) {
delete mGradidoKeyPair;
mGradidoKeyPair = nullptr;
} }
} }
@ -115,4 +122,45 @@ namespace controller {
return json; return json;
} }
int User::setPassword(AuthenticatedEncryption* passwd)
{
std::unique_lock<std::shared_mutex> _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();
}
} }

View File

@ -2,7 +2,8 @@
#define GRADIDO_LOGIN_SERVER_CONTROLLER_USER_INCLUDE #define GRADIDO_LOGIN_SERVER_CONTROLLER_USER_INCLUDE
#include "../model/table/User.h" #include "../model/table/User.h"
#include "../Crypto/AuthenticatedEncryption.h" //#include "../Crypto/AuthenticatedEncryption.h"
#include "../Crypto/KeyPairEd25519.h"
#include <shared_mutex> #include <shared_mutex>
@ -42,13 +43,12 @@ namespace controller {
// *********************************************************************************** // ***********************************************************************************
// password related // 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 //! \param passwd take owner ship
inline void setPassword(AuthenticatedEncryption* passwd) { //! \return 0 = new and current passwords are the same
std::unique_lock<std::shared_mutex> _lock(mSharedMutex); //! \return 1 = password changed, private key re-encrypted and saved into db
if (mPassword) delete passwd; //! \return -1 = stored pubkey and private key didn't match
mPassword = passwd; int setPassword(AuthenticatedEncryption* passwd);
}
inline const AuthenticatedEncryption* getPassword() { inline const AuthenticatedEncryption* getPassword() {
std::shared_lock<std::shared_mutex> _lock(mSharedMutex); std::shared_lock<std::shared_mutex> _lock(mSharedMutex);
@ -60,6 +60,7 @@ namespace controller {
std::string mPublicHex; std::string mPublicHex;
AuthenticatedEncryption* mPassword; AuthenticatedEncryption* mPassword;
KeyPairEd25519* mGradidoKeyPair;
mutable std::shared_mutex mSharedMutex; mutable std::shared_mutex mSharedMutex;
}; };

View File

@ -426,8 +426,8 @@ User::User(Poco::AutoPtr<controller::User> ctrl_user)
mPublicHex = std::string((char*)(*hexStringTemp)); mPublicHex = std::string((char*)(*hexStringTemp));
mm->releaseMemory(hexStringTemp); mm->releaseMemory(hexStringTemp);
} }
if (model->existPrivateKeyCrypted()) { if (model->hasPrivateKeyEncrypted()) {
auto privKeyVetor = model->getPrivateKeyCrypted(); auto privKeyVetor = model->getPrivateKeyEncrypted();
mPrivateKey = mm->getFreeMemory(privKeyVetor.size()); mPrivateKey = mm->getFreeMemory(privKeyVetor.size());
memcpy(*mPrivateKey, privKeyVetor.data(), privKeyVetor.size()); memcpy(*mPrivateKey, privKeyVetor.data(), privKeyVetor.size());
} }

View File

@ -143,7 +143,10 @@ namespace model {
size_t User::updatePrivkey() size_t User::updatePrivkey()
{ {
lock(); lock();
if (mPrivateKey.isNull()) return 0; if (mPrivateKey.isNull()) {
unlock();
return 0;
}
auto result = updateIntoDB("privkey", mPrivateKey.value()); auto result = updateIntoDB("privkey", mPrivateKey.value());
unlock(); unlock();
return result; return result;
@ -151,12 +154,45 @@ namespace model {
size_t User::updatePublickey() size_t User::updatePublickey()
{ {
lock(); lock();
if (mPublicKey.isNull()) return 0; if (mPublicKey.isNull()) {
unlock();
return 0;
}
auto result = updateIntoDB("pubkey", mPublicKey.value()); auto result = updateIntoDB("pubkey", mPublicKey.value());
unlock(); unlock();
return result; 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; std::string mEmail;

View File

@ -45,7 +45,7 @@ namespace model {
// specific db operation // specific db operation
size_t updatePrivkey(); size_t updatePrivkey();
size_t updatePublickey(); size_t updatePublickey();
size_t updatePrivkeyAndPasswordHash();
// default getter unlocked // default getter unlocked
inline const std::string& getEmail() const { return mEmail; } 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(); } inline const unsigned char* getPublicKey() const { if (mPublicKey.isNull()) return nullptr; return mPublicKey.value().content().data(); }
std::string getPublicKeyHex() const; std::string getPublicKeyHex() const;
inline bool existPrivateKeyCrypted() const { return !mPrivateKey.isNull(); } inline bool hasPrivateKeyEncrypted() const { return !mPrivateKey.isNull(); }
inline const std::vector<unsigned char>& getPrivateKeyCrypted() const { return mPrivateKey.value().content(); } inline const std::vector<unsigned char>& getPrivateKeyEncrypted() const { return mPrivateKey.value().content(); }
inline bool isEmailChecked() const { return mEmailChecked; } inline bool isEmailChecked() const { return mEmailChecked; }
inline const std::string& getLanguageKey() const { return mLanguageKey; } inline const std::string& getLanguageKey() const { return mLanguageKey; }

View File

@ -4,6 +4,8 @@
#include "../SingletonManager/SingletonTaskObserver.h" #include "../SingletonManager/SingletonTaskObserver.h"
#include "../SingletonManager/ErrorManager.h" #include "../SingletonManager/ErrorManager.h"
#include "../lib/Profiler.h"
AuthenticatedEncryptionCreateKeyTask::AuthenticatedEncryptionCreateKeyTask(Poco::AutoPtr<controller::User> user, const std::string& passwd) AuthenticatedEncryptionCreateKeyTask::AuthenticatedEncryptionCreateKeyTask(Poco::AutoPtr<controller::User> user, const std::string& passwd)
: UniLib::controller::CPUTask(ServerConfig::g_CryptoCPUScheduler), mUser(user), mPassword(passwd) : UniLib::controller::CPUTask(ServerConfig::g_CryptoCPUScheduler), mUser(user), mPassword(passwd)
{ {
@ -20,6 +22,7 @@ int AuthenticatedEncryptionCreateKeyTask::run()
auto em = ErrorManager::getInstance(); auto em = ErrorManager::getInstance();
const static char* function_name = "AuthenticatedEncryptionCreateKeyTask::run"; const static char* function_name = "AuthenticatedEncryptionCreateKeyTask::run";
auto authenticated_encryption = new AuthenticatedEncryption; auto authenticated_encryption = new AuthenticatedEncryption;
Profiler timeUsed;
if (AuthenticatedEncryption::AUTH_ENCRYPT_OK != authenticated_encryption->createKey(mUser->getModel()->getEmail(), mPassword)) { if (AuthenticatedEncryption::AUTH_ENCRYPT_OK != authenticated_encryption->createKey(mUser->getModel()->getEmail(), mPassword)) {
em->addError(new Error(function_name, "error creating key")); em->addError(new Error(function_name, "error creating key"));
em->addError(new ParamError(function_name, "for email", mUser->getModel()->getEmail())); em->addError(new ParamError(function_name, "for email", mUser->getModel()->getEmail()));
@ -27,7 +30,10 @@ int AuthenticatedEncryptionCreateKeyTask::run()
em->sendErrorsAsEmail(); em->sendErrorsAsEmail();
return -1; return -1;
} }
printf("create password time: %s\n", timeUsed.string().data());
timeUsed.reset();
mUser->setPassword(authenticated_encryption); mUser->setPassword(authenticated_encryption);
printf("set password time: %s\n", timeUsed.string().data());
return 0; return 0;
} }

View File

@ -89,7 +89,7 @@ enum PageState
<li><%= userModel->getEmail() %></li> <li><%= userModel->getEmail() %></li>
<li>Public Key: <%= userModel->getPublicKeyHex() %></li> <li>Public Key: <%= userModel->getPublicKeyHex() %></li>
<li>E-Mail überprüft: <%= std::to_string(userModel->isEmailChecked()) %></li> <li>E-Mail überprüft: <%= std::to_string(userModel->isEmailChecked()) %></li>
<li>Private Key verschlüsselt: <%= std::to_string(userModel->existPrivateKeyCrypted()) %></li> <li>Private Key verschlüsselt: <%= std::to_string(userModel->hasPrivateKeyEncrypted()) %></li>
<li>Passwort gesetzt: <%= std::to_string(userModel->getPasswordHashed() != 0) %></li> <li>Passwort gesetzt: <%= std::to_string(userModel->getPasswordHashed() != 0) %></li>
</ul> </ul>
<% } %> <% } %>