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;
}
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)
{
switch (type) {

View File

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

View File

@ -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)

View File

@ -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

View File

@ -207,7 +207,7 @@ void AdminUserPasswordReset::handleRequest(Poco::Net::HTTPServerRequest& request
responseStream << "</li>\n";
responseStream << "\t\t\t<li>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 << "</li>\n";
responseStream << "\t\t\t<li>Passwort gesetzt: ";
#line 93 "F:\\Gradido\\gradido_login_server\\src\\cpsp\\adminUserPasswordReset.cpsp"

View File

@ -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<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
#include "../model/table/User.h"
#include "../Crypto/AuthenticatedEncryption.h"
//#include "../Crypto/AuthenticatedEncryption.h"
#include "../Crypto/KeyPairEd25519.h"
#include <shared_mutex>
@ -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<std::shared_mutex> _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<std::shared_mutex> _lock(mSharedMutex);
@ -60,6 +60,7 @@ namespace controller {
std::string mPublicHex;
AuthenticatedEncryption* mPassword;
KeyPairEd25519* mGradidoKeyPair;
mutable std::shared_mutex mSharedMutex;
};

View File

@ -426,8 +426,8 @@ User::User(Poco::AutoPtr<controller::User> 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());
}

View File

@ -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;

View File

@ -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<unsigned char>& getPrivateKeyCrypted() const { return mPrivateKey.value().content(); }
inline bool hasPrivateKeyEncrypted() const { return !mPrivateKey.isNull(); }
inline const std::vector<unsigned char>& getPrivateKeyEncrypted() const { return mPrivateKey.value().content(); }
inline bool isEmailChecked() const { return mEmailChecked; }
inline const std::string& getLanguageKey() const { return mLanguageKey; }

View File

@ -4,6 +4,8 @@
#include "../SingletonManager/SingletonTaskObserver.h"
#include "../SingletonManager/ErrorManager.h"
#include "../lib/Profiler.h"
AuthenticatedEncryptionCreateKeyTask::AuthenticatedEncryptionCreateKeyTask(Poco::AutoPtr<controller::User> 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;
}

View File

@ -89,7 +89,7 @@ enum PageState
<li><%= userModel->getEmail() %></li>
<li>Public Key: <%= userModel->getPublicKeyHex() %></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>
</ul>
<% } %>