Use Nettle in linux if found
This commit is contained in:
parent
8873013911
commit
b4d9b43a52
@ -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})
|
||||
|
@ -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)\" \
|
||||
|
@ -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/*")
|
||||
|
@ -19,138 +19,10 @@
|
||||
#ifndef HEADER_CRYPTO_HPP
|
||||
#define HEADER_CRYPTO_HPP
|
||||
|
||||
#include "utils/log.hpp"
|
||||
|
||||
#include <enet/enet.h>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class BareNetworkString;
|
||||
class NetworkString;
|
||||
|
||||
class Crypto
|
||||
{
|
||||
private:
|
||||
static std::string m_client_key;
|
||||
|
||||
static std::string m_client_iv;
|
||||
|
||||
std::array<uint8_t, 12> 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<uint8_t>& input);
|
||||
// ------------------------------------------------------------------------
|
||||
static std::vector<uint8_t> decode64(std::string input);
|
||||
// ------------------------------------------------------------------------
|
||||
static std::unique_ptr<Crypto> getClientCrypto()
|
||||
{
|
||||
assert(!m_client_key.empty());
|
||||
assert(!m_client_iv.empty());
|
||||
auto c = std::unique_ptr<Crypto>(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<uint8_t> key;
|
||||
for (int i = 0; i < 16; i++)
|
||||
key.push_back((uint8_t)(g() % 255));
|
||||
std::vector<uint8_t> 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<uint8_t>& key,
|
||||
const std::vector<uint8_t>& 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
|
||||
|
141
src/network/crypto_nettle.cpp
Normal file
141
src/network/crypto_nettle.cpp
Normal file
@ -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 <nettle/base64.h>
|
||||
|
||||
// ============================================================================
|
||||
std::string Crypto::base64(const std::vector<uint8_t>& 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<uint8_t> Crypto::decode64(std::string input)
|
||||
{
|
||||
size_t decode_len = calcDecodeLength(input);
|
||||
std::vector<uint8_t> 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<uint8_t> 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<uint8_t> pt(ns.m_buffer.size() - 4, 0);
|
||||
uint8_t* tag = ns.m_buffer.data();
|
||||
std::array<uint8_t, 4> 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<uint8_t, 12> iv = m_iv;
|
||||
std::unique_lock<std::mutex> 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<NetworkString>(new NetworkString(p->data, clen));
|
||||
|
||||
std::array<uint8_t, 12> iv = m_iv;
|
||||
memcpy(iv.data(), p->data, 4);
|
||||
uint8_t* packet_start = p->data + 8;
|
||||
uint8_t* tag = p->data + 4;
|
||||
std::array<uint8_t, 4> 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
|
151
src/network/crypto_nettle.hpp
Normal file
151
src/network/crypto_nettle.hpp
Normal file
@ -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 <enet/enet.h>
|
||||
#include <nettle/gcm.h>
|
||||
#include <nettle/yarrow.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class BareNetworkString;
|
||||
class NetworkString;
|
||||
|
||||
class Crypto
|
||||
{
|
||||
private:
|
||||
static std::string m_client_key;
|
||||
|
||||
static std::string m_client_iv;
|
||||
|
||||
std::array<uint8_t, 12> 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<uint8_t, 4>& 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<uint8_t>& input);
|
||||
// ------------------------------------------------------------------------
|
||||
static std::vector<uint8_t> decode64(std::string input);
|
||||
// ------------------------------------------------------------------------
|
||||
static std::unique_ptr<Crypto> getClientCrypto()
|
||||
{
|
||||
assert(!m_client_key.empty());
|
||||
assert(!m_client_iv.empty());
|
||||
auto c = std::unique_ptr<Crypto>(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<uint8_t, YARROW256_SEED_FILE_SIZE> 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<uint8_t, 28> 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<uint8_t>& key,
|
||||
const std::vector<uint8_t>& 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
|
@ -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
|
160
src/network/crypto_openssl.hpp
Normal file
160
src/network/crypto_openssl.hpp
Normal file
@ -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 <enet/enet.h>
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class BareNetworkString;
|
||||
class NetworkString;
|
||||
|
||||
class Crypto
|
||||
{
|
||||
private:
|
||||
static std::string m_client_key;
|
||||
|
||||
static std::string m_client_iv;
|
||||
|
||||
std::array<uint8_t, 12> 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<uint8_t>& input);
|
||||
// ------------------------------------------------------------------------
|
||||
static std::vector<uint8_t> decode64(std::string input);
|
||||
// ------------------------------------------------------------------------
|
||||
static std::unique_ptr<Crypto> getClientCrypto()
|
||||
{
|
||||
assert(!m_client_key.empty());
|
||||
assert(!m_client_iv.empty());
|
||||
auto c = std::unique_ptr<Crypto>(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<uint8_t> key;
|
||||
for (int i = 0; i < 16; i++)
|
||||
key.push_back((uint8_t)(g() % 255));
|
||||
std::vector<uint8_t> 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<uint8_t>& key,
|
||||
const std::vector<uint8_t>& 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
|
Loading…
x
Reference in New Issue
Block a user