#include "Passphrase.h" #include "Poco/Types.h" #include "Poco/Tuple.h" #include "../SingletonManager/ErrorManager.h" #include "KeyPairEd25519.h" #include "../ServerConfig.h" #include "../lib/DataTypeConverter.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)); getWordIndices(); } 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::AutoPtr 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() if (!targetWordSource || !mWordSource) { return nullptr; } if (targetWordSource == mWordSource) { duplicate(); return this; } if (createWordIndices()) { return create(mWordIndices, targetWordSource); } return nullptr; } Poco::AutoPtr Passphrase::create(const std::string& passphrase, const Mnemonic* wordSource) { return new Passphrase(passphrase, 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); } std::string Passphrase::createClearPassphrase() const { auto word_indices = getWordIndices(); std::string clear_passphrase; auto word_source = &ServerConfig::g_Mnemonic_WordLists[ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER]; for (int i = 0; i < PHRASE_WORD_COUNT; i++) { auto word = word_source->getWord(word_indices[i]); if (word) { clear_passphrase += word; clear_passphrase += " "; } } return clear_passphrase; } Poco::AutoPtr Passphrase::create(const Poco::UInt16 wordIndices[PHRASE_WORD_COUNT], const Mnemonic* wordSource) { std::string clearPassphrase; for (int i = 0; i < PHRASE_WORD_COUNT; i++) { auto word = wordSource->getWord(wordIndices[i]); if (word) { clearPassphrase += word; clearPassphrase += " "; } else { return nullptr; } } return new Passphrase(clearPassphrase, wordSource); } Poco::AutoPtr Passphrase::generate(const Mnemonic* wordSource) { auto em = ErrorManager::getInstance(); auto mm = MemoryManager::getInstance(); auto word_indices = mm->getFreeMemory(PHRASE_WORD_COUNT * sizeof(Poco::UInt16)); Poco::UInt16* word_indices_p = (Poco::UInt16*)word_indices->data(); for (int i = 0; i < PHRASE_WORD_COUNT; i++) { word_indices_p[i] = randombytes_random() % 2048; } auto result_passphrase = create(word_indices_p, wordSource); mm->releaseMemory(word_indices); return result_passphrase; /* unsigned int random_indices[PHRASE_WORD_COUNT]; unsigned int str_sizes[PHRASE_WORD_COUNT]; unsigned int phrase_buffer_size = 0; static const char* function_name = "Passphrase::generate"; bool error_reloading_mnemonic_word_list = false; int loop_trys = 0; Poco::RegularExpression check_valid_word("^[a-zA-ZÄÖÜäöüß&;]*$"); // TODO: make sure words didn't double for (int i = 0; i < PHRASE_WORD_COUNT; i++) { random_indices[i] = randombytes_random() % 2048; auto word = wordSource->getWord(random_indices[i]); if (loop_trys > 10 || error_reloading_mnemonic_word_list) { return nullptr; } if (!word) { em->addError(new ParamError(function_name, "empty word get for index", random_indices[i])); em->sendErrorsAsEmail(); random_indices[i] = randombytes_random() % 2048; word = wordSource->getWord(random_indices[i]); if (!word) return nullptr; } else { if (!check_valid_word.match(word, 0, Poco::RegularExpression::RE_NOTEMPTY)) { em->addError(new ParamError(function_name, "invalid word", word)); em->addError(new Error(function_name, "try to reload mnemonic word list, but this error is maybe evidence for a serious memory problem!!!")); if (!ServerConfig::loadMnemonicWordLists()) { em->addError(new Error(function_name, "error reloading mnemonic word lists")); error_reloading_mnemonic_word_list = true; } else { i = 0; loop_trys++; } em->sendErrorsAsEmail(); } } str_sizes[i] = strlen(word); phrase_buffer_size += str_sizes[i]; } phrase_buffer_size += PHRASE_WORD_COUNT + 1; std::string phrase_buffer(phrase_buffer_size, '\0'); int phrase_buffer_cursor = 0; for (int i = 0; i < PHRASE_WORD_COUNT; i++) { memcpy(&phrase_buffer[phrase_buffer_cursor], wordSource->getWord(random_indices[i]), str_sizes[i]); phrase_buffer_cursor += str_sizes[i]; phrase_buffer[phrase_buffer_cursor++] = ' '; } return create(; */ } 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; } const Poco::UInt16* Passphrase::getWordIndices() const { 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 KeyPairEd25519* keyPair /* = nullptr*/) { std::istringstream iss(passphrase); std::vector results(std::istream_iterator{iss}, std::istream_iterator()); std::string user_public_key_hex; if (keyPair) { user_public_key_hex = DataTypeConverter::pubkeyToHex(keyPair->getPublicKey()); //printf("user public key hex: %s\n", user_public_key_hex.data()); } std::string last_words_not_found[ServerConfig::Mnemonic_Types::MNEMONIC_MAX]; 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; //printf("couldn't find word: %s\n", (*it).data()); last_words_not_found[i] = (*it); // leave inner for-loop break; } } if (existAll) { if (keyPair) { Poco::AutoPtr test_passphrase = new Passphrase(passphrase, &m); test_passphrase->createWordIndices(); auto key_pair = KeyPairEd25519::create(test_passphrase); if (key_pair) { if (*key_pair != *keyPair) { #ifdef _TEST_BUILD // additional infos for debugging if error occure in test printf("public key mismatch\n"); std::string generated_key_pair_hex = DataTypeConverter::pubkeyToHex(key_pair->getPublicKey()); std::string parameter_key_pair_hex = DataTypeConverter::pubkeyToHex(keyPair->getPublicKey()); printf("parameter: %s, generated: %s\n", parameter_key_pair_hex.data(), generated_key_pair_hex.data()); #endif delete key_pair; continue; } else { delete key_pair; } } } return &ServerConfig::g_Mnemonic_WordLists[i]; } //printf("last word not found: %s in %s\n", last_words_not_found[i].data(), ServerConfig::mnemonicTypeToString((ServerConfig::Mnemonic_Types)i)); } return nullptr; }