diff --git a/CMakeLists.txt b/CMakeLists.txt index 99e32b774..786c655fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,6 +36,7 @@ FILE(GLOB PROTO_HEDERA "src/cpp/proto/hedera/*.cc" "src/cpp/proto/hedera/*.h") # used only for test project FILE(GLOB TEST "src/cpp/test/*.cpp" "src/cpp/test/*.h") +FILE(GLOB TEST_CRYPTO "src/cpp/test/crypto/*.cpp" "src/cpp/test/crypto/*.h") SET(LOCAL_SRCS ${CONTROLLER} ${TINF} ${MAIN} ${HTTPInterface} @@ -61,6 +62,7 @@ source_group("SingletonManager" FILES ${SINGLETON_MANAGER}) source_group("lib" FILES ${LIB_SRC}) source_group("HTTP-Interface" FILES ${HTTPInterface}) source_group("Json-Interface" FILES ${JSONInterface}) +source_group("Test\\crypto" FILES ${TEST_CRYPTO}) source_group("Test" FILES ${TEST}) endif(MSVC) @@ -150,7 +152,7 @@ enable_testing() #_TEST_BUILD -add_executable(Gradido_LoginServer_Test ${LOCAL_SRCS} ${TEST}) +add_executable(Gradido_LoginServer_Test ${LOCAL_SRCS} ${TEST} ${TEST_CRYPTO}) target_compile_definitions(Gradido_LoginServer_Test PUBLIC "_TEST_BUILD") target_link_libraries(Gradido_LoginServer_Test ${CONAN_LIBS} ${IROHA_ED25519}) @@ -161,3 +163,5 @@ if(WIN32) else(WIN32) target_link_libraries(Gradido_LoginServer_Test libmariadb PocoNet PocoUtil PocoJSON PocoFoundation PocoData PocoNetSSL protoc protobuf -pthread) endif(WIN32) + +add_test(NAME main COMMAND Gradido_LoginServer_Test) diff --git a/conanfile.txt b/conanfile.txt index cd2066f9d..1ad7bf433 100644 --- a/conanfile.txt +++ b/conanfile.txt @@ -3,6 +3,7 @@ Poco/1.9.4@pocoproject/stable libsodium/1.0.18@bincrafters/stable protobuf/3.9.1@bincrafters/stable boost/1.71.0@conan/stable +gtest/1.8.1@bincrafters/stable [generators] cmake diff --git a/src/cpp/Crypto/KeyPair.cpp b/src/cpp/Crypto/KeyPair.cpp index 2b829f6d9..c474a76c6 100644 --- a/src/cpp/Crypto/KeyPair.cpp +++ b/src/cpp/Crypto/KeyPair.cpp @@ -8,6 +8,8 @@ #include "Poco/Types.h" +#include "Passphrase.h" + #include "../ServerConfig.h" using namespace Poco::Data::Keywords; @@ -238,75 +240,7 @@ std::string KeyPair::createClearPassphraseFromWordIndices(MemoryBin* word_indice std::string KeyPair::filterPassphrase(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; + return Passphrase::filter(passphrase); } std::string KeyPair::getPubkeyHex() diff --git a/src/cpp/Crypto/KeyPair.h b/src/cpp/Crypto/KeyPair.h index 0ab69c56a..67a84f6da 100644 --- a/src/cpp/Crypto/KeyPair.h +++ b/src/cpp/Crypto/KeyPair.h @@ -8,8 +8,6 @@ #include "ed25519/ed25519.h" #include - - class UserWriteKeysIntoDB; class UserGenerateKeys; class DebugPassphrasePage; diff --git a/src/cpp/Crypto/Passphrase.cpp b/src/cpp/Crypto/Passphrase.cpp index 0778e96b9..9b8311ec6 100644 --- a/src/cpp/Crypto/Passphrase.cpp +++ b/src/cpp/Crypto/Passphrase.cpp @@ -96,8 +96,9 @@ std::string Passphrase::filter(const std::string& passphrase) return filteredPassphrase; } -Poco::SharedPtr Passphrase::transform(const Mnemonic* targetWordSource) +Poco::AutoPtr Passphrase::transform(const Mnemonic* targetWordSource) { + /* if (!currentWordSource || !targetWordSource) { return ""; @@ -112,16 +113,34 @@ Poco::SharedPtr Passphrase::transform(const Mnemonic* targetWordSour return createClearPassphraseFromWordIndices(word_indices, targetWordSource);*/ // Poco::SharedPtr transformedPassphrase = new Passphrase() + + if (!targetWordSource || mWordSource) { + return nullptr; + } + if (targetWordSource == mWordSource) { + return this; + } + if (createWordIndices()) { + return create(mWordIndices, targetWordSource); + } + return nullptr; } -Poco::SharedPtr Passphrase::create(const MemoryBin* wordIndices, const Mnemonic* wordSource) +Poco::AutoPtr Passphrase::create(const MemoryBin* wordIndices, const Mnemonic* wordSource) +{ + if (PHRASE_WORD_COUNT * sizeof(Poco::UInt16) >= wordIndices->size()) { + return nullptr; + } + + const Poco::UInt16* word_indices_p = (const Poco::UInt16*)wordIndices->data(); + return create(word_indices_p, wordSource); +} + +Poco::AutoPtr Passphrase::create(const Poco::UInt16 wordIndices[PHRASE_WORD_COUNT], 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]); + auto word = wordSource->getWord(wordIndices[i]); if (word) { clearPassphrase += word; clearPassphrase += " "; diff --git a/src/cpp/Crypto/Passphrase.h b/src/cpp/Crypto/Passphrase.h index b2296037a..de57ba859 100644 --- a/src/cpp/Crypto/Passphrase.h +++ b/src/cpp/Crypto/Passphrase.h @@ -5,16 +5,21 @@ #include "mnemonic.h" #include "../SingletonManager/MemoryManager.h" -class Passphrase + +#include "../lib/AutoPtrContainer.h" +#include "Poco/AutoPtr.h" + +class Passphrase : public AutoPtrContainer { public: Passphrase(const std::string& passphrase, const Mnemonic* wordSource); - static Poco::SharedPtr create(const MemoryBin* wordIndices, const Mnemonic* wordSource); + static Poco::AutoPtr create(const Poco::UInt16 wordIndices[PHRASE_WORD_COUNT], const Mnemonic* wordSource); + static Poco::AutoPtr 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); + Poco::AutoPtr transform(const Mnemonic* targetWordSource); //! \brief replace utf8 characters with html special character encoding //! @@ -26,6 +31,7 @@ public: const Poco::UInt16* getWordIndices(); protected: + //! \return true if ok bool createWordIndices(); std::string mPassphraseString; diff --git a/src/cpp/SingletonManager/MemoryManager.cpp b/src/cpp/SingletonManager/MemoryManager.cpp index 245c9d9df..132ec94de 100644 --- a/src/cpp/SingletonManager/MemoryManager.cpp +++ b/src/cpp/SingletonManager/MemoryManager.cpp @@ -1,5 +1,6 @@ #include "MemoryManager.h" #include "ErrorManager.h" +#include "sodium.h" #define _DEFAULT_PAGE_SIZE 10 @@ -17,6 +18,40 @@ MemoryBin::~MemoryBin() } } +std::string MemoryBin::convertToHex() +{ + auto mm = MemoryManager::getInstance(); + + Poco::UInt32 hexSize = mSize * 2 + 1; + auto hexMem = mm->getFreeMemory(hexSize); + //char* hexString = (char*)malloc(hexSize); + memset(*hexMem, 0, hexSize); + sodium_bin2hex(*hexMem, hexSize, mData, mSize); + std::string hex = (char*)*hexMem; + // free(hexString); + mm->releaseMemory(hexMem); + + return hex; +} + +int MemoryBin::convertFromHex(const std::string& hex) +{ + auto mm = MemoryManager::getInstance(); + size_t hexSize = hex.size(); + size_t binSize = (hexSize) / 2; + if (binSize > mSize) { + return -1; + } + memset(mData, 0, mSize); + + size_t resultBinSize = 0; + + if (0 != sodium_hex2bin(mData, binSize, hex.data(), hexSize, nullptr, &resultBinSize, nullptr)) { + return -2; + } + return 0; +} + // ************************************************************* diff --git a/src/cpp/SingletonManager/MemoryManager.h b/src/cpp/SingletonManager/MemoryManager.h index c5b4cdf2e..b010fa362 100644 --- a/src/cpp/SingletonManager/MemoryManager.h +++ b/src/cpp/SingletonManager/MemoryManager.h @@ -41,6 +41,12 @@ public: inline unsigned char* data() { return mData; } inline const unsigned char* data() const { return mData; } + std::string convertToHex(); + //! \return 0 if ok + //! -1 if bin is to small + //! -2 if hex is invalid + int convertFromHex(const std::string& hex); + protected: MemoryBin(Poco::UInt32 size); ~MemoryBin(); diff --git a/src/cpp/controller/UserBackups.cpp b/src/cpp/controller/UserBackups.cpp index 1680e8594..9eb744ac6 100644 --- a/src/cpp/controller/UserBackups.cpp +++ b/src/cpp/controller/UserBackups.cpp @@ -79,9 +79,9 @@ namespace controller { } } } - else { - return ""; - } + + return ""; + } std::string UserBackups::formatPassphrase(std::string passphrase, int targetLinesCount/* = 5*/) diff --git a/src/cpp/lib/AutoPtrContainer.cpp b/src/cpp/lib/AutoPtrContainer.cpp new file mode 100644 index 000000000..febaaa561 --- /dev/null +++ b/src/cpp/lib/AutoPtrContainer.cpp @@ -0,0 +1,35 @@ +#include "AutoPtrContainer.h" + +#include + +AutoPtrContainer::AutoPtrContainer() : mReferenceCount(1) +{ +} + +AutoPtrContainer::AutoPtrContainer(int referenceCount) + : mReferenceCount(referenceCount) +{ +} + +AutoPtrContainer::~AutoPtrContainer() +{ + mReferenceCount = 0; +} + + +void AutoPtrContainer::duplicate() +{ + Poco::ScopedLock lock(mReferenceCountMutex); + mReferenceCount++; +} + +void AutoPtrContainer::release() +{ + Poco::ScopedLock lock(mReferenceCountMutex); + + mReferenceCount--; + assert(mReferenceCount >= 0); + if (0 == mReferenceCount) { + delete this; + } +} \ No newline at end of file diff --git a/src/cpp/lib/AutoPtrContainer.h b/src/cpp/lib/AutoPtrContainer.h new file mode 100644 index 000000000..e0b69501c --- /dev/null +++ b/src/cpp/lib/AutoPtrContainer.h @@ -0,0 +1,35 @@ +#ifndef __GRADIDO_LOGIN_SERVER_LIB_AUTO_PTR_CONTAINER +#define __GRADIDO_LOGIN_SERVER_LIB_AUTO_PTR_CONTAINER + +/*! + * \author: Dario Rekowski + * + * \date: 02.06.2020 + * + * \brief: keep track over reserved instances, for using with Poco::AutoPtr +*/ + +#include "Poco/Mutex.h" + +class AutoPtrContainer +{ +public: + AutoPtrContainer(); + AutoPtrContainer(int referenceCount); + + + + void duplicate(); + void release(); + +protected: + // called only from release + virtual ~AutoPtrContainer(); + +private: + + int mReferenceCount; + Poco::FastMutex mReferenceCountMutex; +}; + +#endif //__GRADIDO_LOGIN_SERVER_LIB_AUTO_PTR_CONTAINER \ No newline at end of file diff --git a/src/cpp/test/crypto/TestPassphrase.cpp b/src/cpp/test/crypto/TestPassphrase.cpp new file mode 100644 index 000000000..2b69d29ec --- /dev/null +++ b/src/cpp/test/crypto/TestPassphrase.cpp @@ -0,0 +1,71 @@ +#include "TestPassphrase.h" + +#include "../../Crypto/Passphrase.h" +#include "../../SingletonManager/MemoryManager.h" + +#include "sodium.h" + +#include "gtest/gtest.h" + + + +TestPassphrase::TestPassphrase() +{ + +} + +TestPassphrase::~TestPassphrase() +{ + +} + +int TestPassphrase::init() +{ + return 0; +} + +//! \return 0 if okay, else return != 0 +int TestPassphrase::test() +{ + return 0; +} + +void PassphraseTest::SetUp() +{ + mPassphrasesForTesting.push_back(PassphraseDataSet( + "beauty slight skill maze wrap neither table term pizza journey unusual fence mind buzz scrap height critic service table knock fury shrimp curious fog", + ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER, + "6fa7180b132e1248c649fc7b2e422ad57663299f85bd88b8b8031dce28b501a8" + )); + mPassphrasesForTesting.push_back(PassphraseDataSet( + "oftmals bist bietet spalten Datenbank Masse sträflich hervor Derartig Hallo christlich Brief iPhone einpendeln telefonieren musizieren gigantisch Orchester zirkulieren essen gilt Erich Dollar money", + ServerConfig::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER, + "8943813a623863dd7c5e5b248e408ac8a8851ef758275b6043a06e9b5832c36c" + )); + mPassphrasesForTesting.push_back(PassphraseDataSet( + "tief Acker Abgaben jenseits Revolution verdeckt Entdeckung Sanktion sammeln Umdrehung regulieren murmeln Erkenntnis hart zwar zuspitzen indem fegen bomber zwölf Mobbing divers Inspiration Krieg", + ServerConfig::MNEMONIC_GRADIDO_BOOK_GERMAN_RANDOM_ORDER, + "d62f14173ae5d66b06753cc9d69d5471913ffc6053feedac2acf901eef3582a9" + )); +} + +TEST_F(PassphraseTest, detectMnemonic) { + for (auto it = mPassphrasesForTesting.begin(); it != mPassphrasesForTesting.end(); it++) { + auto testDataSet = *it; + EXPECT_EQ(Passphrase::detectMnemonic(testDataSet.passphrase), &ServerConfig::g_Mnemonic_WordLists[testDataSet.mnemonicType]); + } + EXPECT_FALSE(Passphrase::detectMnemonic("Dies ist eine ungültige Passphrase")); +} + +TEST_F(PassphraseTest, detectMnemonicWithPubkey) { + auto mm = MemoryManager::getInstance(); + auto pubkeyBin = mm->getFreeMemory(crypto_sign_PUBLICKEYBYTES); + for (auto it = mPassphrasesForTesting.begin(); it != mPassphrasesForTesting.end(); it++) { + auto testDataSet = *it; + //testDataSet.pubkeyHex + ASSERT_FALSE(pubkeyBin->convertFromHex(testDataSet.pubkeyHex)); + EXPECT_EQ(Passphrase::detectMnemonic(testDataSet.passphrase, pubkeyBin), &ServerConfig::g_Mnemonic_WordLists[testDataSet.mnemonicType]); + } + mm->releaseMemory(pubkeyBin); +} + diff --git a/src/cpp/test/crypto/TestPassphrase.h b/src/cpp/test/crypto/TestPassphrase.h new file mode 100644 index 000000000..fd68dde5c --- /dev/null +++ b/src/cpp/test/crypto/TestPassphrase.h @@ -0,0 +1,43 @@ +#ifndef __GRADIDO_LOGIN_SERVER_TEST_CRYPTO_TEST_PASSPHRASE_H +#define __GRADIDO_LOGIN_SERVER_TEST_CRYPTO_TEST_PASSPHRASE_H + +#include "../Test.h" +#include "../../ServerConfig.h" +#include "gtest/gtest.h" + +class TestPassphrase : public Test +{ +public: + TestPassphrase(); + ~TestPassphrase(); + + //! \return 0 if init okay, else return != 0 + int init(); + + //! \return 0 if okay, else return != 0 + int test(); + const char* getName() { return "TestPassphrase"; } + +protected: + +}; + +class PassphraseTest : public ::testing::Test { +protected: + void SetUp() override; + + struct PassphraseDataSet + { + PassphraseDataSet(std::string _passphrase, ServerConfig::Mnemonic_Types _type, std::string _pubkeyHex) + : passphrase(_passphrase), mnemonicType(_type), pubkeyHex(_pubkeyHex) {} + + std::string passphrase; + ServerConfig::Mnemonic_Types mnemonicType; + std::string pubkeyHex; + }; + + std::vector mPassphrasesForTesting; + // void TearDown() override {} +}; + +#endif //__GRADIDO_LOGIN_SERVER_TEST_CRYPTO_TEST_PASSPHRASE_H \ No newline at end of file diff --git a/src/cpp/test/main.cpp b/src/cpp/test/main.cpp index c49a883b6..6cccfff19 100644 --- a/src/cpp/test/main.cpp +++ b/src/cpp/test/main.cpp @@ -1,6 +1,7 @@ #include "main.h" #include +#include "gtest/gtest.h" std::list gTests; @@ -9,6 +10,7 @@ void fillTests() gTests.push_back(new TestTasks()); gTests.push_back(new TestHash()); gTests.push_back(new TestRegExp()); + gTests.push_back(new TestPassphrase()); // gTests.push_back(new LoginTest()); } @@ -53,5 +55,7 @@ int main(int argc, char** argv) load(); run(); ende(); - return 42; -} \ No newline at end of file + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); + //return 42; +} diff --git a/src/cpp/test/main.h b/src/cpp/test/main.h index 943d24eb4..33838aa66 100644 --- a/src/cpp/test/main.h +++ b/src/cpp/test/main.h @@ -2,3 +2,4 @@ #include "TestTasks.h" #include "TestHash.h" #include "TestRegExp.h" +#include "crypto/TestPassphrase.h"