mirror of
https://github.com/diamante0018/MW3ServerFreezer.git
synced 2025-05-09 14:04:54 +00:00
use protocol buffers to do something cool
This commit is contained in:
parent
210da7c6a5
commit
d8919ba684
@ -1,5 +1,4 @@
|
|||||||
|
---
|
||||||
---
|
|
||||||
Language: Cpp
|
Language: Cpp
|
||||||
BasedOnStyle: LLVM
|
BasedOnStyle: LLVM
|
||||||
DerivePointerAlignment: false
|
DerivePointerAlignment: false
|
||||||
@ -10,3 +9,5 @@ SortIncludes: false
|
|||||||
IncludeBlocks: Preserve
|
IncludeBlocks: Preserve
|
||||||
|
|
||||||
---
|
---
|
||||||
|
Language: Proto
|
||||||
|
BasedOnStyle: Google
|
||||||
|
10
.gitmodules
vendored
10
.gitmodules
vendored
@ -1,3 +1,13 @@
|
|||||||
[submodule "deps/GSL"]
|
[submodule "deps/GSL"]
|
||||||
path = deps/GSL
|
path = deps/GSL
|
||||||
url = https://github.com/microsoft/GSL.git
|
url = https://github.com/microsoft/GSL.git
|
||||||
|
[submodule "deps/libtomcrypt"]
|
||||||
|
path = deps/libtomcrypt
|
||||||
|
url = https://github.com/libtom/libtomcrypt.git
|
||||||
|
[submodule "deps/libtommath"]
|
||||||
|
path = deps/libtommath
|
||||||
|
url = https://github.com/libtom/libtommath.git
|
||||||
|
[submodule "deps/protobuf"]
|
||||||
|
path = deps/protobuf
|
||||||
|
url = https://github.com/google/protobuf.git
|
||||||
|
branch = 3.20.x
|
||||||
|
1
deps/libtomcrypt
vendored
Submodule
1
deps/libtomcrypt
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit ddfe2e8aa7c4239463a8a1d26724aef123333549
|
1
deps/libtommath
vendored
Submodule
1
deps/libtommath
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 4b47368501321c795d5b54d87a5bab35a21a7940
|
61
deps/premake/libtomcrypt.lua
vendored
Normal file
61
deps/premake/libtomcrypt.lua
vendored
Normal file
@ -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)
|
52
deps/premake/libtommath.lua
vendored
Normal file
52
deps/premake/libtommath.lua
vendored
Normal file
@ -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)
|
60
deps/premake/protobuf.lua
vendored
Normal file
60
deps/premake/protobuf.lua
vendored
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
protobuf = {
|
||||||
|
source = path.join(dependencies.basePath, "protobuf"),
|
||||||
|
}
|
||||||
|
|
||||||
|
function protobuf.import()
|
||||||
|
links {
|
||||||
|
"protobuf"
|
||||||
|
}
|
||||||
|
|
||||||
|
protobuf.includes()
|
||||||
|
end
|
||||||
|
|
||||||
|
function protobuf.includes()
|
||||||
|
includedirs {
|
||||||
|
path.join(protobuf.source, "src"),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function protobuf.project()
|
||||||
|
project "protobuf"
|
||||||
|
language "C++"
|
||||||
|
|
||||||
|
protobuf.includes()
|
||||||
|
|
||||||
|
files {
|
||||||
|
path.join(protobuf.source, "src/**.cc"),
|
||||||
|
"./src/**.proto",
|
||||||
|
}
|
||||||
|
|
||||||
|
removefiles {
|
||||||
|
path.join(protobuf.source, "src/**/*test.cc"),
|
||||||
|
path.join(protobuf.source, "src/google/protobuf/*test*.cc"),
|
||||||
|
|
||||||
|
path.join(protobuf.source, "src/google/protobuf/testing/**.cc"),
|
||||||
|
path.join(protobuf.source, "src/google/protobuf/compiler/**.cc"),
|
||||||
|
|
||||||
|
path.join(protobuf.source, "src/google/protobuf/arena_nc.cc"),
|
||||||
|
path.join(protobuf.source, "src/google/protobuf/util/internal/error_listener.cc"),
|
||||||
|
path.join(protobuf.source, "**/*_gcc.cc"),
|
||||||
|
}
|
||||||
|
|
||||||
|
rules {
|
||||||
|
"ProtobufCompiler"
|
||||||
|
}
|
||||||
|
|
||||||
|
defines {
|
||||||
|
"_SCL_SECURE_NO_WARNINGS",
|
||||||
|
"_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS",
|
||||||
|
"_SILENCE_ALL_CXX20_DEPRECATION_WARNINGS",
|
||||||
|
}
|
||||||
|
|
||||||
|
linkoptions {
|
||||||
|
"-IGNORE:4221"
|
||||||
|
}
|
||||||
|
|
||||||
|
warnings "Off"
|
||||||
|
kind "StaticLib"
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(dependencies, protobuf)
|
1
deps/protobuf
vendored
Submodule
1
deps/protobuf
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 50bdb17409d4133d51ab6cfa095700f4c816576e
|
11
premake5.lua
11
premake5.lua
@ -31,6 +31,7 @@ end
|
|||||||
dependencies.load()
|
dependencies.load()
|
||||||
|
|
||||||
workspace "mw3-server-freezer"
|
workspace "mw3-server-freezer"
|
||||||
|
startproject "client"
|
||||||
location "./build"
|
location "./build"
|
||||||
objdir "%{wks.location}/obj"
|
objdir "%{wks.location}/obj"
|
||||||
targetdir "%{wks.location}/bin/%{cfg.platform}/%{cfg.buildcfg}"
|
targetdir "%{wks.location}/bin/%{cfg.platform}/%{cfg.buildcfg}"
|
||||||
@ -104,3 +105,13 @@ dependencies.imports()
|
|||||||
|
|
||||||
group "Dependencies"
|
group "Dependencies"
|
||||||
dependencies.projects()
|
dependencies.projects()
|
||||||
|
|
||||||
|
rule "ProtobufCompiler"
|
||||||
|
display "Protobuf compiler"
|
||||||
|
location "./build"
|
||||||
|
fileExtension ".proto"
|
||||||
|
buildmessage "Compiling %(Identity) with protoc..."
|
||||||
|
buildcommands {'@echo off', 'path "$(SolutionDir)\\..\\tools"',
|
||||||
|
'if not exist "$(ProjectDir)\\src\\proto" mkdir "$(ProjectDir)\\src\\proto"',
|
||||||
|
'protoc --error_format=msvs -I=%(RelativeDir) --cpp_out=src\\proto %(Identity)'}
|
||||||
|
buildoutputs {'$(ProjectDir)\\src\\proto\\%(Filename).pb.cc', '$(ProjectDir)\\src\\proto\\%(Filename).pb.h'}
|
||||||
|
62
src/client/component/crypto_key.cpp
Normal file
62
src/client/component/crypto_key.cpp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
|
||||||
|
#include "crypto_key.hpp"
|
||||||
|
#include "console.hpp"
|
||||||
|
|
||||||
|
#include <utils/io.hpp>
|
||||||
|
|
||||||
|
namespace crypto_key {
|
||||||
|
namespace {
|
||||||
|
bool load_key(utils::cryptography::ecc::key& key) {
|
||||||
|
std::string data{};
|
||||||
|
if (!utils::io::read_file("./private.key", &data)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
key.deserialize(data);
|
||||||
|
if (!key.is_valid()) {
|
||||||
|
console::info("Loaded key is invalid!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::cryptography::ecc::key generate_key() {
|
||||||
|
auto key = utils::cryptography::ecc::generate_key(512);
|
||||||
|
if (!key.is_valid()) {
|
||||||
|
throw std::runtime_error("Failed to generate server key!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!utils::io::write_file("./private.key", key.serialize())) {
|
||||||
|
throw std::runtime_error("Failed to write server key!");
|
||||||
|
}
|
||||||
|
|
||||||
|
console::info("Generated cryptographic key: {}", key.get_hash());
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::cryptography::ecc::key load_or_generate_key() {
|
||||||
|
utils::cryptography::ecc::key key{};
|
||||||
|
if (load_key(key)) {
|
||||||
|
console::info("Loaded cryptographic key: {}", key.get_hash());
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
return generate_key();
|
||||||
|
}
|
||||||
|
|
||||||
|
utils::cryptography::ecc::key get_key_internal() {
|
||||||
|
auto key = load_or_generate_key();
|
||||||
|
if (!utils::io::write_file("./public.key", key.get_public_key())) {
|
||||||
|
console::info("Failed to write public key!");
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
const utils::cryptography::ecc::key& get() {
|
||||||
|
static auto key = get_key_internal();
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
} // namespace crypto_key
|
7
src/client/component/crypto_key.hpp
Normal file
7
src/client/component/crypto_key.hpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "utils/cryptography.hpp"
|
||||||
|
|
||||||
|
namespace crypto_key {
|
||||||
|
const utils::cryptography::ecc::key& get();
|
||||||
|
}
|
@ -1,8 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
namespace network {
|
|
||||||
using callback =
|
|
||||||
std::function<void(const game::netadr_s&, const std::string_view&)>;
|
|
||||||
|
|
||||||
void on_packet(const std::string& command, const callback& callback);
|
|
||||||
} // namespace network
|
|
@ -1,15 +1,17 @@
|
|||||||
#include <std_include.hpp>
|
#include <std_include.hpp>
|
||||||
#include "../loader/component_loader.hpp"
|
#include "../../loader/component_loader.hpp"
|
||||||
|
|
||||||
#include <utils/hook.hpp>
|
#include <utils/hook.hpp>
|
||||||
#include <utils/string.hpp>
|
#include <utils/string.hpp>
|
||||||
|
|
||||||
|
#include "../console.hpp"
|
||||||
|
|
||||||
#include "network.hpp"
|
#include "network.hpp"
|
||||||
|
|
||||||
namespace network {
|
namespace network {
|
||||||
namespace {
|
namespace {
|
||||||
std::unordered_map<std::string, network::callback>& get_callbacks() {
|
std::unordered_map<std::string, callback>& get_callbacks() {
|
||||||
static std::unordered_map<std::string, network::callback> network_callbacks{};
|
static std::unordered_map<std::string, callback> network_callbacks{};
|
||||||
return network_callbacks;
|
return network_callbacks;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,7 +34,6 @@ bool handle_command(game::netadr_s* address, const char* command,
|
|||||||
handler->second(*address, data);
|
handler->second(*address, data);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} // namespace
|
|
||||||
|
|
||||||
int packet_interception_handler(game::netadr_s* from, const char* command,
|
int packet_interception_handler(game::netadr_s* from, const char* command,
|
||||||
game::msg_t* message) {
|
game::msg_t* message) {
|
||||||
@ -42,12 +43,61 @@ int packet_interception_handler(game::netadr_s* from, const char* command,
|
|||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void send(const game::netadr_s& address, const std::string& command,
|
||||||
|
const std::string& data, const char separator) {
|
||||||
|
std::string packet = "\xFF\xFF\xFF\xFF";
|
||||||
|
packet.append(command);
|
||||||
|
packet.push_back(separator);
|
||||||
|
packet.append(data);
|
||||||
|
|
||||||
|
send_data(address, packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
void send_data(const game::netadr_s& address, const std::string& data) {
|
||||||
|
auto size = static_cast<int>(data.size());
|
||||||
|
|
||||||
|
if (address.type == game::NA_LOOPBACK) {
|
||||||
|
// TODO: Fix this for loopback
|
||||||
|
if (size > 1280) {
|
||||||
|
console::info("Packet was too long. Truncated!\n");
|
||||||
|
size = 1280;
|
||||||
|
}
|
||||||
|
|
||||||
|
game::NET_SendLoopPacket(game::NS_CLIENT1, size, data.data(), address);
|
||||||
|
} else {
|
||||||
|
game::Sys_SendPacket(size, data.data(), address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void on_packet(const std::string& command, const callback& callback) {
|
void on_packet(const std::string& command, const callback& callback) {
|
||||||
get_callbacks()[utils::string::to_lower(command)] = callback;
|
get_callbacks()[utils::string::to_lower(command)] = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
class component final : public component_interface {
|
const char* net_adr_to_string(const game::netadr_s& a) {
|
||||||
|
if (a.type == game::netadrtype_t::NA_LOOPBACK) {
|
||||||
|
return "loopback";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a.type == game::netadrtype_t::NA_BOT) {
|
||||||
|
return "bot";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a.type == game::netadrtype_t::NA_IP ||
|
||||||
|
a.type == game::netadrtype_t::NA_BROADCAST) {
|
||||||
|
if (a.port) {
|
||||||
|
return utils::string::va("%u.%u.%u.%u:%u", a.ip[0], a.ip[1], a.ip[2],
|
||||||
|
a.ip[3], htons(a.port));
|
||||||
|
}
|
||||||
|
|
||||||
|
return utils::string::va("%u.%u.%u.%u", a.ip[0], a.ip[1], a.ip[2], a.ip[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "bad";
|
||||||
|
}
|
||||||
|
|
||||||
|
class network final : public component_interface {
|
||||||
public:
|
public:
|
||||||
void post_unpack() override {
|
void post_unpack() override {
|
||||||
add_network_commands();
|
add_network_commands();
|
||||||
@ -67,4 +117,4 @@ private:
|
|||||||
};
|
};
|
||||||
} // namespace network
|
} // namespace network
|
||||||
|
|
||||||
REGISTER_COMPONENT(network::component)
|
REGISTER_COMPONENT(network::network)
|
13
src/client/component/network/network.hpp
Normal file
13
src/client/component/network/network.hpp
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace network {
|
||||||
|
void send(const game::netadr_s& address, const std::string& command,
|
||||||
|
const std::string& data = {}, char separator = ' ');
|
||||||
|
void send_data(const game::netadr_s& address, const std::string& data);
|
||||||
|
|
||||||
|
using callback =
|
||||||
|
std::function<void(const game::netadr_s&, const std::string_view&)>;
|
||||||
|
void on_packet(const std::string& command, const callback& callback);
|
||||||
|
|
||||||
|
const char* net_adr_to_string(const game::netadr_s& a);
|
||||||
|
} // namespace network
|
54
src/client/component/rcon.cpp
Normal file
54
src/client/component/rcon.cpp
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "../loader/component_loader.hpp"
|
||||||
|
|
||||||
|
#include <utils/cryptography.hpp>
|
||||||
|
|
||||||
|
#include "network/network.hpp"
|
||||||
|
|
||||||
|
#include "crypto_key.hpp"
|
||||||
|
#include "key_catcher.hpp"
|
||||||
|
|
||||||
|
#include <proto/rcon.pb.h>
|
||||||
|
|
||||||
|
namespace rcon {
|
||||||
|
namespace {
|
||||||
|
utils::cryptography::ecc::key key;
|
||||||
|
std::string commands;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
class component final : public component_interface {
|
||||||
|
public:
|
||||||
|
void post_unpack() override {
|
||||||
|
key = crypto_key::get();
|
||||||
|
add_key_hooks();
|
||||||
|
add_commands();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void add_key_hooks() {
|
||||||
|
// Why commands don't work? I don't know!
|
||||||
|
key_catcher::on_key_press(
|
||||||
|
"7", []([[maybe_unused]] const game::LocalClientNum_t& local_client) {
|
||||||
|
commands = "quit";
|
||||||
|
network::send(game::localClientConnection->serverAddress,
|
||||||
|
"rcon_request");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_commands() {
|
||||||
|
network::on_packet("rcon_authorization", [](const game::netadr_s& adr,
|
||||||
|
const std::string_view& data) {
|
||||||
|
const auto signed_msg =
|
||||||
|
utils::cryptography::ecc::sign_message(key, std::string(data));
|
||||||
|
|
||||||
|
proto::rcon::command info;
|
||||||
|
info.set_commands(commands);
|
||||||
|
info.set_signature(signed_msg);
|
||||||
|
|
||||||
|
network::send(adr, "rcon_execute", info.SerializeAsString());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} // namespace rcon
|
||||||
|
|
||||||
|
REGISTER_COMPONENT(rcon::component)
|
@ -69,7 +69,7 @@ struct netadr_s {
|
|||||||
unsigned int addrHandleIndex;
|
unsigned int addrHandleIndex;
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(sizeof(netadr_s) == 24);
|
static_assert(sizeof(netadr_s) == 0x18);
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ERR_FATAL = 0x0,
|
ERR_FATAL = 0x0,
|
||||||
|
@ -54,7 +54,9 @@ WEAK symbol<bool(netsrc_t, netadr_s dest, unsigned char* data, int size)>
|
|||||||
WEAK symbol<void(netadr_s*, sockaddr*)> NetadrToSockadr{0x48B460};
|
WEAK symbol<void(netadr_s*, sockaddr*)> NetadrToSockadr{0x48B460};
|
||||||
WEAK symbol<int(const char* serverName, netadr_s serverRemote)> NET_StringToAdr{
|
WEAK symbol<int(const char* serverName, netadr_s serverRemote)> NET_StringToAdr{
|
||||||
0x4E09A0};
|
0x4E09A0};
|
||||||
WEAK symbol<SOCKET> query_socket{0x5A861EC};
|
WEAK symbol<bool(int length, const void* voiddata, netadr_s to)> Sys_SendPacket{0x5145C0};
|
||||||
|
WEAK symbol<void(netsrc_t sock, int length, const void* data, netadr_s to)> NET_SendLoopPacket{0x4B9DF0};
|
||||||
|
|
||||||
WEAK symbol<void()> Com_Quit_f{0x556060};
|
WEAK symbol<void()> Com_Quit_f{0x556060};
|
||||||
|
|
||||||
WEAK symbol<void(const msg_t*, unsigned char*, int)> MSG_Init{0x40E030};
|
WEAK symbol<void(const msg_t*, unsigned char*, int)> MSG_Init{0x40E030};
|
||||||
@ -74,11 +76,6 @@ WEAK symbol<int(unsigned __int64, const void*, unsigned int)>
|
|||||||
WEAK symbol<XAssetHeader(int type, const char* name, int allowCreateDefault)>
|
WEAK symbol<XAssetHeader(int type, const char* name, int allowCreateDefault)>
|
||||||
DB_FindXAssetHeader{0x4B25C0};
|
DB_FindXAssetHeader{0x4B25C0};
|
||||||
|
|
||||||
WEAK symbol<void(const char* text, int maxChars, Font_s* font, float x, float y,
|
|
||||||
float xScale, float yScale, float rotation, const float* color,
|
|
||||||
int style)>
|
|
||||||
R_AddCmdDrawText{0x42C970};
|
|
||||||
|
|
||||||
// Variables
|
// Variables
|
||||||
WEAK symbol<CmdArgs> cmd_args{0x1C96850};
|
WEAK symbol<CmdArgs> cmd_args{0x1C96850};
|
||||||
WEAK symbol<PlayerKeyState> playerKeys{0xB3A38C};
|
WEAK symbol<PlayerKeyState> playerKeys{0xB3A38C};
|
||||||
|
8
src/client/proto/rcon.proto
Normal file
8
src/client/proto/rcon.proto
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package proto.rcon;
|
||||||
|
|
||||||
|
message command {
|
||||||
|
bytes commands = 1;
|
||||||
|
bytes signature = 2;
|
||||||
|
}
|
@ -1 +1,11 @@
|
|||||||
#include "std_include.hpp"
|
#include "std_include.hpp"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
int s_read_arc4random(void*, std::size_t) { return -1; }
|
||||||
|
|
||||||
|
int s_read_getrandom(void*, std::size_t) { return -1; }
|
||||||
|
|
||||||
|
int s_read_urandom(void*, std::size_t) { return -1; }
|
||||||
|
|
||||||
|
int s_read_ltm_rng(void*, std::size_t) { return -1; }
|
||||||
|
}
|
||||||
|
@ -4,8 +4,10 @@
|
|||||||
|
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
#include <WinSock2.h>
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
#include <WinSock2.h>
|
||||||
|
#include <WS2tcpip.h>
|
||||||
|
|
||||||
#include <corecrt_io.h>
|
#include <corecrt_io.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
@ -15,10 +17,12 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
#include <source_location>
|
#include <source_location>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
#pragma comment(lib, "ntdll.lib")
|
#pragma comment(lib, "ntdll.lib")
|
||||||
|
#pragma comment(lib, "ws2_32.lib")
|
||||||
|
|
||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
|
|
||||||
|
556
src/common/utils/cryptography.cpp
Normal file
556
src/common/utils/cryptography.cpp
Normal file
@ -0,0 +1,556 @@
|
|||||||
|
#include "string.hpp"
|
||||||
|
#include "cryptography.hpp"
|
||||||
|
#include "nt.hpp"
|
||||||
|
|
||||||
|
#include <gsl/gsl>
|
||||||
|
|
||||||
|
#undef max
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
|
/// http://www.opensource.apple.com/source/CommonCrypto/CommonCrypto-55010/Source/libtomcrypt/doc/libTomCryptDoc.pdf
|
||||||
|
|
||||||
|
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 std::uint8_t* data) {
|
||||||
|
return reinterpret_cast<const char*>(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[maybe_unused]] char* cs(std::uint8_t* data) {
|
||||||
|
return reinterpret_cast<char*>(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[maybe_unused]] const std::uint8_t* cs(const char* data) {
|
||||||
|
return reinterpret_cast<const std::uint8_t*>(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[maybe_unused]] std::uint8_t* cs(char* data) {
|
||||||
|
return reinterpret_cast<std::uint8_t*>(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[maybe_unused]] unsigned long ul(const std::size_t value) {
|
||||||
|
return static_cast<unsigned long>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
class prng {
|
||||||
|
public:
|
||||||
|
prng(const ltc_prng_descriptor& descriptor, const bool autoseed = true)
|
||||||
|
: state_(std::make_unique<prng_state>()), 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()); }
|
||||||
|
|
||||||
|
[[nodiscard]] prng_state* get_state() const {
|
||||||
|
this->descriptor_.ready(this->state_.get());
|
||||||
|
return this->state_.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] int get_id() const { return this->id_; }
|
||||||
|
|
||||||
|
void add_entropy(const void* data, const std::size_t length) const {
|
||||||
|
this->descriptor_.add_entropy(static_cast<const std::uint8_t*>(data),
|
||||||
|
ul(length), this->state_.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
void read(void* data, const std::size_t length) const {
|
||||||
|
this->descriptor_.read(static_cast<std::uint8_t*>(data), ul(length),
|
||||||
|
this->get_state());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int id_;
|
||||||
|
std::unique_ptr<prng_state> 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<std::uint8_t*>(&i), sizeof(i));
|
||||||
|
this->add_entropy(reinterpret_cast<std::uint8_t*>(&i_ptr), sizeof(i_ptr));
|
||||||
|
|
||||||
|
auto t = time(nullptr);
|
||||||
|
this->add_entropy(reinterpret_cast<std::uint8_t*>(&t), sizeof(t));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const prng prng_(fortuna_desc);
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
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::operator==(key& key) const {
|
||||||
|
return (this->is_valid() && key.is_valid() &&
|
||||||
|
this->serialize(PK_PUBLIC) == key.serialize(PK_PUBLIC));
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
std::uint8_t buffer[512] = {0};
|
||||||
|
unsigned long length = sizeof(buffer);
|
||||||
|
|
||||||
|
if (ecc_ansi_x963_export(&this->key_storage_, buffer, &length) == CRYPT_OK) {
|
||||||
|
return {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 {
|
||||||
|
std::uint8_t buffer[4096] = {0};
|
||||||
|
unsigned long length = sizeof(buffer);
|
||||||
|
|
||||||
|
if (ecc_export(buffer, &length, type, &this->key_storage_) == CRYPT_OK) {
|
||||||
|
return {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_));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint64_t ecc::key::get_hash() const {
|
||||||
|
const auto hash = sha1::compute(this->get_public_key());
|
||||||
|
if (hash.size() >= 8) {
|
||||||
|
return *reinterpret_cast<const std::uint64_t*>(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 {};
|
||||||
|
|
||||||
|
std::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 {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(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"), &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<int>(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<int>(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) {
|
||||||
|
std::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 enc_data;
|
||||||
|
enc_data.resize(data.size());
|
||||||
|
|
||||||
|
symmetric_CBC cbc;
|
||||||
|
const auto aes = find_cipher("aes");
|
||||||
|
|
||||||
|
cbc_start(aes, cs(iv.data()), cs(key.data()), static_cast<int>(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 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<int>(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<int>(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 std::uint8_t* data, const std::size_t length,
|
||||||
|
const bool hex) {
|
||||||
|
std::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 std::uint8_t* data, const std::size_t length,
|
||||||
|
const bool hex) {
|
||||||
|
std::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 std::uint8_t* data, const std::size_t length,
|
||||||
|
const bool hex) {
|
||||||
|
std::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, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string base64::encode(const std::uint8_t* data, const std::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()), 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 std::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;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::uint32_t random::get_integer() {
|
||||||
|
std::uint32_t result;
|
||||||
|
random::get_data(&result, sizeof(result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string random::get_challenge() {
|
||||||
|
std::string result;
|
||||||
|
result.resize(sizeof(std::uint32_t));
|
||||||
|
random::get_data(result.data(), result.size());
|
||||||
|
return string::dump_hex(result, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
void random::get_data(void* data, const std::size_t size) {
|
||||||
|
prng_.read(data, size);
|
||||||
|
}
|
||||||
|
} // namespace utils::cryptography
|
113
src/common/utils/cryptography.hpp
Normal file
113
src/common/utils/cryptography.hpp
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <tomcrypt.h>
|
||||||
|
|
||||||
|
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 operator==(key& key) const;
|
||||||
|
|
||||||
|
[[nodiscard]] bool is_valid() const;
|
||||||
|
|
||||||
|
ecc_key& get();
|
||||||
|
[[nodiscard]] const ecc_key& get() const;
|
||||||
|
|
||||||
|
[[nodiscard]] std::string get_public_key() const;
|
||||||
|
|
||||||
|
void set(const std::string& pub_key_buffer);
|
||||||
|
|
||||||
|
void deserialize(const std::string& key);
|
||||||
|
|
||||||
|
[[nodiscard]] std::string serialize(int type = PK_PRIVATE) const;
|
||||||
|
|
||||||
|
void free();
|
||||||
|
|
||||||
|
[[nodiscard]] std::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 ecc
|
||||||
|
|
||||||
|
namespace rsa {
|
||||||
|
std::string encrypt(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 des3
|
||||||
|
|
||||||
|
namespace tiger {
|
||||||
|
std::string compute(const std::string& data, bool hex = false);
|
||||||
|
std::string compute(const std::uint8_t* data, std::size_t length,
|
||||||
|
bool hex = false);
|
||||||
|
} // namespace tiger
|
||||||
|
|
||||||
|
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 aes
|
||||||
|
|
||||||
|
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 std::uint8_t* data, std::size_t length,
|
||||||
|
bool hex = false);
|
||||||
|
} // namespace sha1
|
||||||
|
|
||||||
|
namespace sha256 {
|
||||||
|
std::string compute(const std::string& data, bool hex = false);
|
||||||
|
std::string compute(const std::uint8_t* data, std::size_t length,
|
||||||
|
bool hex = false);
|
||||||
|
} // namespace sha256
|
||||||
|
|
||||||
|
namespace sha512 {
|
||||||
|
std::string compute(const std::string& data, bool hex = false);
|
||||||
|
std::string compute(const std::uint8_t* data, std::size_t length,
|
||||||
|
bool hex = false);
|
||||||
|
} // namespace sha512
|
||||||
|
|
||||||
|
namespace base64 {
|
||||||
|
std::string encode(const std::uint8_t* data, std::size_t len);
|
||||||
|
std::string encode(const std::string& data);
|
||||||
|
std::string decode(const std::string& data);
|
||||||
|
} // namespace base64
|
||||||
|
|
||||||
|
namespace jenkins_one_at_a_time {
|
||||||
|
unsigned int compute(const std::string& data);
|
||||||
|
unsigned int compute(const char* key, std::size_t len);
|
||||||
|
}; // namespace jenkins_one_at_a_time
|
||||||
|
|
||||||
|
namespace random {
|
||||||
|
std::uint32_t get_integer();
|
||||||
|
std::string get_challenge();
|
||||||
|
void get_data(void* data, std::size_t size);
|
||||||
|
} // namespace random
|
||||||
|
} // namespace utils::cryptography
|
109
src/common/utils/io.cpp
Normal file
109
src/common/utils/io.cpp
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
#include "io.hpp"
|
||||||
|
#include "nt.hpp"
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
namespace utils::io {
|
||||||
|
bool remove_file(const std::string& file) {
|
||||||
|
return DeleteFileA(file.data()) == TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool move_file(const std::string& src, const std::string& target) {
|
||||||
|
return MoveFileA(src.data(), target.data()) == TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool file_exists(const std::string& file) {
|
||||||
|
return std::filesystem::exists(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool write_file(const std::string& file, const std::string& data,
|
||||||
|
const bool append) {
|
||||||
|
const auto pos = file.find_last_of("/\\");
|
||||||
|
if (pos != std::string::npos) {
|
||||||
|
create_directory(file.substr(0, pos));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ofstream stream(file, std::ios::binary | std::ofstream::out |
|
||||||
|
(append ? std::ofstream::app : 0));
|
||||||
|
|
||||||
|
if (stream.is_open()) {
|
||||||
|
stream.write(data.data(), data.size());
|
||||||
|
stream.close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string read_file(const std::string& file) {
|
||||||
|
std::string data;
|
||||||
|
read_file(file, &data);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool read_file(const std::string& file, std::string* data) {
|
||||||
|
if (!data)
|
||||||
|
return false;
|
||||||
|
data->clear();
|
||||||
|
|
||||||
|
if (file_exists(file)) {
|
||||||
|
std::ifstream stream(file, std::ios::binary);
|
||||||
|
if (!stream.is_open())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
stream.seekg(0, std::ios::end);
|
||||||
|
const std::streamsize size = stream.tellg();
|
||||||
|
stream.seekg(0, std::ios::beg);
|
||||||
|
|
||||||
|
if (size > -1) {
|
||||||
|
data->resize(static_cast<uint32_t>(size));
|
||||||
|
stream.read(data->data(), size);
|
||||||
|
stream.close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t file_size(const std::string& file) {
|
||||||
|
if (file_exists(file)) {
|
||||||
|
std::ifstream stream(file, std::ios::binary);
|
||||||
|
|
||||||
|
if (stream.good()) {
|
||||||
|
stream.seekg(0, std::ios::end);
|
||||||
|
return static_cast<size_t>(stream.tellg());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool create_directory(const std::string& directory) {
|
||||||
|
return std::filesystem::create_directories(directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool directory_exists(const std::string& directory) {
|
||||||
|
return std::filesystem::is_directory(directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool directory_is_empty(const std::string& directory) {
|
||||||
|
return std::filesystem::is_empty(directory);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> list_files(const std::string& directory) {
|
||||||
|
std::vector<std::string> files;
|
||||||
|
|
||||||
|
for (auto& file : std::filesystem::directory_iterator(directory)) {
|
||||||
|
files.push_back(file.path().generic_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
|
|
||||||
|
void copy_folder(const std::filesystem::path& src,
|
||||||
|
const std::filesystem::path& target) {
|
||||||
|
std::filesystem::copy(src, target,
|
||||||
|
std::filesystem::copy_options::overwrite_existing |
|
||||||
|
std::filesystem::copy_options::recursive);
|
||||||
|
}
|
||||||
|
} // namespace utils::io
|
22
src/common/utils/io.hpp
Normal file
22
src/common/utils/io.hpp
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <filesystem>
|
||||||
|
|
||||||
|
namespace utils::io {
|
||||||
|
bool remove_file(const std::string& file);
|
||||||
|
bool move_file(const std::string& src, const std::string& target);
|
||||||
|
bool file_exists(const std::string& file);
|
||||||
|
bool write_file(const std::string& file, const std::string& data,
|
||||||
|
bool append = false);
|
||||||
|
bool read_file(const std::string& file, std::string* data);
|
||||||
|
std::string read_file(const std::string& file);
|
||||||
|
size_t file_size(const std::string& file);
|
||||||
|
bool create_directory(const std::string& directory);
|
||||||
|
bool directory_exists(const std::string& directory);
|
||||||
|
bool directory_is_empty(const std::string& directory);
|
||||||
|
std::vector<std::string> list_files(const std::string& directory);
|
||||||
|
void copy_folder(const std::filesystem::path& src,
|
||||||
|
const std::filesystem::path& target);
|
||||||
|
} // namespace utils::io
|
BIN
tools/protoc.exe
Normal file
BIN
tools/protoc.exe
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user