From 16870d5ca6a7df932495d76be45ffe6c82e26980 Mon Sep 17 00:00:00 2001 From: giskard Date: Sun, 29 Sep 2024 00:36:08 +0800 Subject: [PATCH] udp2p: setup utils (WIP..) --- src/meson.build | 3 ++ src/udp2p/manager.cc | 75 ++++++++++++++++++++++++++++++++++++++++ src/udp2p/manager.h | 46 ++++++++++++++++++++++++ src/udp2p/meson.build | 4 +++ src/udp2p/utils.cc | 53 ++++++++++++++++++++++++++++ src/udp2p/utils.h | 44 +++++++++++++++++++++++ test/meson.build | 1 + test/test_udp2p_utils.cc | 44 +++++++++++++++++++++++ 8 files changed, 270 insertions(+) create mode 100644 src/udp2p/manager.cc create mode 100644 src/udp2p/manager.h create mode 100644 src/udp2p/meson.build create mode 100644 src/udp2p/utils.cc create mode 100644 src/udp2p/utils.h create mode 100644 test/test_udp2p_utils.cc diff --git a/src/meson.build b/src/meson.build index 3d414f8..7130d79 100644 --- a/src/meson.build +++ b/src/meson.build @@ -31,6 +31,9 @@ deps = [ dependency('argparse', version: '>=3.0'), ] +subdir('udp2p/') +deps += udp2p_deps + exe = executable('mtrx', sources: src, dependencies: deps, diff --git a/src/udp2p/manager.cc b/src/udp2p/manager.cc new file mode 100644 index 0000000..5177685 --- /dev/null +++ b/src/udp2p/manager.cc @@ -0,0 +1,75 @@ +#include +#include + +#include "manager.h" + +namespace mtrx { +namespace udp2p { + +auto logger = spdlog::default_logger()->clone("udp2p"); + +bool AuthManager::updateUser(const std::string & id, const std::string & hash) { + if (userdb_.contains(id)) + logger->info("update user: {}", id); + else + logger->info("add user: {}", id); + + userdb_[id] = hash; + return true; +} + +bool AuthManager::rmUser(const std::string & id) { + auto it = userdb_.find(id); + if (it == userdb_.end()) { + logger->error("no such user: {}", id); + return false; + } + + userdb_.erase(it); + return true; +} + +bool AuthManager::authUser(const std::string & id, const std::string & hash) { + auto it = userdb_.find(id); + if (it == userdb_.end()) { + logger->error("no such user: {}", id); + return false; + } + return it->second == hash; +} + +bool EndpointManager::updateEndpoint(const std::string & id, const EndPoint & endpoint) { + if (onlineMap_.contains(id)) + logger->info("update endpoint: {}", id); + else + logger->info("add endpoint: {}", id); + + onlineMap_[id] = endpoint; + return true; +} + +bool EndpointManager::rmEndpoint(const std::string & id) { + auto it = onlineMap_.find(id); + if (it == onlineMap_.end()) { + logger->error("no such endpoint: {}", id); + return false; + } + + onlineMap_.erase(it); + return true; +}; + +const EndPoint & EndpointManager::getEndpointByID(const std::string & id) { + + auto it = onlineMap_.find(id); + if (it == onlineMap_.end()) { + logger->warn("no such endpoint: {}", id); + static const EndPoint endpoint_zero{}; + return endpoint_zero; + } + + return onlineMap_[id]; +} + +} // namespace udp2p +} // namespace mtrx diff --git a/src/udp2p/manager.h b/src/udp2p/manager.h new file mode 100644 index 0000000..a0ebef2 --- /dev/null +++ b/src/udp2p/manager.h @@ -0,0 +1,46 @@ +#ifndef INCLUDE_UDP2P_MANAGER_H +#define INCLUDE_UDP2P_MANAGER_H + +#include +#include + +#include + +namespace mtrx { +namespace udp2p { + +struct EndPoint { + asio::ip::address_v4 ip4; + int port; +}; + +class AuthManager { + public: + AuthManager(){}; + ~AuthManager(){}; + + bool authUser(const std::string & id, const std::string & hash); + bool updateUser(const std::string & id, const std::string & hash); + bool rmUser(const std::string & id); + + private: + std::map userdb_; +}; + +class EndpointManager { + public: + EndpointManager(){}; + ~EndpointManager(){}; + + bool updateEndpoint(const std::string & id, const EndPoint & endpoint); + bool rmEndpoint(const std::string & id); + const EndPoint & getEndpointByID(const std::string & id); + + private: + std::map onlineMap_; +}; + +}; // namespace udp2p +}; // namespace mtrx + +#endif diff --git a/src/udp2p/meson.build b/src/udp2p/meson.build new file mode 100644 index 0000000..2c3414d --- /dev/null +++ b/src/udp2p/meson.build @@ -0,0 +1,4 @@ +udp2p_deps = [ + dependency('asio'), + dependency('libargon2'), +] diff --git a/src/udp2p/utils.cc b/src/udp2p/utils.cc new file mode 100644 index 0000000..ec4f2e6 --- /dev/null +++ b/src/udp2p/utils.cc @@ -0,0 +1,53 @@ +#include +#include +#include +#include +#include +#include + +#include "utils.h" + +namespace mtrx { +namespace udp2p { +namespace utils { + +bool KeyUtils::genRandBytes(uint8_t * buf, const uint32_t size) { + // TODO: seed? better impl? + std::independent_bits_engine rbe; + std::generate(buf, buf + size, std::ref(rbe)); + return true; +} + +argon2_context KeyUtils::getHashContext(uint8_t * hash, const uint32_t hash_size, + const std::string & key) { + return argon2_context{ + hash, hash_size, /* output hash digest */ + const_cast(reinterpret_cast(key.c_str())), + static_cast(key.size()), // key + const_cast(reinterpret_cast(salt.c_str())), + static_cast(salt.size()), // salt + nullptr, 0, /* optional secret data */ + nullptr, 0, /* optional associated data */ + t_cost, m_cost, paralle, paralle, hash_ver, /* algorithm version */ + nullptr, nullptr, /* custom memory allocation / deallocation functions */ + /* by default only internal memory is cleared (pwd is not wiped) */ + ARGON2_DEFAULT_FLAGS}; +} + +bool KeyUtils::hashFromKey(uint8_t * hash, const uint32_t hash_size, + const std::string & key) { + auto ctx = getHashContext(hash, hash_size, key); + auto rc = argon2_ctx(&ctx, hash_type); + return (rc == ARGON2_OK); +} + +bool KeyUtils::verifyHash(const uint8_t * hash, const uint32_t hash_size, + const std::string & key) { + auto ctx = getHashContext(const_cast(hash), hash_size, key); + auto rc = argon2_verify_ctx(&ctx, reinterpret_cast(hash), hash_type); + return (rc == ARGON2_OK); +} + +}; // namespace utils +}; // namespace udp2p +}; // namespace mtrx diff --git a/src/udp2p/utils.h b/src/udp2p/utils.h new file mode 100644 index 0000000..55f8733 --- /dev/null +++ b/src/udp2p/utils.h @@ -0,0 +1,44 @@ +#ifndef INCLUDE_UDP2P_UTILS_H +#define INCLUDE_UDP2P_UTILS_H + +#include +#include + +#include + +namespace mtrx { +namespace udp2p { +namespace utils { + +// default hash length in byte +constexpr uint8_t HASH_SIZE = 32; +constexpr uint8_t SALT_SIZE = 16; + +class KeyUtils { + public: + static bool genRandBytes(uint8_t * buf, const uint32_t size); + static bool hashFromKey(uint8_t * hash, const uint32_t hash_size, + const std::string & key); + static bool verifyHash(const uint8_t * hash, const uint32_t hash_size, + const std::string & key); + + private: + static argon2_context getHashContext(uint8_t * hash, const uint32_t hash_size, + const std::string & key); + + // TODO: preshared salt, random salt? + constexpr static std::string salt = "somesalt"; + + constexpr static uint8_t t_cost = 4; // n-pass computation + constexpr static uint32_t m_cost = 1 << 10; // n-MB memory usage + constexpr static uint8_t paralle = 2; // number of threads and lanes + + constexpr static argon2_type hash_type = Argon2_id; + constexpr static argon2_version hash_ver = ARGON2_VERSION_13; +}; + +}; // namespace utils +}; // namespace udp2p +}; // namespace mtrx + +#endif diff --git a/test/meson.build b/test/meson.build index f1ab19b..a6b9885 100644 --- a/test/meson.build +++ b/test/meson.build @@ -3,6 +3,7 @@ src_test = cmd.stdout().strip().split('\n') src_test += [ '../src/log.cc', + '../src/udp2p/utils.cc', ] deps_test = deps + [ dependency('doctest') ] diff --git a/test/test_udp2p_utils.cc b/test/test_udp2p_utils.cc new file mode 100644 index 0000000..46ad988 --- /dev/null +++ b/test/test_udp2p_utils.cc @@ -0,0 +1,44 @@ +#define DOCTEST_CONFIG_IMPLEMENTATION_IN_DLL +#include "doctest.h" + +#include +#include +#include + +#include +#include + +#include "../src/udp2p/utils.h" + +auto logger = spdlog::default_logger(); +auto utils = mtrx::udp2p::utils::KeyUtils(); + +TEST_CASE("gen rand bytes") { + std::array hash; + utils.genRandBytes(hash.data(), hash.size()); + logger->info("1st salt bytes[{}]: {}", hash.size(), + spdlog::to_hex(hash.begin(), hash.end())); + + utils.genRandBytes(hash.data(), hash.size()); + logger->info("2nd salt bytes[{}]: {}", hash.size(), + spdlog::to_hex(hash.begin(), hash.end())); +} + +TEST_CASE("key hash") { + std::string key = "hello"; + + std::array hash; + + logger->info("unhash bytes[{}]: {}", hash.size(), + spdlog::to_hex(hash.begin(), hash.end())); + logger->info(utils.verifyHash(hash.data(), hash.size(), key)); + + logger->info("hash verified bytes[{}]: {}", hash.size(), + spdlog::to_hex(hash.begin(), hash.end())); + + utils.hashFromKey(hash.data(), hash.size(), key); + + logger->info("hashed bytes[{}]: {}", hash.size(), + spdlog::to_hex(hash.begin(), hash.end())); + CHECK(utils.verifyHash(hash.data(), hash.size(), key)); +}