diff --git a/include/gradido_blockchain/const.h b/include/gradido_blockchain/const.h index 73199212..2e4cde74 100644 --- a/include/gradido_blockchain/const.h +++ b/include/gradido_blockchain/const.h @@ -10,4 +10,7 @@ #define GRADIDO_DEFERRED_TRANSFER_MAX_TIMEOUT_INTERVAL std::chrono::months(3) +// passphrase word count +#define PHRASE_WORD_COUNT 24 + #endif //__GRADIDO_BLOCKCHAIN_CONST_H \ No newline at end of file diff --git a/include/gradido_blockchain/crypto/CryptoConfig.h b/include/gradido_blockchain/crypto/CryptoConfig.h index dc9f113a..b30a15a6 100644 --- a/include/gradido_blockchain/crypto/CryptoConfig.h +++ b/include/gradido_blockchain/crypto/CryptoConfig.h @@ -19,12 +19,14 @@ namespace CryptoConfig GRADIDOBLOCKCHAIN_EXPORT extern memory::BlockPtr g_SupportPublicKey; GRADIDOBLOCKCHAIN_EXPORT extern Mnemonic g_Mnemonic_WordLists[magic_enum::enum_integer(MnemonicType::MAX)]; + // throw exception on error //! //! \param printToFile if true, print every word list in a separat txt file for debugging GRADIDOBLOCKCHAIN_EXPORT void loadMnemonicWordLists(bool printToFile = false); GRADIDOBLOCKCHAIN_EXPORT bool loadCryptoKeys(const MapEnvironmentToConfig& cfg); GRADIDOBLOCKCHAIN_EXPORT void unload(); + GRADIDOBLOCKCHAIN_EXPORT const Mnemonic* getWordList(MnemonicType type); class GRADIDOBLOCKCHAIN_EXPORT MissingKeyException : GradidoBlockchainException { diff --git a/include/gradido_blockchain/crypto/Passphrase.h b/include/gradido_blockchain/crypto/Passphrase.h index 6cabd76d..2728e45c 100644 --- a/include/gradido_blockchain/crypto/Passphrase.h +++ b/include/gradido_blockchain/crypto/Passphrase.h @@ -2,8 +2,9 @@ #define __GRADIDO_LOGIN_SERVER_CRYPTO_PASSPHRASE_H #include "gradido_blockchain/memory/Block.h" -#include "mnemonic.h" +#include "MnemonicType.h" #include "gradido_blockchain/GradidoBlockchainException.h" +#include "gradido_blockchain/const.h" #include #include @@ -14,17 +15,17 @@ class GRADIDOBLOCKCHAIN_EXPORT Passphrase { public: Passphrase() = delete; - Passphrase(const std::string& passphrase, const Mnemonic* wordSource); + Passphrase(const std::string& passphrase, MnemonicType wordListType); - static std::shared_ptr create(const std::array& wordIndices, const Mnemonic* wordSource); + static std::shared_ptr create(const std::array& wordIndices, MnemonicType wordListType); //! \brief generate new passphrase with random - static std::shared_ptr generate(const Mnemonic* wordSource); + static std::shared_ptr generate(MnemonicType wordListType); - static const Mnemonic* detectMnemonic(const std::string& passphrase, const KeyPairEd25519* userKeyPair = nullptr); + static MnemonicType detectMnemonic(const std::string& passphrase, const KeyPairEd25519* userKeyPair = nullptr); //! \brief transform passphrase into another language/mnemonic source //! \return this if targetWordSource is the same as mWordSource - std::shared_ptr transform(const Mnemonic* targetWordSource); + std::shared_ptr transform(MnemonicType wordListType); //! \brief create clear passphrase from word indices from bitcoin word list (bip0039) //! @@ -49,7 +50,7 @@ class GRADIDOBLOCKCHAIN_EXPORT Passphrase void createWordIndices(); std::string mPassphraseString; - const Mnemonic* mWordSource; + MnemonicType mWordListType; std::array mWordIndices; }; diff --git a/include/gradido_blockchain/crypto/mnemonic.h b/include/gradido_blockchain/crypto/mnemonic.h index 70b00ea0..8a1cd3e3 100644 --- a/include/gradido_blockchain/crypto/mnemonic.h +++ b/include/gradido_blockchain/crypto/mnemonic.h @@ -12,15 +12,13 @@ */ #include "gradido_blockchain/GradidoBlockchainException.h" #include "gradido_blockchain/lib/DRHashList.h" +#include "MnemonicType.h" #include #include #include #include #include -#define PHRASE_WORD_COUNT 24 - - class GRADIDOBLOCKCHAIN_EXPORT Mnemonic { public: @@ -65,12 +63,12 @@ class MnemonicException : public GradidoBlockchainException explicit MnemonicException(const char* what, const char* word = nullptr); std::string getFullString() const noexcept; - MnemonicException& setMnemonic(const Mnemonic* mnemonic); - inline int getMnemonicIndex() { return mMnemonicIndex; } + MnemonicException& setWordListType(MnemonicType type) { mMnemonicType = type; return *this; } + inline MnemonicType getWordListType() { return mMnemonicType; } protected: std::string mWord; - int mMnemonicIndex; + MnemonicType mMnemonicType; }; diff --git a/src/crypto/CryptoConfig.cpp b/src/crypto/CryptoConfig.cpp index 10ded4e3..d5f52fdf 100644 --- a/src/crypto/CryptoConfig.cpp +++ b/src/crypto/CryptoConfig.cpp @@ -45,7 +45,7 @@ namespace CryptoConfig } catch (MnemonicException& ex) { // add info and rethrow - throw ex.setMnemonic(&g_Mnemonic_WordLists[i]); + throw ex.setWordListType(type); } if (printToFile) { std::string fileName(enum_name(type)); @@ -91,6 +91,11 @@ namespace CryptoConfig g_SupportPublicKey.reset(); } + const Mnemonic* getWordList(MnemonicType type) + { + return &CryptoConfig::g_Mnemonic_WordLists[enum_integer(type)]; + } + // ####################### exception ################################## MissingKeyException::MissingKeyException(const char* what, const char* keyName) noexcept : GradidoBlockchainException(what), mKeyName(keyName) diff --git a/src/crypto/Passphrase.cpp b/src/crypto/Passphrase.cpp index 0da40e4e..fe1d296b 100644 --- a/src/crypto/Passphrase.cpp +++ b/src/crypto/Passphrase.cpp @@ -22,8 +22,8 @@ static std::vector> g_specialChars = { { 0x9f, "szlig" } }; -Passphrase::Passphrase(const std::string& passphrase, const Mnemonic* wordSource) - : mPassphraseString(filter(passphrase)), mWordSource(wordSource) +Passphrase::Passphrase(const std::string& passphrase, MnemonicType wordListType) + : mPassphraseString(filter(passphrase)), mWordListType(wordListType) { mWordIndices.fill(0); createWordIndices(); @@ -103,19 +103,16 @@ std::string Passphrase::filter(const std::string& passphrase) return filteredPassphrase; } -std::shared_ptr Passphrase::transform(const Mnemonic* targetWordSource) +std::shared_ptr Passphrase::transform(MnemonicType wordListType) { - if (!targetWordSource || !mWordSource) { - return nullptr; - } - return create(mWordIndices, targetWordSource); + return create(mWordIndices, wordListType); } std::string Passphrase::createClearPassphrase() const { auto word_indices = getWordIndices(); std::string clear_passphrase; - auto word_source = &CryptoConfig::g_Mnemonic_WordLists[enum_integer(MnemonicType::BIP0039_SORTED_ORDER)]; + auto word_source = CryptoConfig::getWordList(MnemonicType::BIP0039_SORTED_ORDER); for (int i = 0; i < PHRASE_WORD_COUNT; i++) { auto word = word_source->getWord(word_indices[i]); if (word) { @@ -126,11 +123,11 @@ std::string Passphrase::createClearPassphrase() const return clear_passphrase; } -std::shared_ptr Passphrase::create(const std::array& wordIndices, const Mnemonic* wordSource) +std::shared_ptr Passphrase::create(const std::array& wordIndices, MnemonicType wordListType) { std::string clearPassphrase; for (int i = 0; i < PHRASE_WORD_COUNT; i++) { - auto word = wordSource->getWord(wordIndices[i]); + auto word = CryptoConfig::getWordList(wordListType)->getWord(wordIndices[i]); if (word) { clearPassphrase += word; clearPassphrase += " "; @@ -139,28 +136,26 @@ std::shared_ptr Passphrase::create(const std::array(new Passphrase(clearPassphrase, wordSource)); + return std::shared_ptr(new Passphrase(clearPassphrase, wordListType)); } -std::shared_ptr Passphrase::generate(const Mnemonic* wordSource) +std::shared_ptr Passphrase::generate(MnemonicType wordListType) { std::array word_indices; for (int i = 0; i < PHRASE_WORD_COUNT; i++) { word_indices[i] = randombytes_random() % 2048; } - return create(word_indices, wordSource); + return create(word_indices, wordListType); } void Passphrase::createWordIndices() { - if (!mWordSource) { - throw PassphraseEmptyWordSourceException(); - } size_t passphraseSize = mPassphraseString.size(); std::array buffer; buffer.fill(0); size_t bufferCursor = 0; + auto wordList = CryptoConfig::getWordList(mWordListType); // get word indices for hmac key unsigned char word_cursor = 0; @@ -170,12 +165,12 @@ void Passphrase::createWordIndices() if (bufferCursor < 3) { continue; } - if (PHRASE_WORD_COUNT > word_cursor && mWordSource->isWordExist(buffer.data())) { - mWordIndices[word_cursor] = mWordSource->getWordIndex(buffer.data()); + if (PHRASE_WORD_COUNT > word_cursor && wordList->isWordExist(buffer.data())) { + mWordIndices[word_cursor] = wordList->getWordIndex(buffer.data()); } else { MnemonicException exception("word don't exist", buffer.data()); - exception.setMnemonic(mWordSource); + exception.setWordListType(mWordListType); throw exception; } word_cursor++; @@ -188,14 +183,13 @@ void Passphrase::createWordIndices() buffer[bufferCursor++] = *it; } } - if (PHRASE_WORD_COUNT > word_cursor && mWordSource->isWordExist(buffer.data())) { - mWordIndices[word_cursor] = mWordSource->getWordIndex(buffer.data()); + if (PHRASE_WORD_COUNT > word_cursor && wordList->isWordExist(buffer.data())) { + mWordIndices[word_cursor] = wordList->getWordIndex(buffer.data()); } } bool Passphrase::checkIfValid() { - if (!mWordSource) return false; std::istringstream iss(mPassphraseString); std::vector results( std::istream_iterator{iss}, @@ -205,13 +199,13 @@ bool Passphrase::checkIfValid() bool existAll = true; for (auto it = results.begin(); it != results.end(); it++) { if (*it == "\0" || *it == "" || it->size() < 3) continue; - if (!mWordSource->isWordExist(it->data())) { + if (!CryptoConfig::getWordList(mWordListType)->isWordExist(it->data())) { return false; } } return true; } -const Mnemonic* Passphrase::detectMnemonic(const std::string& passphrase, const KeyPairEd25519* userKeyPair /* = nullptr*/) +MnemonicType Passphrase::detectMnemonic(const std::string& passphrase, const KeyPairEd25519* userKeyPair /* = nullptr*/) { std::istringstream iss(passphrase); std::vector results( @@ -229,9 +223,9 @@ const Mnemonic* Passphrase::detectMnemonic(const std::string& passphrase, const } #endif std::string last_words_not_found[enum_integer(MnemonicType::MAX)]; - Mnemonic* result = nullptr; + MnemonicType result = MnemonicType::MAX; enum_for_each([&](auto val) { - if (result) return; + if (result != MnemonicType::MAX) return; constexpr MnemonicType type = val; if(type == MnemonicType::MAX) return; int i = enum_integer(type); @@ -256,7 +250,7 @@ const Mnemonic* Passphrase::detectMnemonic(const std::string& passphrase, const { if (userKeyPair) { - std::shared_ptr test_passphrase(new Passphrase(passphrase, &m)); + std::shared_ptr test_passphrase(new Passphrase(passphrase, type)); test_passphrase->createWordIndices(); auto keyPairFromPassphrase = KeyPairEd25519::create(test_passphrase); if (keyPairFromPassphrase) @@ -276,7 +270,7 @@ const Mnemonic* Passphrase::detectMnemonic(const std::string& passphrase, const } } } - result = &CryptoConfig::g_Mnemonic_WordLists[i]; + result = type; // return &CryptoConfig::g_Mnemonic_WordLists[i]; } #ifdef _DEBUG diff --git a/src/crypto/mnemonic.cpp b/src/crypto/mnemonic.cpp index 4d0032e4..83cc702c 100644 --- a/src/crypto/mnemonic.cpp +++ b/src/crypto/mnemonic.cpp @@ -1,7 +1,7 @@ #include "gradido_blockchain/crypto/CryptoConfig.h" -#include "gradido_blockchain/crypto/MnemonicType.h" #include "gradido_blockchain/crypto/mnemonic.h" +#include "gradido_blockchain/const.h" #include "tinf.h" #include "magic_enum/magic_enum_utility.hpp" @@ -340,29 +340,13 @@ std::string Mnemonic::getSortedWordListJsonString() MnemonicException::MnemonicException(const char* what, const char* word/* = nullptr*/) : - GradidoBlockchainException(what), mMnemonicIndex(-1) + GradidoBlockchainException(what), mMnemonicType(MnemonicType::BIP0039_SORTED_ORDER) { if (word) { mWord = word; } } -MnemonicException& MnemonicException::setMnemonic(const Mnemonic* mnemonic) -{ - int mnemonicIndex = 0; - enum_for_each([&mnemonicIndex, mnemonic](auto val) { - if (mnemonicIndex) return; - constexpr MnemonicType type = val; - int i = enum_integer(type); - if (&CryptoConfig::g_Mnemonic_WordLists[i] == mnemonic) { - mnemonicIndex = i; - return; - } - }); - mMnemonicIndex = mnemonicIndex; - return *this; -} - std::string MnemonicException::getFullString() const noexcept { if (mWord.size()) { diff --git a/test/crypto/TestPassphrase.cpp b/test/crypto/TestPassphrase.cpp index f9e36f12..2f170f2d 100644 --- a/test/crypto/TestPassphrase.cpp +++ b/test/crypto/TestPassphrase.cpp @@ -5,6 +5,7 @@ #include "sodium.h" #include "gtest/gtest.h" +#include "magic_enum/magic_enum_utility.hpp" #include "gradido_blockchain/lib/DataTypeConverter.h" @@ -63,10 +64,10 @@ TEST_F(PassphraseTest, detectMnemonic) // currently not easy to differentiate from MnemonicType::GRADIDO_BOOK_GERMAN_RANDOM_ORDER if (MnemonicType::GRADIDO_BOOK_GERMAN_RANDOM_ORDER_FIXED_CASES == type) continue; - EXPECT_EQ(Passphrase::detectMnemonic(testDataSet.passphrases[i]), &CryptoConfig::g_Mnemonic_WordLists[i]); + EXPECT_EQ(Passphrase::detectMnemonic(testDataSet.passphrases[i]), type); } } - EXPECT_FALSE(Passphrase::detectMnemonic("Dies ist eine ungültige Passphrase")); + EXPECT_EQ(Passphrase::detectMnemonic("Dies ist eine ungültige Passphrase"), MnemonicType::MAX); } TEST_F(PassphraseTest, detectMnemonicWithPubkey) @@ -78,10 +79,13 @@ TEST_F(PassphraseTest, detectMnemonicWithPubkey) auto pubkeyBin = std::make_shared(memory::Block::fromHex(testDataSet.pubkeyHex)); auto key_pair = new KeyPairEd25519(pubkeyBin); - for (int i = 0; i < enum_integer(MnemonicType::MAX); i++) - { - EXPECT_EQ(Passphrase::detectMnemonic(testDataSet.passphrases[i], key_pair), &CryptoConfig::g_Mnemonic_WordLists[i]); - } + enum_for_each([testDataSet, key_pair](auto val) { + constexpr MnemonicType type = val; + if (type == MnemonicType::MAX) return; + auto i = enum_integer(type); + + EXPECT_EQ(Passphrase::detectMnemonic(testDataSet.passphrases[i], key_pair), type); + }); } } @@ -105,23 +109,23 @@ TEST_F(PassphraseTest, constructAndValid) for (auto it = mPassphrasesForTesting.begin(); it != mPassphrasesForTesting.end(); it++) { auto testDataSet = *it; - for (int i = 0; i < enum_integer(MnemonicType::MAX); i++) - { - Passphrase passphrase(testDataSet.passphrases[i], &CryptoConfig::g_Mnemonic_WordLists[i]); + enum_for_each([testDataSet](auto val) { + constexpr MnemonicType type = val; + if (type == MnemonicType::MAX) return; + auto i = enum_integer(type); + Passphrase passphrase(testDataSet.passphrases[i], type); EXPECT_TRUE(passphrase.checkIfValid()); - } + }); } // skip because it will stop tests even with try catch block - /*try + try { - Passphrase passphrase( - "Höh, maß, xDäöas", - &CryptoConfig::g_Mnemonic_WordLists[enum_integer(MnemonicType::GRADIDO_BOOK_GERMAN_RANDOM_ORDER)]); + Passphrase passphrase("Höh, maß, xDäöas", MnemonicType::GRADIDO_BOOK_GERMAN_RANDOM_ORDER); } catch (MnemonicException &ex) { SUCCEED(); - }*/ + } } TEST_F(PassphraseTest, wordIndices) @@ -129,13 +133,16 @@ TEST_F(PassphraseTest, wordIndices) for (auto it = mPassphrasesForTesting.begin(); it != mPassphrasesForTesting.end(); it++) { auto testDataSet = *it; - for (int i = 0; i < enum_integer(MnemonicType::MAX); i++) - { - Passphrase passphrase(testDataSet.passphrases[i], &CryptoConfig::g_Mnemonic_WordLists[i]); + enum_for_each([testDataSet](auto val) { + constexpr MnemonicType type = val; + if (type == MnemonicType::MAX) return; + auto i = enum_integer(type); + + Passphrase passphrase(testDataSet.passphrases[i], type); ASSERT_TRUE(passphrase.checkIfValid()); auto wordIndices = passphrase.getWordIndices(); EXPECT_TRUE(wordIndices == testDataSet.wordIndices); - } + }); } } @@ -144,8 +151,7 @@ TEST_F(PassphraseTest, createAndTransform) for (auto it = mPassphrasesForTesting.begin(); it != mPassphrasesForTesting.end(); it++) { auto test_data_set = *it; - auto mnemonic = &CryptoConfig::g_Mnemonic_WordLists[enum_integer(test_data_set.mnemonicType)]; - auto tr = Passphrase::create(test_data_set.wordIndices, mnemonic); + auto tr = Passphrase::create(test_data_set.wordIndices, test_data_set.mnemonicType); auto word_indices = tr->getWordIndices(); @@ -162,17 +168,17 @@ TEST_F(PassphraseTest, createAndTransform) // auto key_pair_old ASSERT_FALSE(tr == nullptr); EXPECT_TRUE(tr->checkIfValid()); - auto tr_english = tr->transform(&CryptoConfig::g_Mnemonic_WordLists[enum_integer(MnemonicType::BIP0039_SORTED_ORDER)]); + auto tr_english = tr->transform(MnemonicType::BIP0039_SORTED_ORDER); ASSERT_FALSE(tr_english == nullptr); EXPECT_EQ(tr_english->getString(), test_data_set.passphrases[enum_integer(MnemonicType::BIP0039_SORTED_ORDER)]); // printf("english: %s\n", tr_english->getString().data()); - auto tr_german1 = tr->transform(&CryptoConfig::g_Mnemonic_WordLists[enum_integer(MnemonicType::GRADIDO_BOOK_GERMAN_RANDOM_ORDER)]); + auto tr_german1 = tr->transform(MnemonicType::GRADIDO_BOOK_GERMAN_RANDOM_ORDER); ASSERT_FALSE(tr_german1 == nullptr); EXPECT_EQ(tr_german1->getString(), test_data_set.passphrases[enum_integer(MnemonicType::GRADIDO_BOOK_GERMAN_RANDOM_ORDER)]); // printf("german 1: %s\n", tr_german1->getString().data()); - auto tr_german2 = tr->transform(&CryptoConfig::g_Mnemonic_WordLists[enum_integer(MnemonicType::GRADIDO_BOOK_GERMAN_RANDOM_ORDER_FIXED_CASES)]); + auto tr_german2 = tr->transform(MnemonicType::GRADIDO_BOOK_GERMAN_RANDOM_ORDER_FIXED_CASES); ASSERT_FALSE(tr_german2 == nullptr); EXPECT_EQ(tr_german2->getString(), test_data_set.passphrases[enum_integer(MnemonicType::GRADIDO_BOOK_GERMAN_RANDOM_ORDER_FIXED_CASES)]); // printf("german 2: %s\n\n", tr_german2->getString().data()); diff --git a/test/crypto/TestPassphrase.h b/test/crypto/TestPassphrase.h index 53662477..db24bb42 100644 --- a/test/crypto/TestPassphrase.h +++ b/test/crypto/TestPassphrase.h @@ -3,6 +3,7 @@ #include "gradido_blockchain/crypto/CryptoConfig.h" #include "gradido_blockchain/crypto/MnemonicType.h" +#include "gradido_blockchain/Const.h" #include "gtest/gtest.h" #include "magic_enum/magic_enum.hpp"