From b69b90617565c1988c217ca25e2e63f5110b4979 Mon Sep 17 00:00:00 2001 From: alice <58637860+alicealys@users.noreply.github.com> Date: Mon, 27 Jul 2026 22:42:27 +0200 Subject: [PATCH] merge changes from t6-gsc-utils --- .gitmodules | 6 + deps/libtomcrypt | 1 + deps/libtommath | 1 + deps/premake/libtomcrypt.lua | 61 ++++ deps/premake/libtommath.lua | 52 +++ src/component/http.cpp | 131 ++++--- src/component/mysql.cpp | 6 +- src/dllmain.cpp | 30 +- src/utils/cryptography.cpp | 691 +++++++++++++++++++++++++++++++++++ src/utils/cryptography.hpp | 151 ++++++++ src/utils/http.cpp | 28 +- src/utils/http.hpp | 3 +- 12 files changed, 1071 insertions(+), 90 deletions(-) create mode 160000 deps/libtomcrypt create mode 160000 deps/libtommath create mode 100644 deps/premake/libtomcrypt.lua create mode 100644 deps/premake/libtommath.lua create mode 100644 src/utils/cryptography.cpp create mode 100644 src/utils/cryptography.hpp diff --git a/.gitmodules b/.gitmodules index 4775a9a..bd5ec43 100644 --- a/.gitmodules +++ b/.gitmodules @@ -37,3 +37,9 @@ [submodule "deps/date"] path = deps/date url = https://github.com/HowardHinnant/date +[submodule "deps/libtommath"] + path = deps/libtommath + url = https://github.com/libtom/libtommath.git +[submodule "deps/libtomcrypt"] + path = deps/libtomcrypt + url = https://github.com/libtom/libtomcrypt.git diff --git a/deps/libtomcrypt b/deps/libtomcrypt new file mode 160000 index 0000000..a8ed78c --- /dev/null +++ b/deps/libtomcrypt @@ -0,0 +1 @@ +Subproject commit a8ed78c2ca8a7dcb50ad789702ac0586125544f0 diff --git a/deps/libtommath b/deps/libtommath new file mode 160000 index 0000000..ae40a87 --- /dev/null +++ b/deps/libtommath @@ -0,0 +1 @@ +Subproject commit ae40a87a920099a7d9d00979570e0c8d917a1fd7 diff --git a/deps/premake/libtomcrypt.lua b/deps/premake/libtomcrypt.lua new file mode 100644 index 0000000..6c6f28d --- /dev/null +++ b/deps/premake/libtomcrypt.lua @@ -0,0 +1,61 @@ +libtomcrypt = { + source = path.join(dependencies.basePath, "libtomcrypt"), +} + +function libtomcrypt.import() + links { + "libtomcrypt" + } + + libtomcrypt.includes() +end + +function libtomcrypt.includes() + includedirs { + path.join(libtomcrypt.source, "src/headers") + } + + defines { + "LTC_NO_FAST", + "LTC_NO_PROTOTYPES", + "LTC_NO_RSA_BLINDING", + } +end + +function libtomcrypt.project() + project "libtomcrypt" + language "C" + + libtomcrypt.includes() + libtommath.import() + + files { + path.join(libtomcrypt.source, "src/**.c"), + } + + removefiles { + path.join(libtomcrypt.source, "src/**/*tab.c"), + path.join(libtomcrypt.source, "src/encauth/ocb3/**.c"), + } + + defines { + "_CRT_SECURE_NO_WARNINGS", + "LTC_SOURCE", + "_LIB", + "USE_LTM" + } + + removedefines { + "_DLL", + "_USRDLL" + } + + linkoptions { + "-IGNORE:4221" + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, libtomcrypt) diff --git a/deps/premake/libtommath.lua b/deps/premake/libtommath.lua new file mode 100644 index 0000000..ab4cdde --- /dev/null +++ b/deps/premake/libtommath.lua @@ -0,0 +1,52 @@ +libtommath = { + source = path.join(dependencies.basePath, "libtommath"), +} + +function libtommath.import() + links { + "libtommath" + } + + libtommath.includes() +end + +function libtommath.includes() + includedirs { + libtommath.source + } + + defines { + "LTM_DESC", + "__STDC_IEC_559__", + "MP_NO_DEV_URANDOM", + } +end + +function libtommath.project() + project "libtommath" + language "C" + + libtommath.includes() + + files { + path.join(libtommath.source, "*.c"), + } + + defines { + "_LIB" + } + + removedefines { + "_DLL", + "_USRDLL" + } + + linkoptions { + "-IGNORE:4221" + } + + warnings "Off" + kind "StaticLib" +end + +table.insert(dependencies, libtommath) diff --git a/src/component/http.cpp b/src/component/http.cpp index 6f929d6..71f12f6 100644 --- a/src/component/http.cpp +++ b/src/component/http.cpp @@ -57,7 +57,7 @@ namespace http if (result.buffer.size() >= max_result_size) { - printf("^3WARNING: http result size bigger than %i bytes (%i), truncating!", max_result_size, + printf("^3WARNING: http result size bigger than %i bytes (%i), truncating!", max_result_size, static_cast(result.buffer.size())); result.buffer.resize(max_result_size); } @@ -92,9 +92,9 @@ namespace http scheduler::thread_pool.push([request] { request->result = utils::http::get_data( - request->params.url, - request->params.fields, - request->params.headers, + request->params.url, + request->params.fields, + request->params.headers, request->params.method); request->completed = true; }); @@ -121,6 +121,61 @@ namespace http requests.clear(); } + + void parse_request_options(http_request_params_t& params, const scripting::array& options) + { + const auto fields = options["parameters"]; + const auto body = options["body"]; + const auto headers = options["headers"]; + const auto method = options["method"]; + + if (method.is()) + { + params.method = method.as(); + } + + if (fields.is()) + { + const auto fields_ = fields.as(); + const auto keys = fields_.get_keys(); + + for (const auto& key : keys) + { + if (!key.is()) + { + continue; + } + + const auto key_ = key.as(); + const auto value = fields_[key].to_string(); + params.fields += key_ + "=" + value + "&"; + } + + } + else if (body.is()) + { + params.fields = body.as(); + } + + if (headers.is()) + { + const auto headers_arr = headers.as(); + const auto keys = headers_arr.get_keys(); + + for (const auto& key : keys) + { + if (!key.is()) + { + continue; + } + + const auto key_str = key.as(); + const auto value = headers_arr[key].to_string(); + + params.headers[key_str] = value; + } + } + } } class component final : public component_interface @@ -151,62 +206,26 @@ namespace http if (va.size() > 0) { const auto options = va[0].as(); - - const auto fields = options["parameters"]; - const auto body = options["body"]; - const auto headers = options["headers"]; - const auto method = options["method"]; - - if (method.is()) - { - params.method = method.as(); - } - - if (fields.is()) - { - const auto fields_ = fields.as(); - const auto keys = fields_.get_keys(); - - for (const auto& key : keys) - { - if (!key.is()) - { - continue; - } - - const auto key_ = key.as(); - const auto value = fields_[key].to_string(); - params.fields += key_ + "=" + value + "&"; - } - - } - else if (body.is()) - { - params.fields = body.as(); - } - - if (headers.is()) - { - const auto headers_arr = headers.as(); - const auto keys = headers_arr.get_keys(); - - for (const auto& key : keys) - { - if (!key.is()) - { - continue; - } - - const auto key_str = key.as(); - const auto value = headers_arr[key].to_string(); - - params.headers[key_str] = value; - } - } + parse_request_options(params, options); } return create_request(params); }); + + gsc::function::add_multiple([](const std::string& url, const scripting::variadic_args& va) + { + http_request_params_t params{}; + params.url = url; + params.method = "POST"; + + if (va.size() > 0) + { + const auto options = va[0].as(); + parse_request_options(params, options); + } + + return create_request(params); + }, "httppost", "http::post"); } }; } diff --git a/src/component/mysql.cpp b/src/component/mysql.cpp index e452ee6..52f953c 100644 --- a/src/component/mysql.cpp +++ b/src/component/mysql.cpp @@ -451,7 +451,7 @@ namespace mysql }); }); - gsc::function::add("mysql::query", [](const std::string& query) + gsc::function::add_multiple([](const std::string& query) { return create_mysql_query([=](database_t& db) { @@ -469,7 +469,7 @@ namespace mysql return result; }); - }); + }, "mysql::query", "mysql::execute"); gsc::function::add("mysql::prepared_statement", [](const std::string& query, const scripting::variadic_args& values) { @@ -520,7 +520,7 @@ namespace mysql const auto handle = db->get_handle(); const auto stmt = mysql_stmt_init(handle); - if (mysql_stmt_prepare(stmt, query.data(), query.size()) != 0 || + if (mysql_stmt_prepare(stmt, query.data(), query.size()) != 0 || mysql_stmt_bind_param(stmt, binds) != 0 || mysql_stmt_execute(stmt) != 0) { diff --git a/src/dllmain.cpp b/src/dllmain.cpp index 5940c3e..6906b91 100644 --- a/src/dllmain.cpp +++ b/src/dllmain.cpp @@ -8,22 +8,48 @@ #include #include #include +#include +#include namespace { utils::hook::detour load_library_hook; + + std::string extract_resource(const std::string& name, const int resource) + { + const auto data = utils::nt::load_resource(resource); + const auto path = std::filesystem::current_path() / "tmp" / name; + const auto path_str = path.generic_string(); + + if (!utils::io::write_file(path_str, data)) + { + const auto current = utils::io::read_file(path_str); + const auto hash_current = utils::cryptography::md5::compute(current); + const auto hash_target = utils::cryptography::md5::compute(data); + if (hash_target != hash_current) + { + throw std::runtime_error("failed to extract libmysql.dll!"); + } + } + + return path_str; + } + HMODULE __stdcall load_library_stub(LPCSTR lib_name, HANDLE file, DWORD flags) { if (lib_name == "libmysql.dll"s) { - static auto dll = utils::binary_resource{LIBMYSQL_DLL, lib_name}; - const auto path = dll.get_extracted_file(); + const auto path = extract_resource(lib_name, LIBMYSQL_DLL); const auto handle = load_library_hook.invoke_pascal(path.data(), file, flags); if (handle != nullptr) { return handle; } + else + { + throw std::runtime_error(std::format("failed to load libmysql.dll: {}", GetLastError())); + } } return load_library_hook.invoke_pascal(lib_name, file, flags); diff --git a/src/utils/cryptography.cpp b/src/utils/cryptography.cpp new file mode 100644 index 0000000..3d32ca2 --- /dev/null +++ b/src/utils/cryptography.cpp @@ -0,0 +1,691 @@ +#include + +#include "cryptography.hpp" +#include "nt.hpp" +#include + +#undef max +using namespace std::string_literals; + +/// http://www.opensource.apple.com/source/CommonCrypto/CommonCrypto-55010/Source/libtomcrypt/doc/libTomCryptDoc.pdf + +#pragma warning(push) +#pragma warning(disable: 4996) + +namespace utils::cryptography +{ + namespace + { + struct __ + { + __() + { + ltc_mp = ltm_desc; + + register_cipher(&aes_desc); + register_cipher(&des3_desc); + + register_prng(&sprng_desc); + register_prng(&fortuna_desc); + register_prng(&yarrow_desc); + + register_hash(&sha1_desc); + register_hash(&sha256_desc); + register_hash(&sha512_desc); + } + } ___; + + [[maybe_unused]] const char* cs(const uint8_t* data) + { + return reinterpret_cast(data); + } + + [[maybe_unused]] char* cs(uint8_t* data) + { + return reinterpret_cast(data); + } + + [[maybe_unused]] const uint8_t* cs(const char* data) + { + return reinterpret_cast(data); + } + + [[maybe_unused]] uint8_t* cs(char* data) + { + return reinterpret_cast(data); + } + + [[maybe_unused]] unsigned long ul(const size_t value) + { + return static_cast(value); + } + + class prng + { + public: + prng(const ltc_prng_descriptor& descriptor, const bool autoseed = true) + : state_(std::make_unique()) + , descriptor_(descriptor) + { + this->id_ = register_prng(&descriptor); + if (this->id_ == -1) + { + throw std::runtime_error("PRNG "s + this->descriptor_.name + " could not be registered!"); + } + + if (autoseed) + { + this->auto_seed(); + } + else + { + this->descriptor_.start(this->state_.get()); + } + } + + ~prng() + { + this->descriptor_.done(this->state_.get()); + } + + prng_state* get_state() const + { + this->descriptor_.ready(this->state_.get()); + return this->state_.get(); + } + + int get_id() const + { + return this->id_; + } + + void add_entropy(const void* data, const size_t length) const + { + this->descriptor_.add_entropy(static_cast(data), ul(length), this->state_.get()); + } + + void read(void* data, const size_t length) const + { + this->descriptor_.read(static_cast(data), ul(length), this->get_state()); + } + + private: + int id_; + std::unique_ptr state_; + const ltc_prng_descriptor& descriptor_; + + void auto_seed() const + { + rng_make_prng(128, this->id_, this->state_.get(), nullptr); + + int i[4]; // uninitialized data + auto* i_ptr = &i; + this->add_entropy(reinterpret_cast(&i), sizeof(i)); + this->add_entropy(reinterpret_cast(&i_ptr), sizeof(i_ptr)); + + auto t = time(nullptr); + this->add_entropy(reinterpret_cast(&t), sizeof(t)); + } + }; + + const prng prng_(fortuna_desc); + } + + ecc::key::key() + { + ZeroMemory(&this->key_storage_, sizeof(this->key_storage_)); + } + + ecc::key::~key() + { + this->free(); + } + + ecc::key::key(key&& obj) noexcept + : key() + { + this->operator=(std::move(obj)); + } + + ecc::key::key(const key& obj) + : key() + { + this->operator=(obj); + } + + ecc::key& ecc::key::operator=(key&& obj) noexcept + { + if (this != &obj) + { + std::memmove(&this->key_storage_, &obj.key_storage_, sizeof(this->key_storage_)); + ZeroMemory(&obj.key_storage_, sizeof(obj.key_storage_)); + } + + return *this; + } + + ecc::key& ecc::key::operator=(const key& obj) + { + if (this != &obj && obj.is_valid()) + { + this->deserialize(obj.serialize(obj.key_storage_.type)); + } + + return *this; + } + + bool ecc::key::is_valid() const + { + return (!memory::is_set(&this->key_storage_, 0, sizeof(this->key_storage_))); + } + + ecc_key& ecc::key::get() + { + return this->key_storage_; + } + + const ecc_key& ecc::key::get() const + { + return this->key_storage_; + } + + std::string ecc::key::get_public_key() const + { + uint8_t buffer[512] = {0}; + unsigned long length = sizeof(buffer); + + if (ecc_ansi_x963_export(&this->key_storage_, buffer, &length) == CRYPT_OK) + { + return std::string(cs(buffer), length); + } + + return {}; + } + + void ecc::key::set(const std::string& pub_key_buffer) + { + this->free(); + + if (ecc_ansi_x963_import(cs(pub_key_buffer.data()), + ul(pub_key_buffer.size()), + &this->key_storage_) != CRYPT_OK) + { + ZeroMemory(&this->key_storage_, sizeof(this->key_storage_)); + } + } + + void ecc::key::deserialize(const std::string& key) + { + this->free(); + + if (ecc_import(cs(key.data()), ul(key.size()), + &this->key_storage_) != CRYPT_OK + ) + { + ZeroMemory(&this->key_storage_, sizeof(this->key_storage_)); + } + } + + std::string ecc::key::serialize(const int type) const + { + uint8_t buffer[4096] = {0}; + unsigned long length = sizeof(buffer); + + if (ecc_export(buffer, &length, type, &this->key_storage_) == CRYPT_OK) + { + return std::string(cs(buffer), length); + } + + return ""; + } + + void ecc::key::free() + { + if (this->is_valid()) + { + ecc_free(&this->key_storage_); + } + + ZeroMemory(&this->key_storage_, sizeof(this->key_storage_)); + } + + bool ecc::key::operator==(key& key) const + { + return (this->is_valid() && key.is_valid() && this->serialize(PK_PUBLIC) == key.serialize(PK_PUBLIC)); + } + + uint64_t ecc::key::get_hash() const + { + const auto hash = sha1::compute(this->get_public_key()); + if (hash.size() >= 8) + { + return *reinterpret_cast(hash.data()); + } + + return 0; + } + + ecc::key ecc::generate_key(const int bits) + { + key key; + ecc_make_key(prng_.get_state(), prng_.get_id(), bits / 8, &key.get()); + + return key; + } + + ecc::key ecc::generate_key(const int bits, const std::string& entropy) + { + key key{}; + const prng yarrow(yarrow_desc, false); + yarrow.add_entropy(entropy.data(), entropy.size()); + + ecc_make_key(yarrow.get_state(), yarrow.get_id(), bits / 8, &key.get()); + + return key; + } + + std::string ecc::sign_message(const key& key, const std::string& message) + { + if (!key.is_valid()) return ""; + + uint8_t buffer[512]; + unsigned long length = sizeof(buffer); + + ecc_sign_hash(cs(message.data()), ul(message.size()), buffer, &length, prng_.get_state(), prng_.get_id(), + &key.get()); + + return std::string(cs(buffer), length); + } + + bool ecc::verify_message(const key& key, const std::string& message, const std::string& signature) + { + if (!key.is_valid()) return false; + + auto result = 0; + return (ecc_verify_hash(cs(signature.data()), + ul(signature.size()), + cs(message.data()), + ul(message.size()), &result, + &key.get()) == CRYPT_OK && result != 0); + } + + bool ecc::encrypt(const key& key, std::string& data) + { + std::string out_data{}; + out_data.resize(std::max(ul(data.size() * 3), ul(0x100))); + + auto out_len = ul(out_data.size()); + auto crypt = [&]() + { + return ecc_encrypt_key(cs(data.data()), ul(data.size()), cs(out_data.data()), &out_len, + prng_.get_state(), prng_.get_id(), find_hash("sha512"), &key.get()); + }; + + auto res = crypt(); + + if (res == CRYPT_BUFFER_OVERFLOW) + { + out_data.resize(out_len); + res = crypt(); + } + + if (res != CRYPT_OK) + { + return false; + } + + out_data.resize(out_len); + data = std::move(out_data); + return true; + } + + bool ecc::decrypt(const key& key, std::string& data) + { + std::string out_data{}; + out_data.resize(std::max(ul(data.size() * 3), ul(0x100))); + + auto out_len = ul(out_data.size()); + auto crypt = [&]() + { + return ecc_decrypt_key(cs(data.data()), ul(data.size()), cs(out_data.data()), &out_len, &key.get()); + }; + + auto res = crypt(); + + if (res == CRYPT_BUFFER_OVERFLOW) + { + out_data.resize(out_len); + res = crypt(); + } + + if (res != CRYPT_OK) + { + return false; + } + + out_data.resize(out_len); + data = std::move(out_data); + return true; + } + + std::string rsa::encrypt(const std::string& data, const std::string& hash, const std::string& key) + { + rsa_key new_key; + rsa_import(cs(key.data()), ul(key.size()), &new_key); + const auto _ = gsl::finally([&]() + { + rsa_free(&new_key); + }); + + + std::string out_data{}; + out_data.resize(std::max(ul(data.size() * 3), ul(0x100))); + + auto out_len = ul(out_data.size()); + auto crypt = [&]() + { + return rsa_encrypt_key_ex(cs(data.data()), ul(data.size()), cs(out_data.data()), &out_len, cs(hash.data()), + ul(hash.size()), prng_.get_state(), prng_.get_id(), find_hash("sha512"), LTC_PKCS_1_V1_5, &new_key); + }; + + auto res = crypt(); + + if (res == CRYPT_BUFFER_OVERFLOW) + { + out_data.resize(out_len); + res = crypt(); + } + + if (res == CRYPT_OK) + { + out_data.resize(out_len); + return out_data; + } + + return {}; + } + + std::string des3::encrypt(const std::string& data, const std::string& iv, const std::string& key) + { + std::string enc_data; + enc_data.resize(data.size()); + + symmetric_CBC cbc; + const auto des3 = find_cipher("3des"); + + cbc_start(des3, cs(iv.data()), cs(key.data()), static_cast(key.size()), 0, &cbc); + cbc_encrypt(cs(data.data()), cs(enc_data.data()), ul(data.size()), &cbc); + cbc_done(&cbc); + + return enc_data; + } + + std::string des3::decrypt(const std::string& data, const std::string& iv, const std::string& key) + { + std::string dec_data; + dec_data.resize(data.size()); + + symmetric_CBC cbc; + const auto des3 = find_cipher("3des"); + + cbc_start(des3, cs(iv.data()), cs(key.data()), static_cast(key.size()), 0, &cbc); + cbc_decrypt(cs(data.data()), cs(dec_data.data()), ul(data.size()), &cbc); + cbc_done(&cbc); + + return dec_data; + } + + std::string tiger::compute(const std::string& data, const bool hex) + { + return compute(cs(data.data()), data.size(), hex); + } + + std::string tiger::compute(const uint8_t* data, const size_t length, const bool hex) + { + uint8_t buffer[24] = {0}; + + hash_state state; + tiger_init(&state); + tiger_process(&state, data, ul(length)); + tiger_done(&state, buffer); + + std::string hash(cs(buffer), sizeof(buffer)); + if (!hex) return hash; + + return string::dump_hex(hash, ""); + } + + std::string aes::encrypt(const std::string& data, const std::string& iv, const std::string& key) + { + std::string aligned_data = data; + const auto mod = aligned_data.size() % 16; + if (mod != 0) + { + aligned_data.resize(aligned_data.size() + (16 - mod)); + } + + std::string enc_data; + enc_data.resize(aligned_data.size()); + + symmetric_CBC cbc; + const auto aes = find_cipher("aes"); + + cbc_start(aes, cs(iv.data()), cs(key.data()), + static_cast(key.size()), 0, &cbc); + cbc_encrypt(cs(aligned_data.data()), + cs(enc_data.data()), + ul(aligned_data.size()), &cbc); + cbc_done(&cbc); + + return enc_data; + } + + std::string aes::decrypt(const std::string& data, const std::string& iv, const std::string& key) + { + std::string dec_data; + dec_data.resize(data.size()); + + symmetric_CBC cbc; + const auto aes = find_cipher("aes"); + + cbc_start(aes, cs(iv.data()), cs(key.data()), + static_cast(key.size()), 0, &cbc); + cbc_decrypt(cs(data.data()), + cs(dec_data.data()), + ul(data.size()), &cbc); + cbc_done(&cbc); + + return dec_data; + } + + std::string hmac_sha1::compute(const std::string& data, const std::string& key) + { + std::string buffer; + buffer.resize(20); + + hmac_state state; + hmac_init(&state, find_hash("sha1"), cs(key.data()), ul(key.size())); + hmac_process(&state, cs(data.data()), static_cast(data.size())); + + auto out_len = ul(buffer.size()); + hmac_done(&state, cs(buffer.data()), &out_len); + + buffer.resize(out_len); + return buffer; + } + + std::string sha1::compute(const std::string& data, const bool hex) + { + return compute(cs(data.data()), data.size(), hex); + } + + std::string sha1::compute(const uint8_t* data, const size_t length, const bool hex) + { + uint8_t buffer[20] = {0}; + + hash_state state; + sha1_init(&state); + sha1_process(&state, data, ul(length)); + sha1_done(&state, buffer); + + std::string hash(cs(buffer), sizeof(buffer)); + if (!hex) return hash; + + return string::dump_hex(hash, ""); + } + + std::string sha256::compute(const std::string& data, const bool hex) + { + return compute(cs(data.data()), data.size(), hex); + } + + std::string sha256::compute(const uint8_t* data, const size_t length, const bool hex) + { + uint8_t buffer[32] = {0}; + + hash_state state; + sha256_init(&state); + sha256_process(&state, data, ul(length)); + sha256_done(&state, buffer); + + std::string hash(cs(buffer), sizeof(buffer)); + if (!hex) return hash; + + return string::dump_hex(hash, ""); + } + + std::string sha512::compute(const std::string& data, const bool hex) + { + return compute(cs(data.data()), data.size(), hex); + } + + std::string sha512::compute(const uint8_t* data, const size_t length, const bool hex) + { + uint8_t buffer[64] = {0}; + + hash_state state; + sha512_init(&state); + sha512_process(&state, data, ul(length)); + sha512_done(&state, buffer); + + std::string hash(cs(buffer), sizeof(buffer)); + if (!hex) return hash; + + return string::dump_hex(hash, ""); + } + + namespace md5 + { + std::string compute(const std::string& data, bool hex) + { + return compute(cs(data.data()), data.size(), hex); + } + + std::string compute(const uint8_t* data, size_t length, bool hex) + { + uint8_t buffer[16] = {0}; + + hash_state state; + md5_init(&state); + md5_process(&state, data, ul(length)); + md5_done(&state, buffer); + + std::string hash(cs(buffer), sizeof(buffer)); + if (!hex) return hash; + + return string::dump_hex(hash, ""); + } + } + + std::string base64::encode(const uint8_t* data, const size_t len) + { + std::string result; + result.resize((len + 2) * 2); + + auto out_len = ul(result.size()); + if (base64_encode(data, ul(len), result.data(), &out_len) != CRYPT_OK) + { + return {}; + } + + result.resize(out_len); + return result; + } + + std::string base64::encode(const std::string& data) + { + return base64::encode(cs(data.data()), static_cast(data.size())); + } + + std::string base64::decode(const std::string& data) + { + std::string result; + result.resize((data.size() + 2) * 2); + + auto out_len = ul(result.size()); + if (base64_decode(data.data(), ul(data.size()), cs(result.data()), &out_len) != CRYPT_OK) + { + return {}; + } + + result.resize(out_len); + return result; + } + + unsigned int jenkins_one_at_a_time::compute(const std::string& data) + { + return compute(data.data(), data.size()); + } + + unsigned int jenkins_one_at_a_time::compute(const char* key, const size_t len) + { + unsigned int hash, i; + for (hash = i = 0; i < len; ++i) + { + hash += key[i]; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + hash += (hash << 15); + return hash; + } + + uint32_t random::get_integer() + { + uint32_t result; + random::get_data(&result, sizeof(result)); + return result; + } + + uint32_t random::get_integer(const std::uint32_t min, const std::uint32_t max) + { + const auto range = max - min + 1; + const auto value = random::get_integer(); + return value % range + min; + } + + std::string random::get_challenge() + { + std::string result; + result.resize(sizeof(uint32_t)); + random::get_data(result.data(), result.size()); + return string::dump_hex(result, ""); + } + + void random::get_data(void* data, const size_t size) + { + prng_.read(data, size); + } + + std::string random::get_data(const size_t size) + { + std::string data; + data.resize(size); + random::get_data(data.data(), size); + return data; + } +} + +#pragma warning(pop) diff --git a/src/utils/cryptography.hpp b/src/utils/cryptography.hpp new file mode 100644 index 0000000..01409a7 --- /dev/null +++ b/src/utils/cryptography.hpp @@ -0,0 +1,151 @@ +#pragma once + +#include +#include +#include "string.hpp" + +namespace utils::cryptography +{ + namespace ecc + { + class key final + { + public: + key(); + ~key(); + + key(key&& obj) noexcept; + key(const key& obj); + key& operator=(key&& obj) noexcept; + key& operator=(const key& obj); + + bool is_valid() const; + + ecc_key& get(); + const ecc_key& get() const; + + std::string get_public_key() const; + + void set(const std::string& pub_key_buffer); + + void deserialize(const std::string& key); + + std::string serialize(int type = PK_PRIVATE) const; + + void free(); + + bool operator==(key& key) const; + + uint64_t get_hash() const; + + private: + ecc_key key_storage_{}; + }; + + key generate_key(int bits); + key generate_key(int bits, const std::string& entropy); + std::string sign_message(const key& key, const std::string& message); + bool verify_message(const key& key, const std::string& message, const std::string& signature); + + bool encrypt(const key& key, std::string& data); + bool decrypt(const key& key, std::string& data); + } + + namespace rsa + { + std::string encrypt(const std::string& data, const std::string& hash, const std::string& key); + std::string decrypt(const std::string& data, const std::string& hash, const std::string& key); + } + + namespace des3 + { + std::string encrypt(const std::string& data, const std::string& iv, const std::string& key); + std::string decrypt(const std::string& data, const std::string& iv, const std::string& key); + } + + namespace tiger + { + std::string compute(const std::string& data, bool hex = false); + std::string compute(const uint8_t* data, size_t length, bool hex = false); + } + + namespace aes + { + std::string encrypt(const std::string& data, const std::string& iv, const std::string& key); + std::string decrypt(const std::string& data, const std::string& iv, const std::string& key); + } + + namespace hmac_sha1 + { + std::string compute(const std::string& data, const std::string& key); + } + + namespace sha1 + { + std::string compute(const std::string& data, bool hex = false); + std::string compute(const uint8_t* data, size_t length, bool hex = false); + } + + namespace sha256 + { + std::string compute(const std::string& data, bool hex = false); + std::string compute(const uint8_t* data, size_t length, bool hex = false); + } + + namespace sha512 + { + std::string compute(const std::string& data, bool hex = false); + std::string compute(const uint8_t* data, size_t length, bool hex = false); + } + + namespace md5 + { + std::string compute(const std::string& data, bool hex = false); + std::string compute(const uint8_t* data, size_t length, bool hex = false); + } + + namespace argon2 + { + template + std::string compute(const std::string& data, bool hex = false) + { + std::uint8_t buffer[HashLen]{}; + std::uint8_t salt[SaltLen]{}; + + argon2i_hash_raw(TCost, MCost, Threads, data.data(), data.size(), salt, SaltLen, buffer, HashLen); + + const auto str = std::string{reinterpret_cast(buffer), HashLen}; + if (hex) + { + return string::dump_hex(str, "", false); + } + else + { + return str; + } + } + } + + namespace base64 + { + std::string encode(const uint8_t* data, size_t len); + std::string encode(const std::string& data); + std::string decode(const std::string& data); + } + + namespace jenkins_one_at_a_time + { + unsigned int compute(const std::string& data); + unsigned int compute(const char* key, size_t len); + }; + + namespace random + { + uint32_t get_integer(); + uint32_t get_integer(const std::uint32_t min, const std::uint32_t max); + std::string get_challenge(); + void get_data(void* data, size_t size); + std::string get_data(const size_t size); + } +} diff --git a/src/utils/http.cpp b/src/utils/http.cpp index 3cee86d..9caa373 100644 --- a/src/utils/http.cpp +++ b/src/utils/http.cpp @@ -9,32 +9,6 @@ namespace utils::http { namespace { - struct progress_helper - { - const std::function* callback{}; - std::exception_ptr exception{}; - }; - - int progress_callback(void* clientp, const curl_off_t /*dltotal*/, const curl_off_t dlnow, const curl_off_t /*ultotal*/, const curl_off_t /*ulnow*/) - { - auto* helper = static_cast(clientp); - - try - { - if (*helper->callback) - { - (*helper->callback)(static_cast(dlnow)); - } - } - catch (...) - { - helper->exception = std::current_exception(); - return -1; - } - - return 0; - } - size_t write_callback(void* contents, const size_t size, const size_t nmemb, void* userp) { const auto buffer = static_cast(userp); @@ -102,4 +76,4 @@ namespace utils::http return result; } } -} \ No newline at end of file +} diff --git a/src/utils/http.hpp b/src/utils/http.hpp index c2eae3f..8a481ad 100644 --- a/src/utils/http.hpp +++ b/src/utils/http.hpp @@ -2,7 +2,6 @@ #include #include -#include #include @@ -18,4 +17,4 @@ namespace utils::http std::optional get_data(const std::string& url, const std::string& fields = {}, const headers& headers = {}, const std::string& method = {}); -} \ No newline at end of file +}