From 1aeb506cd3fcc43e7cb01722deddeb83ab235456 Mon Sep 17 00:00:00 2001 From: Dario Date: Mon, 1 Jun 2020 19:13:38 +0200 Subject: [PATCH] make it more modular --- src/cpp/Crypto/KeyPair.cpp | 7 - src/cpp/Crypto/KeyPair.h | 7 + src/cpp/Crypto/Passphrase.cpp | 240 +++++++++++++++++++++++ src/cpp/Crypto/Passphrase.h | 37 ++++ src/cpp/SingletonManager/MemoryManager.h | 1 + src/cpp/model/Session.h | 2 +- src/cpsp/debugMnemonic.cpsp | 1 + src/cpsp/registerDirect.cpsp | 85 ++++++++ 8 files changed, 372 insertions(+), 8 deletions(-) create mode 100644 src/cpp/Crypto/Passphrase.cpp create mode 100644 src/cpp/Crypto/Passphrase.h create mode 100644 src/cpsp/registerDirect.cpsp diff --git a/src/cpp/Crypto/KeyPair.cpp b/src/cpp/Crypto/KeyPair.cpp index a94fb3f7c..2b829f6d9 100644 --- a/src/cpp/Crypto/KeyPair.cpp +++ b/src/cpp/Crypto/KeyPair.cpp @@ -12,15 +12,8 @@ using namespace Poco::Data::Keywords; - #define STR_BUFFER_SIZE 25 -static std::vector> g_specialChars = { - { 0xa4, "auml" },{ 0x84, "Auml" }, - { 0xbc, "uuml" },{ 0x9c, "Uuml" }, - { 0xb6, "ouml" },{ 0x96, "Ouml" }, - { 0x9f, "szlig" } -}; KeyPair::KeyPair() diff --git a/src/cpp/Crypto/KeyPair.h b/src/cpp/Crypto/KeyPair.h index 51a7076d2..0ab69c56a 100644 --- a/src/cpp/Crypto/KeyPair.h +++ b/src/cpp/Crypto/KeyPair.h @@ -52,12 +52,19 @@ protected: private: // 32 Byte + //! \brief ed25519 ref10 private key MemoryBin* mPrivateKey; + // 64 Byte + //! \brief ed25519 libsodium private key MemoryBin* mSodiumSecret; + // 32 Byte + //! \brief ed25519 ref10 public key unsigned char mPublicKey[ed25519_pubkey_SIZE]; + // 32 Byte + //! \brief ed25519 libsodium public key unsigned char mSodiumPublic[crypto_sign_PUBLICKEYBYTES]; }; diff --git a/src/cpp/Crypto/Passphrase.cpp b/src/cpp/Crypto/Passphrase.cpp new file mode 100644 index 000000000..0778e96b9 --- /dev/null +++ b/src/cpp/Crypto/Passphrase.cpp @@ -0,0 +1,240 @@ +#include "Passphrase.h" + +#include "Poco/Types.h" +#include "Poco/Tuple.h" + +#include "../SingletonManager/ErrorManager.h" + +#include "../ServerConfig.h" + +#define STR_BUFFER_SIZE 25 + +static std::vector> g_specialChars = { + { 0xa4, "auml" },{ 0x84, "Auml" }, + { 0xbc, "uuml" },{ 0x9c, "Uuml" }, + { 0xb6, "ouml" },{ 0x96, "Ouml" }, + { 0x9f, "szlig" } +}; + +Passphrase::Passphrase(const std::string& passphrase, const Mnemonic* wordSource) + : mPassphraseString(filter(passphrase)), mWordSource(wordSource) +{ + memset(mWordIndices, 0, PHRASE_WORD_COUNT * sizeof(Poco::UInt16)); +} + + +std::string Passphrase::filter(const std::string& passphrase) +{ + std::string filteredPassphrase; + auto passphrase_size = passphrase.size(); + + for (int i = 0; i < passphrase_size; i++) { + unsigned char c = passphrase.data()[i]; + // asci 128 even by utf8 (hex) + // 0000 0000 – 0000 007F + // utf8 + if (c > 0x0000007F) { + int additionalUtfByteCount = 0; + //filteredPassphrase += c; + if ((c & 0x00000080) == 0x00000080) { + // c3 a4 => ä + // c3 bc => ü + // c3 b6 => ö + // c3 84 => Ä + // c3 96 => Ö + // c3 9c => Ü + // c3 9f => ß + + + + unsigned char c2 = passphrase.data()[i + 1]; + bool insertedHtmlEntitie = false; + for (auto it = g_specialChars.begin(); it != g_specialChars.end(); it++) { + if (c2 == it->get<0>()) { + auto htmlEntitie = it->get<1>(); + filteredPassphrase += "&"; + filteredPassphrase += htmlEntitie; + filteredPassphrase += ";"; + i++; + insertedHtmlEntitie = true; + break; + } + } + if (insertedHtmlEntitie) continue; + additionalUtfByteCount = 1; + } + else if ((c & 0x00000800) == 0x00000800) { + additionalUtfByteCount = 2; + } + else if ((c & 0x00010000) == 0x00010000) { + additionalUtfByteCount = 3; + } + for (int j = 0; j <= additionalUtfByteCount; j++) { + filteredPassphrase += passphrase.data()[i + j]; + i++; + } + } + else { + // 32 = Space + // 65 = A + // 90 = Z + // 97 = a + // 122 = z + // 59 = ; + // 38 = & + if (c == 32 || c == 59 || c == 38 || + (c >= 65 && c <= 90) || + (c >= 97 && c <= 122)) { + filteredPassphrase += c; + } + else if (c == '\n' || c == '\r') { + filteredPassphrase += ' '; + } + } + + } + return filteredPassphrase; +} + +Poco::SharedPtr Passphrase::transform(const Mnemonic* targetWordSource) +{ + /* + if (!currentWordSource || !targetWordSource) { + return ""; + } + if (targetWordSource == currentWordSource) { + return passphrase; + } + auto word_indices = createWordIndices(passphrase, currentWordSource); + if (!word_indices) { + return ""; + } + + return createClearPassphraseFromWordIndices(word_indices, targetWordSource);*/ +// Poco::SharedPtr transformedPassphrase = new Passphrase() +} + +Poco::SharedPtr Passphrase::create(const MemoryBin* wordIndices, const Mnemonic* wordSource) +{ + //Poco::SharedPtr passphrase = new Passphrase() + const Poco::UInt64* word_indices_p = (const Poco::UInt64*)wordIndices->data(); + std::string clearPassphrase; + for (int i = 0; i < PHRASE_WORD_COUNT; i++) { + if (i * sizeof(Poco::UInt64) >= wordIndices->size()) break; + auto word = wordSource->getWord(word_indices_p[i]); + if (word) { + clearPassphrase += word; + clearPassphrase += " "; + } + } + return new Passphrase(clearPassphrase, wordSource); +} + + +bool Passphrase::createWordIndices() +{ + auto er = ErrorManager::getInstance(); + auto mm = MemoryManager::getInstance(); + const char* functionName = "Passphrase::createWordIndices"; + + if (!mWordSource) { + er->addError(new Error(functionName, "word source is empty")); + return false; + } + + + //DHASH key = DRMakeStringHash(passphrase); + size_t pass_phrase_size = mPassphraseString.size(); + + char acBuffer[STR_BUFFER_SIZE]; memset(acBuffer, 0, STR_BUFFER_SIZE); + size_t buffer_cursor = 0; + + // get word indices for hmac key + unsigned char word_cursor = 0; + for (auto it = mPassphraseString.begin(); it != mPassphraseString.end(); it++) + { + if (*it == ' ') { + if (buffer_cursor < 3) { + continue; + } + if (PHRASE_WORD_COUNT > word_cursor && mWordSource->isWordExist(acBuffer)) { + mWordIndices[word_cursor] = mWordSource->getWordIndex(acBuffer); + //word_indices_old[word_cursor] = word_source->getWordIndex(acBuffer); + } + else { + er->addError(new ParamError(functionName, "word didn't exist", acBuffer)); + er->sendErrorsAsEmail(); + return false; + } + word_cursor++; + memset(acBuffer, 0, STR_BUFFER_SIZE); + buffer_cursor = 0; + + } + else { + acBuffer[buffer_cursor++] = *it; + } + } + if (PHRASE_WORD_COUNT > word_cursor && mWordSource->isWordExist(acBuffer)) { + mWordIndices[word_cursor] = mWordSource->getWordIndex(acBuffer); + //word_indices_old[word_cursor] = word_source->getWordIndex(acBuffer); + word_cursor++; + } + //printf("word cursor: %d\n", word_cursor); + /*if (memcmp(word_indices_p, word_indices_old, word_indices->size()) != 0) { + + printf("not identical\n"); + memcpy(word_indices_p, word_indices_old, word_indices->size()); + }*/ + return true; +} + +const Poco::UInt16* Passphrase::getWordIndices() +{ + if (!(mWordIndices[0] | mWordIndices[1] | mWordIndices[2] | mWordIndices[3])) { + if (createWordIndices()) return mWordIndices; + } + return mWordIndices; +} + +bool Passphrase::checkIfValid() +{ + std::istringstream iss(mPassphraseString); + std::vector results(std::istream_iterator{iss}, + std::istream_iterator()); + + bool existAll = true; + for (auto it = results.begin(); it != results.end(); it++) { + if (*it == "\0" || *it == "" || it->size() < 3) continue; + if (!mWordSource->isWordExist(*it)) { + return false; + } + } + return true; +} +const Mnemonic* Passphrase::detectMnemonic(const std::string& passphrase, const MemoryBin* publicKey /* = nullptr*/) +{ + std::istringstream iss(passphrase); + std::vector results(std::istream_iterator{iss}, + std::istream_iterator()); + + for (int i = 0; i < ServerConfig::Mnemonic_Types::MNEMONIC_MAX; i++) { + Mnemonic& m = ServerConfig::g_Mnemonic_WordLists[i]; + bool existAll = true; + for (auto it = results.begin(); it != results.end(); it++) { + if (*it == "\0" || *it == "" || it->size() < 3) continue; + if (!m.isWordExist(*it)) { + existAll = false; + // leave inner for-loop + break; + } + } + if (existAll) { + if (publicKey) { + + } + return &ServerConfig::g_Mnemonic_WordLists[i]; + } + } + return nullptr; +} \ No newline at end of file diff --git a/src/cpp/Crypto/Passphrase.h b/src/cpp/Crypto/Passphrase.h new file mode 100644 index 000000000..b2296037a --- /dev/null +++ b/src/cpp/Crypto/Passphrase.h @@ -0,0 +1,37 @@ +#ifndef __GRADIDO_LOGIN_SERVER_CRYPTO_PASSPHRASE_H +#define __GRADIDO_LOGIN_SERVER_CRYPTO_PASSPHRASE_H + +//#include +#include "mnemonic.h" +#include "../SingletonManager/MemoryManager.h" + +class Passphrase +{ +public: + Passphrase(const std::string& passphrase, const Mnemonic* wordSource); + + static Poco::SharedPtr create(const MemoryBin* wordIndices, const Mnemonic* wordSource); + static const Mnemonic* detectMnemonic(const std::string& passphrase, const MemoryBin* publicKey = nullptr); + + //! \brief transform passphrase into another language/mnemonic source + Poco::SharedPtr transform(const Mnemonic* targetWordSource); + + //! \brief replace utf8 characters with html special character encoding + //! + //! TODO: add more utf8 chars for other languages as they needed + static std::string filter(const std::string& passphrase); + + bool checkIfValid(); + + const Poco::UInt16* getWordIndices(); + +protected: + bool createWordIndices(); + + std::string mPassphraseString; + const Mnemonic* mWordSource; + Poco::UInt16 mWordIndices[PHRASE_WORD_COUNT]; +}; + +#endif // __GRADIDO_LOGIN_SERVER_CRYPTO_PASSPHRASE + diff --git a/src/cpp/SingletonManager/MemoryManager.h b/src/cpp/SingletonManager/MemoryManager.h index 49ad9c5c2..c5b4cdf2e 100644 --- a/src/cpp/SingletonManager/MemoryManager.h +++ b/src/cpp/SingletonManager/MemoryManager.h @@ -39,6 +39,7 @@ public: inline operator size_t() const { return static_cast(mSize); } inline unsigned char* data() { return mData; } + inline const unsigned char* data() const { return mData; } protected: MemoryBin(Poco::UInt32 size); diff --git a/src/cpp/model/Session.h b/src/cpp/model/Session.h index c81e3d4c7..34cedfae5 100644 --- a/src/cpp/model/Session.h +++ b/src/cpp/model/Session.h @@ -73,8 +73,8 @@ public: inline Poco::AutoPtr getNewUser() { return mNewUser; } // ---------------- User functions ---------------------------- - // TODO: automatic redirect after some time, median profiled time for register // TODO: register state: written into db, mails sended, update state only if new state is higher as old state + // create User send e-mail activation link bool createUser(const std::string& first_name, const std::string& last_name, const std::string& email, const std::string& password); // adminRegister without passwort diff --git a/src/cpsp/debugMnemonic.cpsp b/src/cpsp/debugMnemonic.cpsp index bed6ba32b..06f0c5f86 100644 --- a/src/cpsp/debugMnemonic.cpsp +++ b/src/cpsp/debugMnemonic.cpsp @@ -33,6 +33,7 @@ { switch(type) { case ServerConfig::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER: return "de"; + case ServerConfig::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER_FIXED_CASES: return "de"; case ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER: return "en"; } return "unknown"; diff --git a/src/cpsp/registerDirect.cpsp b/src/cpsp/registerDirect.cpsp new file mode 100644 index 000000000..31d06d9fb --- /dev/null +++ b/src/cpsp/registerDirect.cpsp @@ -0,0 +1,85 @@ +<%@ page class="RegisterDirectPage" %> +<%@ page form="true" %> +<%@ page compressed="true" %> +<%@ page baseClass="PageRequestMessagedHandler" %> +<%@ header include="PageRequestMessagedHandler.h" %> +<%! +#include "../SingletonManager/SessionManager.h" +#include "Poco/Net/HTTPCookie.h" +%> +<%% + const char* pageName = "Registrieren"; + auto sm = SessionManager::getInstance(); + + bool userReturned = false; + + if(!form.empty()) { + if(form.get("register-password2", "") != form.get("register-password", "")) { + addError(new Error("Passwort", "Passwörter sind nicht identisch."), false); + } else { + auto session = sm->getSession(request); + if(!session) { + session = sm->getNewSession(); + auto user_host = request.clientAddress().host(); + session->setClientIp(user_host); + response.addCookie(session->getLoginCookie()); + } + + userReturned = session->createUser( + form.get("register-first-name", ""), + form.get("register-last-name", ""), + form.get("register-email", ""), + form.get("register-password", "") + ); + getErrors(session); + } + + } else { + // on enter login page with empty form + // remove old cookies if exist + sm->deleteLoginCookies(request, response); + } +%><%@ include file="header_old.cpsp" %> +
+

Einen neuen Account anlegen

+ <%= getErrorsHtml() %> + <% if(!form.empty() && userReturned) {%> +
+
+ Deine Anmeldung wird verarbeitet und es wird dir eine E-Mail zugeschickt. + Wenn sie da ist, befolge ihren Anweisungen. +
+
+ <% } else { %> +
+ +
+ Account anlegen +

Bitte gebe deine Daten um einen Account anzulegen

+

+ + "/> +

+

+ + "/> +

+

+ + "/> +

+

+ + +

+

+ + +

+
+ + +
+ <% } %> +
+<%@ include file="footer.cpsp" %>