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_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)
|
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
|
CMAKE_DEPENDENT_OPTION(BUILD_RECORDER "Build opengl recorder" ON
|
||||||
"NOT SERVER_ONLY;NOT APPLE" OFF)
|
"NOT SERVER_ONLY;NOT APPLE" OFF)
|
||||||
CMAKE_DEPENDENT_OPTION(USE_FRIBIDI "Support for right-to-left languages" ON
|
CMAKE_DEPENDENT_OPTION(USE_FRIBIDI "Support for right-to-left languages" ON
|
||||||
@ -453,26 +455,45 @@ else()
|
|||||||
target_link_libraries(supertuxkart ${PTHREAD_LIBRARY})
|
target_link_libraries(supertuxkart ${PTHREAD_LIBRARY})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# CURL and OpenSSL
|
# CURL and OpenSSL or Nettle
|
||||||
# 1.0.1d for compatible AES GCM handling
|
# 1.0.1d for compatible AES GCM handling
|
||||||
SET(OPENSSL_MINIMUM_VERSION "1.0.1d")
|
SET(OPENSSL_MINIMUM_VERSION "1.0.1d")
|
||||||
if(MSVC)
|
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/libcurl.lib)
|
||||||
target_link_libraries(supertuxkart ${PROJECT_SOURCE_DIR}/${DEPENDENCIES}/lib/libeay32.lib)
|
target_link_libraries(supertuxkart ${PROJECT_SOURCE_DIR}/${DEPENDENCIES}/lib/libeay32.lib)
|
||||||
elseif(MINGW)
|
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/libcurldll.a)
|
||||||
target_link_libraries(supertuxkart ${PROJECT_SOURCE_DIR}/${DEPENDENCIES}/lib/libeay32.dll)
|
target_link_libraries(supertuxkart ${PROJECT_SOURCE_DIR}/${DEPENDENCIES}/lib/libeay32.dll)
|
||||||
else()
|
else()
|
||||||
find_package(CURL REQUIRED)
|
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(${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()
|
endif()
|
||||||
|
|
||||||
# Common library dependencies
|
# Common library dependencies
|
||||||
@ -484,9 +505,14 @@ target_link_libraries(supertuxkart
|
|||||||
stkirrlicht
|
stkirrlicht
|
||||||
${Angelscript_LIBRARIES}
|
${Angelscript_LIBRARIES}
|
||||||
${CURL_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 SERVER_ONLY)
|
||||||
if(NOT USE_GLES2)
|
if(NOT USE_GLES2)
|
||||||
target_link_libraries(supertuxkart ${OPENGL_gl_LIBRARY} ${GLEW_LIBRARIES})
|
target_link_libraries(supertuxkart ${OPENGL_gl_LIBRARY} ${GLEW_LIBRARIES})
|
||||||
|
@ -161,6 +161,7 @@ LOCAL_CFLAGS := -I../lib/angelscript/include \
|
|||||||
-Iobj/openssl/include \
|
-Iobj/openssl/include \
|
||||||
-DUSE_GLES2 \
|
-DUSE_GLES2 \
|
||||||
-DENABLE_SOUND \
|
-DENABLE_SOUND \
|
||||||
|
-DENABLE_CRYPTO_OPENSSL \
|
||||||
-DNDEBUG \
|
-DNDEBUG \
|
||||||
-DANDROID_PACKAGE_NAME=\"$(PACKAGE_NAME)\" \
|
-DANDROID_PACKAGE_NAME=\"$(PACKAGE_NAME)\" \
|
||||||
-DANDROID_APP_DIR_NAME=\"$(APP_DIR_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.
|
# 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_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp")
|
||||||
file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp")
|
file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp")
|
||||||
file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*")
|
file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*")
|
||||||
|
@ -19,138 +19,10 @@
|
|||||||
#ifndef HEADER_CRYPTO_HPP
|
#ifndef HEADER_CRYPTO_HPP
|
||||||
#define HEADER_CRYPTO_HPP
|
#define HEADER_CRYPTO_HPP
|
||||||
|
|
||||||
#include "utils/log.hpp"
|
#ifdef ENABLE_CRYPTO_OPENSSL
|
||||||
|
#include "network/crypto_openssl.hpp"
|
||||||
#include <enet/enet.h>
|
#else
|
||||||
|
#include "network/crypto_nettle.hpp"
|
||||||
#include <openssl/evp.h>
|
#endif
|
||||||
#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_HPP
|
#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
|
// along with this program; if not, write to the Free Software
|
||||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
// 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_config.hpp"
|
||||||
#include "network/network_string.hpp"
|
#include "network/network_string.hpp"
|
||||||
|
|
||||||
@ -201,3 +203,5 @@ NetworkString* Crypto::decryptRecieve(ENetPacket* p)
|
|||||||
}
|
}
|
||||||
throw std::runtime_error("Failed to finalize decryption.");
|
throw std::runtime_error("Failed to finalize decryption.");
|
||||||
} // decryptRecieve
|
} // 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