From b4d9b43a52854ddd782abdb8170e851f6903d0aa Mon Sep 17 00:00:00 2001 From: Benau Date: Sat, 1 Sep 2018 01:05:22 +0800 Subject: [PATCH] Use Nettle in linux if found --- CMakeLists.txt | 46 +++-- android/Android.mk | 1 + sources.cmake | 2 +- src/network/crypto.hpp | 138 +-------------- src/network/crypto_nettle.cpp | 141 +++++++++++++++ src/network/crypto_nettle.hpp | 151 +++++++++++++++++ .../{crypto.cpp => crypto_openssl.cpp} | 6 +- src/network/crypto_openssl.hpp | 160 ++++++++++++++++++ 8 files changed, 500 insertions(+), 145 deletions(-) create mode 100644 src/network/crypto_nettle.cpp create mode 100644 src/network/crypto_nettle.hpp rename src/network/{crypto.cpp => crypto_openssl.cpp} (98%) create mode 100644 src/network/crypto_openssl.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a028c745..159236e40 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,8 @@ option(USE_SYSTEM_ANGELSCRIPT "Use system angelscript instead of built-in angels option(USE_SYSTEM_ENET "Use system ENET instead of the built-in version, when available." ON) option(USE_SYSTEM_GLEW "Use system GLEW instead of the built-in version, when available." ON) +CMAKE_DEPENDENT_OPTION(USE_CRYPTO_OPENSSL "Use OpenSSL instead of Nettle for cryptography in STK." OFF + "NOT APPLE" ON) CMAKE_DEPENDENT_OPTION(BUILD_RECORDER "Build opengl recorder" ON "NOT SERVER_ONLY;NOT APPLE" OFF) CMAKE_DEPENDENT_OPTION(USE_FRIBIDI "Support for right-to-left languages" ON @@ -453,26 +455,45 @@ else() target_link_libraries(supertuxkart ${PTHREAD_LIBRARY}) endif() -# CURL and OpenSSL +# CURL and OpenSSL or Nettle # 1.0.1d for compatible AES GCM handling SET(OPENSSL_MINIMUM_VERSION "1.0.1d") if(MSVC) + set(USE_CRYPTO_OPENSSL ON) target_link_libraries(supertuxkart ${PROJECT_SOURCE_DIR}/${DEPENDENCIES}/lib/libcurl.lib) target_link_libraries(supertuxkart ${PROJECT_SOURCE_DIR}/${DEPENDENCIES}/lib/libeay32.lib) elseif(MINGW) + set(USE_CRYPTO_OPENSSL ON) target_link_libraries(supertuxkart ${PROJECT_SOURCE_DIR}/${DEPENDENCIES}/lib/libcurldll.a) target_link_libraries(supertuxkart ${PROJECT_SOURCE_DIR}/${DEPENDENCIES}/lib/libeay32.dll) else() find_package(CURL REQUIRED) - find_package(OpenSSL REQUIRED) - - if(${OPENSSL_VERSION} VERSION_LESS ${OPENSSL_MINIMUM_VERSION} OR - (${OPENSSL_VERSION} VERSION_EQUAL ${OPENSSL_MINIMUM_VERSION} AND ${OPENSSL_VERSION} STRLESS ${OPENSSL_MINIMUM_VERSION})) - message(FATAL_ERROR "OpenSSL version found (${OPENSSL_VERSION}) is less then the minimum required (${OPENSSL_MINIMUM_VERSION}), aborting.") - endif() - include_directories(${CURL_INCLUDE_DIRS}) - include_directories(${OpenSSL_INCLUDE_DIRS}) + + find_path(NETTLE_INCLUDE_DIRS nettle/gcm.h nettle/sha.h nettle/base64.h nettle/yarrow.h) + find_library(NETTLE_LIBRARY NAMES nettle libnettle) + + if (NOT NETTLE_INCLUDE_DIRS OR NOT NETTLE_LIBRARY OR USE_CRYPTO_OPENSSL) + set(USE_CRYPTO_OPENSSL ON) + find_package(OpenSSL REQUIRED) + + if(${OPENSSL_VERSION} VERSION_LESS ${OPENSSL_MINIMUM_VERSION} OR + (${OPENSSL_VERSION} VERSION_EQUAL ${OPENSSL_MINIMUM_VERSION} AND ${OPENSSL_VERSION} STRLESS ${OPENSSL_MINIMUM_VERSION})) + message(FATAL_ERROR "OpenSSL version found (${OPENSSL_VERSION}) is less then the minimum required (${OPENSSL_MINIMUM_VERSION}), aborting.") + endif() + include_directories(${OpenSSL_INCLUDE_DIRS}) + else() + set(USE_CRYPTO_OPENSSL OFF) + include_directories(${NETTLE_INCLUDE_DIRS}) + endif() +endif() + +if (USE_CRYPTO_OPENSSL) + message(STATUS "OpenSSL will be used for cryptography in STK.") + add_definitions(-DENABLE_CRYPTO_OPENSSL) +else() + message(STATUS "Nettle will be used for cryptography in STK.") + add_definitions(-DENABLE_CRYPTO_NETTLE) endif() # Common library dependencies @@ -484,9 +505,14 @@ target_link_libraries(supertuxkart stkirrlicht ${Angelscript_LIBRARIES} ${CURL_LIBRARIES} - ${OPENSSL_CRYPTO_LIBRARY} ) +if (USE_CRYPTO_OPENSSL) + target_link_libraries(supertuxkart ${OPENSSL_CRYPTO_LIBRARY}) +else() + target_link_libraries(supertuxkart ${NETTLE_LIBRARY}) +endif() + if(NOT SERVER_ONLY) if(NOT USE_GLES2) target_link_libraries(supertuxkart ${OPENGL_gl_LIBRARY} ${GLEW_LIBRARIES}) diff --git a/android/Android.mk b/android/Android.mk index 67fddb84d..a2f0f0724 100644 --- a/android/Android.mk +++ b/android/Android.mk @@ -161,6 +161,7 @@ LOCAL_CFLAGS := -I../lib/angelscript/include \ -Iobj/openssl/include \ -DUSE_GLES2 \ -DENABLE_SOUND \ + -DENABLE_CRYPTO_OPENSSL \ -DNDEBUG \ -DANDROID_PACKAGE_NAME=\"$(PACKAGE_NAME)\" \ -DANDROID_APP_DIR_NAME=\"$(APP_DIR_NAME)\" \ diff --git a/sources.cmake b/sources.cmake index 13db008ff..d4f28ae4d 100644 --- a/sources.cmake +++ b/sources.cmake @@ -1,5 +1,5 @@ # Modify this file to change the last-modified date when you add/remove a file. -# This will then trigger a new cmake run automatically. +# This will then trigger a new cmake run automatically. file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp") file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp") file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*") diff --git a/src/network/crypto.hpp b/src/network/crypto.hpp index b330231b7..43738809e 100644 --- a/src/network/crypto.hpp +++ b/src/network/crypto.hpp @@ -19,138 +19,10 @@ #ifndef HEADER_CRYPTO_HPP #define HEADER_CRYPTO_HPP -#include "utils/log.hpp" - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -class BareNetworkString; -class NetworkString; - -class Crypto -{ -private: - static std::string m_client_key; - - static std::string m_client_iv; - - std::array m_iv; - - uint32_t m_packet_counter; - - EVP_CIPHER_CTX* m_encrypt; - - EVP_CIPHER_CTX* m_decrypt; - - std::mutex m_crypto_mutex; - - // ------------------------------------------------------------------------ - static size_t calcDecodeLength(const std::string& input) - { - // Calculates the length of a decoded string - size_t padding = 0; - const size_t len = input.size(); - if (input[len - 1] == '=' && input[len - 2] == '=') - { - // last two chars are = - padding = 2; - } - else if (input[len - 1] == '=') - { - // last char is = - padding = 1; - } - return (len * 3) / 4 - padding; - } // calcDecodeLength -public: - // ------------------------------------------------------------------------ - static std::string base64(const std::vector& input); - // ------------------------------------------------------------------------ - static std::vector decode64(std::string input); - // ------------------------------------------------------------------------ - static std::unique_ptr getClientCrypto() - { - assert(!m_client_key.empty()); - assert(!m_client_iv.empty()); - auto c = std::unique_ptr(new Crypto(decode64(m_client_key), - decode64(m_client_iv))); - c->m_packet_counter = 1; - return c; - } - // ------------------------------------------------------------------------ - static void initClientAES() - { - std::random_device rd; - std::mt19937 g(rd()); - - // Default key and if RAND_bytes failed - std::vector key; - for (int i = 0; i < 16; i++) - key.push_back((uint8_t)(g() % 255)); - std::vector iv; - for (int i = 0; i < 12; i++) - iv.push_back((uint8_t)(g() % 255)); - if (!RAND_bytes(key.data(), 16)) - { - Log::warn("Crypto", - "Failed to generate cryptographically strong key"); - } - m_client_key = base64(key); - m_client_iv = base64(iv); - } - // ------------------------------------------------------------------------ - static void resetClientAES() - { - m_client_key = ""; - m_client_iv = ""; - } - // ------------------------------------------------------------------------ - static const std::string& getClientKey() { return m_client_key; } - // ------------------------------------------------------------------------ - static const std::string& getClientIV() { return m_client_iv; } - // ------------------------------------------------------------------------ - Crypto(const std::vector& key, - const std::vector& iv) - { - assert(key.size() == 16); - assert(iv.size() == 12); - std::copy_n(iv.begin(), 12, m_iv.begin()); - m_packet_counter = (uint32_t)-1; - m_encrypt = EVP_CIPHER_CTX_new(); - EVP_CIPHER_CTX_init(m_encrypt); - EVP_EncryptInit_ex(m_encrypt, EVP_aes_128_gcm(), NULL, key.data(), - iv.data()); - m_decrypt = EVP_CIPHER_CTX_new(); - EVP_CIPHER_CTX_init(m_decrypt); - EVP_DecryptInit_ex(m_decrypt, EVP_aes_128_gcm(), NULL, key.data(), - iv.data()); - } - // ------------------------------------------------------------------------ - ~Crypto() - { - EVP_CIPHER_CTX_free(m_encrypt); - EVP_CIPHER_CTX_free(m_decrypt); - } - // ------------------------------------------------------------------------ - bool encryptConnectionRequest(BareNetworkString& ns); - // ------------------------------------------------------------------------ - bool decryptConnectionRequest(BareNetworkString& ns); - // ------------------------------------------------------------------------ - ENetPacket* encryptSend(BareNetworkString& ns, bool reliable); - // ------------------------------------------------------------------------ - NetworkString* decryptRecieve(ENetPacket* p); - -}; +#ifdef ENABLE_CRYPTO_OPENSSL +#include "network/crypto_openssl.hpp" +#else +#include "network/crypto_nettle.hpp" +#endif #endif // HEADER_CRYPTO_HPP diff --git a/src/network/crypto_nettle.cpp b/src/network/crypto_nettle.cpp new file mode 100644 index 000000000..4b072d8bc --- /dev/null +++ b/src/network/crypto_nettle.cpp @@ -0,0 +1,141 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2018 SuperTuxKart-Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifdef ENABLE_CRYPTO_NETTLE + +#include "network/crypto_nettle.hpp" +#include "network/network_config.hpp" +#include "network/network_string.hpp" + +#include + +// ============================================================================ +std::string Crypto::base64(const std::vector& input) +{ + std::string result; + const size_t char_size = ((input.size() + 3 - 1) / 3) * 4; + result.resize(char_size, (char)0); + base64_encode_raw(&result[0], input.size(), input.data()); + return result; +} // base64 + +// ============================================================================ +std::vector Crypto::decode64(std::string input) +{ + size_t decode_len = calcDecodeLength(input); + std::vector result(decode_len, 0); + struct base64_decode_ctx ctx; + base64_decode_init(&ctx); + size_t decode_len_by_nettle; +#ifdef DEBUG + int ret = base64_decode_update(&ctx, &decode_len_by_nettle, result.data(), + input.size(), input.c_str()); + assert(ret == 1); + ret = base64_decode_final(&ctx); + assert(ret == 1); + assert(decode_len_by_nettle == decode_len); +#else + base64_decode_update(&ctx, &decode_len_by_nettle, result.data(), + input.size(), input.c_str()); + base64_decode_final(&ctx); +#endif + return result; +} // decode64 + +// ============================================================================ +std::string Crypto::m_client_key; +std::string Crypto::m_client_iv; +// ============================================================================ +bool Crypto::encryptConnectionRequest(BareNetworkString& ns) +{ + std::vector cipher(ns.m_buffer.size() + 4, 0); + gcm_aes128_encrypt(&m_aes_context, ns.m_buffer.size(), cipher.data() + 4, + ns.m_buffer.data()); + gcm_aes128_digest(&m_aes_context, 4, cipher.data()); + std::swap(ns.m_buffer, cipher); + return true; +} // encryptConnectionRequest + +// ---------------------------------------------------------------------------- +bool Crypto::decryptConnectionRequest(BareNetworkString& ns) +{ + std::vector pt(ns.m_buffer.size() - 4, 0); + uint8_t* tag = ns.m_buffer.data(); + std::array tag_after = {}; + + gcm_aes128_decrypt(&m_aes_context, ns.m_buffer.size() - 4, pt.data(), + ns.m_buffer.data() + 4); + gcm_aes128_digest(&m_aes_context, 4, tag_after.data()); + handleAuthentication(tag, tag_after); + + std::swap(ns.m_buffer, pt); + return true; +} // decryptConnectionRequest + +// ---------------------------------------------------------------------------- +ENetPacket* Crypto::encryptSend(BareNetworkString& ns, bool reliable) +{ + // 4 bytes counter and 4 bytes tag + ENetPacket* p = enet_packet_create(NULL, ns.m_buffer.size() + 8, + (reliable ? ENET_PACKET_FLAG_RELIABLE : + (ENET_PACKET_FLAG_UNSEQUENCED | ENET_PACKET_FLAG_UNRELIABLE_FRAGMENT)) + ); + if (p == NULL) + return NULL; + + std::array iv = m_iv; + std::unique_lock ul(m_crypto_mutex); + uint32_t val = NetworkConfig::get()->isClient() ? + m_packet_counter++ : m_packet_counter--; + memcpy(iv.data(), &val, 4); + uint8_t* packet_start = p->data + 8; + + gcm_aes128_set_iv(&m_aes_context, 12, iv.data()); + gcm_aes128_encrypt(&m_aes_context, ns.m_buffer.size(), packet_start, + ns.m_buffer.data()); + gcm_aes128_digest(&m_aes_context, 4, p->data + 4); + ul.unlock(); + + memcpy(p->data, iv.data(), 4); + return p; +} // encryptSend + +// ---------------------------------------------------------------------------- +NetworkString* Crypto::decryptRecieve(ENetPacket* p) +{ + int clen = (int)(p->dataLength - 8); + auto ns = std::unique_ptr(new NetworkString(p->data, clen)); + + std::array iv = m_iv; + memcpy(iv.data(), p->data, 4); + uint8_t* packet_start = p->data + 8; + uint8_t* tag = p->data + 4; + std::array tag_after = {}; + + gcm_aes128_set_iv(&m_aes_context, 12, iv.data()); + gcm_aes128_decrypt(&m_aes_context, clen, ns->m_buffer.data(), + packet_start); + gcm_aes128_digest(&m_aes_context, 4, tag_after.data()); + handleAuthentication(tag, tag_after); + + NetworkString* result = ns.get(); + ns.release(); + return result; +} // decryptRecieve + +#endif diff --git a/src/network/crypto_nettle.hpp b/src/network/crypto_nettle.hpp new file mode 100644 index 000000000..d867f0ff7 --- /dev/null +++ b/src/network/crypto_nettle.hpp @@ -0,0 +1,151 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2018 SuperTuxKart-Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifdef ENABLE_CRYPTO_NETTLE + +#ifndef HEADER_CRYPTO_NETTLE_HPP +#define HEADER_CRYPTO_NETTLE_HPP + +#include "utils/log.hpp" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +class BareNetworkString; +class NetworkString; + +class Crypto +{ +private: + static std::string m_client_key; + + static std::string m_client_iv; + + std::array m_iv; + + uint32_t m_packet_counter; + + struct gcm_aes128_ctx m_aes_context; + + std::mutex m_crypto_mutex; + + // ------------------------------------------------------------------------ + static size_t calcDecodeLength(const std::string& input) + { + // Calculates the length of a decoded string + size_t padding = 0; + const size_t len = input.size(); + if (input[len - 1] == '=' && input[len - 2] == '=') + { + // last two chars are = + padding = 2; + } + else if (input[len - 1] == '=') + { + // last char is = + padding = 1; + } + return (len * 3) / 4 - padding; + } // calcDecodeLength + // ------------------------------------------------------------------------ + void handleAuthentication(const uint8_t* tag, + const std::array& tag_after) + { + for (unsigned i = 0; i < tag_after.size(); i++) + { + if (tag[i] != tag_after[i]) + throw std::runtime_error("Failed authentication."); + } + } + +public: + // ------------------------------------------------------------------------ + static std::string base64(const std::vector& input); + // ------------------------------------------------------------------------ + static std::vector decode64(std::string input); + // ------------------------------------------------------------------------ + static std::unique_ptr getClientCrypto() + { + assert(!m_client_key.empty()); + assert(!m_client_iv.empty()); + auto c = std::unique_ptr(new Crypto(decode64(m_client_key), + decode64(m_client_iv))); + c->m_packet_counter = 1; + return c; + } + // ------------------------------------------------------------------------ + static void initClientAES() + { + struct yarrow256_ctx ctx; + yarrow256_init(&ctx, 0, NULL); + std::random_device rd; + std::mt19937 g(rd()); + std::array seed; + for (unsigned i = 0; i < YARROW256_SEED_FILE_SIZE; i++) + seed[i] = (uint8_t)(g() % 255); + yarrow256_seed(&ctx, YARROW256_SEED_FILE_SIZE, seed.data()); + std::array key_iv; + yarrow256_random(&ctx, key_iv.size(), key_iv.data()); + m_client_key = base64({ key_iv.begin(), key_iv.begin() + 16 }); + m_client_iv = base64({ key_iv.begin() + 16, key_iv.end() }); + } + // ------------------------------------------------------------------------ + static void resetClientAES() + { + m_client_key = ""; + m_client_iv = ""; + } + // ------------------------------------------------------------------------ + static const std::string& getClientKey() { return m_client_key; } + // ------------------------------------------------------------------------ + static const std::string& getClientIV() { return m_client_iv; } + // ------------------------------------------------------------------------ + Crypto(const std::vector& key, + const std::vector& iv) + { + assert(key.size() == 16); + assert(iv.size() == 12); + std::copy_n(iv.begin(), 12, m_iv.begin()); + m_packet_counter = (uint32_t)-1; + gcm_aes128_set_key(&m_aes_context, key.data()); + gcm_aes128_set_iv(&m_aes_context, 12, iv.data()); + } + // ------------------------------------------------------------------------ + bool encryptConnectionRequest(BareNetworkString& ns); + // ------------------------------------------------------------------------ + bool decryptConnectionRequest(BareNetworkString& ns); + // ------------------------------------------------------------------------ + ENetPacket* encryptSend(BareNetworkString& ns, bool reliable); + // ------------------------------------------------------------------------ + NetworkString* decryptRecieve(ENetPacket* p); + +}; + +#endif // HEADER_CRYPTO_NETTLE_HPP + +#endif diff --git a/src/network/crypto.cpp b/src/network/crypto_openssl.cpp similarity index 98% rename from src/network/crypto.cpp rename to src/network/crypto_openssl.cpp index f2d9e87d8..b681d21b3 100644 --- a/src/network/crypto.cpp +++ b/src/network/crypto_openssl.cpp @@ -16,7 +16,9 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -#include "network/crypto.hpp" +#ifdef ENABLE_CRYPTO_OPENSSL + +#include "network/crypto_openssl.hpp" #include "network/network_config.hpp" #include "network/network_string.hpp" @@ -201,3 +203,5 @@ NetworkString* Crypto::decryptRecieve(ENetPacket* p) } throw std::runtime_error("Failed to finalize decryption."); } // decryptRecieve + +#endif diff --git a/src/network/crypto_openssl.hpp b/src/network/crypto_openssl.hpp new file mode 100644 index 000000000..3a9d560ad --- /dev/null +++ b/src/network/crypto_openssl.hpp @@ -0,0 +1,160 @@ +// +// SuperTuxKart - a fun racing game with go-kart +// Copyright (C) 2018 SuperTuxKart-Team +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 3 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +#ifdef ENABLE_CRYPTO_OPENSSL + +#ifndef HEADER_CRYPTO_OPENSSL_HPP +#define HEADER_CRYPTO_OPENSSL_HPP + +#include "utils/log.hpp" + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +class BareNetworkString; +class NetworkString; + +class Crypto +{ +private: + static std::string m_client_key; + + static std::string m_client_iv; + + std::array m_iv; + + uint32_t m_packet_counter; + + EVP_CIPHER_CTX* m_encrypt; + + EVP_CIPHER_CTX* m_decrypt; + + std::mutex m_crypto_mutex; + + // ------------------------------------------------------------------------ + static size_t calcDecodeLength(const std::string& input) + { + // Calculates the length of a decoded string + size_t padding = 0; + const size_t len = input.size(); + if (input[len - 1] == '=' && input[len - 2] == '=') + { + // last two chars are = + padding = 2; + } + else if (input[len - 1] == '=') + { + // last char is = + padding = 1; + } + return (len * 3) / 4 - padding; + } // calcDecodeLength +public: + // ------------------------------------------------------------------------ + static std::string base64(const std::vector& input); + // ------------------------------------------------------------------------ + static std::vector decode64(std::string input); + // ------------------------------------------------------------------------ + static std::unique_ptr getClientCrypto() + { + assert(!m_client_key.empty()); + assert(!m_client_iv.empty()); + auto c = std::unique_ptr(new Crypto(decode64(m_client_key), + decode64(m_client_iv))); + c->m_packet_counter = 1; + return c; + } + // ------------------------------------------------------------------------ + static void initClientAES() + { + std::random_device rd; + std::mt19937 g(rd()); + + // Default key and if RAND_bytes failed + std::vector key; + for (int i = 0; i < 16; i++) + key.push_back((uint8_t)(g() % 255)); + std::vector iv; + for (int i = 0; i < 12; i++) + iv.push_back((uint8_t)(g() % 255)); + if (!RAND_bytes(key.data(), 16)) + { + Log::warn("Crypto", + "Failed to generate cryptographically strong key"); + } + m_client_key = base64(key); + m_client_iv = base64(iv); + } + // ------------------------------------------------------------------------ + static void resetClientAES() + { + m_client_key = ""; + m_client_iv = ""; + } + // ------------------------------------------------------------------------ + static const std::string& getClientKey() { return m_client_key; } + // ------------------------------------------------------------------------ + static const std::string& getClientIV() { return m_client_iv; } + // ------------------------------------------------------------------------ + Crypto(const std::vector& key, + const std::vector& iv) + { + assert(key.size() == 16); + assert(iv.size() == 12); + std::copy_n(iv.begin(), 12, m_iv.begin()); + m_packet_counter = (uint32_t)-1; + m_encrypt = EVP_CIPHER_CTX_new(); + EVP_CIPHER_CTX_init(m_encrypt); + EVP_EncryptInit_ex(m_encrypt, EVP_aes_128_gcm(), NULL, key.data(), + iv.data()); + m_decrypt = EVP_CIPHER_CTX_new(); + EVP_CIPHER_CTX_init(m_decrypt); + EVP_DecryptInit_ex(m_decrypt, EVP_aes_128_gcm(), NULL, key.data(), + iv.data()); + } + // ------------------------------------------------------------------------ + ~Crypto() + { + EVP_CIPHER_CTX_free(m_encrypt); + EVP_CIPHER_CTX_free(m_decrypt); + } + // ------------------------------------------------------------------------ + bool encryptConnectionRequest(BareNetworkString& ns); + // ------------------------------------------------------------------------ + bool decryptConnectionRequest(BareNetworkString& ns); + // ------------------------------------------------------------------------ + ENetPacket* encryptSend(BareNetworkString& ns, bool reliable); + // ------------------------------------------------------------------------ + NetworkString* decryptRecieve(ENetPacket* p); + +}; + +#endif // HEADER_CRYPTO_OPENSSL_HPP + +#endif