Use MbedTLS instead of Nettle
This commit is contained in:
parent
39c42c3f0c
commit
d753393f4d
@ -33,7 +33,7 @@ option(USE_IPV6 "Allow create or connect to game server with IPv6 address, syste
|
|||||||
option(USE_SYSTEM_WIIUSE "Use system WiiUse instead of the built-in version, when available." OFF)
|
option(USE_SYSTEM_WIIUSE "Use system WiiUse instead of the built-in version, when available." OFF)
|
||||||
option(USE_SQLITE3 "Use sqlite to manage server stats and ban list." ON)
|
option(USE_SQLITE3 "Use sqlite to manage server stats and ban list." ON)
|
||||||
|
|
||||||
option(USE_CRYPTO_OPENSSL "Use OpenSSL instead of Nettle for cryptography in STK." ON)
|
option(USE_CRYPTO_OPENSSL "Use OpenSSL instead of MbedTLS for cryptography in STK." 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_SYSTEM_SQUISH "Use system Squish library instead of the built-in version, when available." ON
|
CMAKE_DEPENDENT_OPTION(USE_SYSTEM_SQUISH "Use system Squish library instead of the built-in version, when available." ON
|
||||||
@ -551,7 +551,7 @@ if (NOT NO_LIBATOMIC_NEEDED)
|
|||||||
target_link_libraries(supertuxkart atomic)
|
target_link_libraries(supertuxkart atomic)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# CURL and OpenSSL or Nettle
|
# CURL and OpenSSL or MbedTLS
|
||||||
# 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 OR LLVM_MINGW)
|
if (MSVC OR LLVM_MINGW)
|
||||||
@ -566,10 +566,10 @@ else()
|
|||||||
find_package(CURL REQUIRED)
|
find_package(CURL REQUIRED)
|
||||||
include_directories(${CURL_INCLUDE_DIRS})
|
include_directories(${CURL_INCLUDE_DIRS})
|
||||||
|
|
||||||
find_path(NETTLE_INCLUDE_DIRS nettle/version.h)
|
find_path(MBEDTLS_INCLUDE_DIRS mbedtls/version.h)
|
||||||
find_library(NETTLE_LIBRARY NAMES nettle libnettle)
|
find_library(MBEDCRYPTO_LIBRARY NAMES mbedcrypto libmbedcrypto)
|
||||||
|
|
||||||
if (NOT NETTLE_INCLUDE_DIRS OR NOT NETTLE_LIBRARY OR USE_CRYPTO_OPENSSL)
|
if (NOT MBEDCRYPTO_LIBRARY OR NOT MBEDTLS_INCLUDE_DIRS OR USE_CRYPTO_OPENSSL)
|
||||||
set(USE_CRYPTO_OPENSSL ON)
|
set(USE_CRYPTO_OPENSSL ON)
|
||||||
find_package(OpenSSL REQUIRED)
|
find_package(OpenSSL REQUIRED)
|
||||||
|
|
||||||
@ -580,7 +580,7 @@ else()
|
|||||||
include_directories(${OpenSSL_INCLUDE_DIRS})
|
include_directories(${OpenSSL_INCLUDE_DIRS})
|
||||||
else()
|
else()
|
||||||
set(USE_CRYPTO_OPENSSL OFF)
|
set(USE_CRYPTO_OPENSSL OFF)
|
||||||
include_directories(${NETTLE_INCLUDE_DIRS})
|
include_directories(${MBEDTLS_INCLUDE_DIRS})
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@ -588,8 +588,8 @@ if (USE_CRYPTO_OPENSSL)
|
|||||||
message(STATUS "OpenSSL will be used for cryptography in STK.")
|
message(STATUS "OpenSSL will be used for cryptography in STK.")
|
||||||
add_definitions(-DENABLE_CRYPTO_OPENSSL)
|
add_definitions(-DENABLE_CRYPTO_OPENSSL)
|
||||||
else()
|
else()
|
||||||
message(STATUS "Nettle will be used for cryptography in STK.")
|
message(STATUS "MbedTLS will be used for cryptography in STK.")
|
||||||
add_definitions(-DENABLE_CRYPTO_NETTLE)
|
add_definitions(-DENABLE_CRYPTO_MBEDTLS)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Common library dependencies
|
# Common library dependencies
|
||||||
@ -612,7 +612,7 @@ endif()
|
|||||||
if (USE_CRYPTO_OPENSSL)
|
if (USE_CRYPTO_OPENSSL)
|
||||||
target_link_libraries(supertuxkart ${OPENSSL_CRYPTO_LIBRARY})
|
target_link_libraries(supertuxkart ${OPENSSL_CRYPTO_LIBRARY})
|
||||||
else()
|
else()
|
||||||
target_link_libraries(supertuxkart ${NETTLE_LIBRARY})
|
target_link_libraries(supertuxkart ${MBEDCRYPTO_LIBRARY})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT SERVER_ONLY)
|
if(NOT SERVER_ONLY)
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
#ifdef ENABLE_CRYPTO_OPENSSL
|
#ifdef ENABLE_CRYPTO_OPENSSL
|
||||||
#include "network/crypto_openssl.hpp"
|
#include "network/crypto_openssl.hpp"
|
||||||
#else
|
#else
|
||||||
#include "network/crypto_nettle.hpp"
|
#include "network/crypto_mbedtls.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // HEADER_CRYPTO_HPP
|
#endif // HEADER_CRYPTO_HPP
|
||||||
|
@ -16,66 +16,48 @@
|
|||||||
// 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.
|
||||||
|
|
||||||
#ifdef ENABLE_CRYPTO_NETTLE
|
#ifdef ENABLE_CRYPTO_MBEDTLS
|
||||||
|
|
||||||
#include "network/crypto_nettle.hpp"
|
#include "network/crypto_mbedtls.hpp"
|
||||||
#include "network/network_config.hpp"
|
#include "network/network_config.hpp"
|
||||||
#include "network/network_string.hpp"
|
#include "network/network_string.hpp"
|
||||||
|
|
||||||
#include <nettle/base64.h>
|
#include <mbedtls/base64.h>
|
||||||
#include <nettle/sha.h>
|
#include <mbedtls/sha256.h>
|
||||||
#include <nettle/version.h>
|
#include <cstring>
|
||||||
|
|
||||||
#if NETTLE_VERSION_MAJOR > 3 || \
|
|
||||||
(NETTLE_VERSION_MAJOR == 3 && NETTLE_VERSION_MINOR > 3)
|
|
||||||
typedef const char* NETTLE_CONST_CHAR;
|
|
||||||
typedef char* NETTLE_CHAR;
|
|
||||||
#else
|
|
||||||
typedef const uint8_t* NETTLE_CONST_CHAR;
|
|
||||||
typedef uint8_t* NETTLE_CHAR;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
std::string Crypto::base64(const std::vector<uint8_t>& input)
|
std::string Crypto::base64(const std::vector<uint8_t>& input)
|
||||||
{
|
{
|
||||||
|
size_t required_size = 0;
|
||||||
|
mbedtls_base64_encode(NULL, 0, &required_size, &input[0], input.size());
|
||||||
std::string result;
|
std::string result;
|
||||||
const size_t char_size = ((input.size() + 3 - 1) / 3) * 4;
|
result.resize(required_size, (char)0);
|
||||||
result.resize(char_size, (char)0);
|
mbedtls_base64_encode((unsigned char*)&result[0], required_size,
|
||||||
base64_encode_raw((NETTLE_CHAR)&result[0], input.size(), input.data());
|
&required_size, &input[0], input.size());
|
||||||
|
// mbedtls_base64_encode includes the null terminator for required size
|
||||||
|
result.resize(strlen(result.c_str()));
|
||||||
return result;
|
return result;
|
||||||
} // base64
|
} // base64
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
std::vector<uint8_t> Crypto::decode64(std::string input)
|
std::vector<uint8_t> Crypto::decode64(std::string input)
|
||||||
{
|
{
|
||||||
size_t decode_len = calcDecodeLength(input);
|
size_t required_size = 0;
|
||||||
std::vector<uint8_t> result(decode_len, 0);
|
mbedtls_base64_decode(NULL, 0, &required_size, (unsigned char*)&input[0],
|
||||||
struct base64_decode_ctx ctx;
|
input.size());
|
||||||
base64_decode_init(&ctx);
|
std::vector<uint8_t> result(required_size, 0);
|
||||||
size_t decode_len_by_nettle;
|
mbedtls_base64_decode(result.data(), required_size,
|
||||||
#ifdef DEBUG
|
&required_size, (unsigned char*)&input[0], input.size());
|
||||||
int ret = base64_decode_update(&ctx, &decode_len_by_nettle, result.data(),
|
|
||||||
input.size(), (NETTLE_CONST_CHAR)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(), (NETTLE_CONST_CHAR)input.c_str());
|
|
||||||
base64_decode_final(&ctx);
|
|
||||||
#endif
|
|
||||||
return result;
|
return result;
|
||||||
} // decode64
|
} // decode64
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
std::array<uint8_t, 32> Crypto::sha256(const std::string& input)
|
std::array<uint8_t, 32> Crypto::sha256(const std::string& input)
|
||||||
{
|
{
|
||||||
std::array<uint8_t, SHA256_DIGEST_SIZE> result;
|
std::array<uint8_t, 32> result;
|
||||||
struct sha256_ctx hash;
|
mbedtls_sha256_ret((unsigned char*)&input[0], input.size(),
|
||||||
sha256_init(&hash);
|
result.data(), 0/*not 224*/);
|
||||||
sha256_update(&hash, input.size(), (const uint8_t*)input.c_str());
|
|
||||||
sha256_digest(&hash, SHA256_DIGEST_SIZE, result.data());
|
|
||||||
return result;
|
return result;
|
||||||
} // sha256
|
} // sha256
|
||||||
|
|
||||||
@ -86,9 +68,12 @@ std::string Crypto::m_client_iv;
|
|||||||
bool Crypto::encryptConnectionRequest(BareNetworkString& ns)
|
bool Crypto::encryptConnectionRequest(BareNetworkString& ns)
|
||||||
{
|
{
|
||||||
std::vector<uint8_t> cipher(ns.m_buffer.size() + 4, 0);
|
std::vector<uint8_t> cipher(ns.m_buffer.size() + 4, 0);
|
||||||
gcm_aes128_encrypt(&m_aes_encrypt_context, ns.m_buffer.size(),
|
if (mbedtls_gcm_crypt_and_tag(&m_aes_encrypt_context, MBEDTLS_GCM_ENCRYPT,
|
||||||
cipher.data() + 4, ns.m_buffer.data());
|
ns.m_buffer.size(), m_iv.data(), m_iv.size(), NULL, 0,
|
||||||
gcm_aes128_digest(&m_aes_encrypt_context, 4, cipher.data());
|
ns.m_buffer.data(), cipher.data() + 4, 4, cipher.data()) != 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
std::swap(ns.m_buffer, cipher);
|
std::swap(ns.m_buffer, cipher);
|
||||||
return true;
|
return true;
|
||||||
} // encryptConnectionRequest
|
} // encryptConnectionRequest
|
||||||
@ -98,13 +83,12 @@ bool Crypto::decryptConnectionRequest(BareNetworkString& ns)
|
|||||||
{
|
{
|
||||||
std::vector<uint8_t> pt(ns.m_buffer.size() - 4, 0);
|
std::vector<uint8_t> pt(ns.m_buffer.size() - 4, 0);
|
||||||
uint8_t* tag = ns.m_buffer.data();
|
uint8_t* tag = ns.m_buffer.data();
|
||||||
std::array<uint8_t, 4> tag_after = {};
|
if (mbedtls_gcm_auth_decrypt(&m_aes_decrypt_context, pt.size(),
|
||||||
|
m_iv.data(), m_iv.size(), NULL, 0, tag, 4, ns.m_buffer.data() + 4,
|
||||||
gcm_aes128_decrypt(&m_aes_decrypt_context, ns.m_buffer.size() - 4,
|
pt.data()) != 0)
|
||||||
pt.data(), ns.m_buffer.data() + 4);
|
{
|
||||||
gcm_aes128_digest(&m_aes_decrypt_context, 4, tag_after.data());
|
throw std::runtime_error("Failed authentication.");
|
||||||
handleAuthentication(tag, tag_after);
|
}
|
||||||
|
|
||||||
std::swap(ns.m_buffer, pt);
|
std::swap(ns.m_buffer, pt);
|
||||||
return true;
|
return true;
|
||||||
} // decryptConnectionRequest
|
} // decryptConnectionRequest
|
||||||
@ -140,11 +124,13 @@ ENetPacket* Crypto::encryptSend(BareNetworkString& ns, bool reliable)
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint8_t* packet_start = p->data + 8;
|
uint8_t* packet_start = p->data + 8;
|
||||||
|
if (mbedtls_gcm_crypt_and_tag(&m_aes_encrypt_context, MBEDTLS_GCM_ENCRYPT,
|
||||||
gcm_aes128_set_iv(&m_aes_encrypt_context, 12, iv.data());
|
ns.m_buffer.size(), iv.data(), iv.size(), NULL, 0, ns.m_buffer.data(),
|
||||||
gcm_aes128_encrypt(&m_aes_encrypt_context, ns.m_buffer.size(),
|
packet_start, 4, p->data + 4) != 0)
|
||||||
packet_start, ns.m_buffer.data());
|
{
|
||||||
gcm_aes128_digest(&m_aes_encrypt_context, 4, p->data + 4);
|
enet_packet_destroy(p);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
ul.unlock();
|
ul.unlock();
|
||||||
|
|
||||||
p->data[0] = (val >> 24) & 0xff;
|
p->data[0] = (val >> 24) & 0xff;
|
||||||
@ -168,13 +154,11 @@ NetworkString* Crypto::decryptRecieve(ENetPacket* p)
|
|||||||
|
|
||||||
uint8_t* packet_start = p->data + 8;
|
uint8_t* packet_start = p->data + 8;
|
||||||
uint8_t* tag = p->data + 4;
|
uint8_t* tag = p->data + 4;
|
||||||
std::array<uint8_t, 4> tag_after = {};
|
if (mbedtls_gcm_auth_decrypt(&m_aes_decrypt_context, clen, iv.data(),
|
||||||
|
iv.size(), NULL, 0, tag, 4, packet_start, ns->m_buffer.data()) != 0)
|
||||||
gcm_aes128_set_iv(&m_aes_decrypt_context, 12, iv.data());
|
{
|
||||||
gcm_aes128_decrypt(&m_aes_decrypt_context, clen, ns->m_buffer.data(),
|
throw std::runtime_error("Failed authentication.");
|
||||||
packet_start);
|
}
|
||||||
gcm_aes128_digest(&m_aes_decrypt_context, 4, tag_after.data());
|
|
||||||
handleAuthentication(tag, tag_after);
|
|
||||||
|
|
||||||
NetworkString* result = ns.get();
|
NetworkString* result = ns.get();
|
||||||
ns.release();
|
ns.release();
|
@ -16,16 +16,17 @@
|
|||||||
// 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.
|
||||||
|
|
||||||
#ifdef ENABLE_CRYPTO_NETTLE
|
#ifdef ENABLE_CRYPTO_MBEDTLS
|
||||||
|
|
||||||
#ifndef HEADER_CRYPTO_NETTLE_HPP
|
#ifndef HEADER_CRYPTO_MBEDTLS_HPP
|
||||||
#define HEADER_CRYPTO_NETTLE_HPP
|
#define HEADER_CRYPTO_MBEDTLS_HPP
|
||||||
|
|
||||||
#include "utils/log.hpp"
|
#include "utils/log.hpp"
|
||||||
|
|
||||||
#include <enet/enet.h>
|
#include <enet/enet.h>
|
||||||
#include <nettle/gcm.h>
|
#include <mbedtls/ctr_drbg.h>
|
||||||
#include <nettle/yarrow.h>
|
#include <mbedtls/entropy.h>
|
||||||
|
#include <mbedtls/gcm.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
@ -50,39 +51,10 @@ private:
|
|||||||
|
|
||||||
uint32_t m_packet_counter;
|
uint32_t m_packet_counter;
|
||||||
|
|
||||||
struct gcm_aes128_ctx m_aes_encrypt_context, m_aes_decrypt_context;
|
mbedtls_gcm_context m_aes_encrypt_context, m_aes_decrypt_context;
|
||||||
|
|
||||||
std::mutex m_crypto_mutex;
|
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:
|
public:
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
static std::string base64(const std::vector<uint8_t>& input);
|
static std::string base64(const std::vector<uint8_t>& input);
|
||||||
@ -103,16 +75,24 @@ public:
|
|||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
static void initClientAES()
|
static void initClientAES()
|
||||||
{
|
{
|
||||||
struct yarrow256_ctx ctx;
|
mbedtls_entropy_context entropy;
|
||||||
yarrow256_init(&ctx, 0, NULL);
|
mbedtls_entropy_init(&entropy);
|
||||||
|
mbedtls_ctr_drbg_context ctr_drbg;
|
||||||
|
mbedtls_ctr_drbg_init(&ctr_drbg);
|
||||||
std::random_device rd;
|
std::random_device rd;
|
||||||
std::mt19937 g(rd());
|
std::mt19937 g(rd());
|
||||||
std::array<uint8_t, YARROW256_SEED_FILE_SIZE> seed;
|
std::array<uint8_t, 28> seed, key_iv;
|
||||||
for (unsigned i = 0; i < YARROW256_SEED_FILE_SIZE; i++)
|
for (unsigned i = 0; i < 28; i++)
|
||||||
seed[i] = (uint8_t)(g() % 255);
|
seed[i] = (uint8_t)(g() % 255);
|
||||||
yarrow256_seed(&ctx, YARROW256_SEED_FILE_SIZE, seed.data());
|
key_iv = seed;
|
||||||
std::array<uint8_t, 28> key_iv;
|
if (mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func,
|
||||||
yarrow256_random(&ctx, key_iv.size(), key_iv.data());
|
&entropy, seed.data(), seed.size()) == 0)
|
||||||
|
{
|
||||||
|
// If failed use the seed in the beginning
|
||||||
|
if (mbedtls_ctr_drbg_random((void*)&ctr_drbg, key_iv.data(),
|
||||||
|
key_iv.size()) != 0)
|
||||||
|
key_iv = seed;
|
||||||
|
}
|
||||||
m_client_key = base64({ key_iv.begin(), key_iv.begin() + 16 });
|
m_client_key = base64({ key_iv.begin(), key_iv.begin() + 16 });
|
||||||
m_client_iv = base64({ key_iv.begin() + 16, key_iv.end() });
|
m_client_iv = base64({ key_iv.begin() + 16, key_iv.end() });
|
||||||
}
|
}
|
||||||
@ -134,10 +114,16 @@ public:
|
|||||||
assert(iv.size() == 12);
|
assert(iv.size() == 12);
|
||||||
std::copy_n(iv.begin(), 12, m_iv.begin());
|
std::copy_n(iv.begin(), 12, m_iv.begin());
|
||||||
m_packet_counter = 0;
|
m_packet_counter = 0;
|
||||||
gcm_aes128_set_key(&m_aes_encrypt_context, key.data());
|
mbedtls_gcm_setkey(&m_aes_encrypt_context, MBEDTLS_CIPHER_ID_AES,
|
||||||
gcm_aes128_set_iv(&m_aes_encrypt_context, 12, iv.data());
|
key.data(), key.size() * 8);
|
||||||
gcm_aes128_set_key(&m_aes_decrypt_context, key.data());
|
mbedtls_gcm_setkey(&m_aes_decrypt_context, MBEDTLS_CIPHER_ID_AES,
|
||||||
gcm_aes128_set_iv(&m_aes_decrypt_context, 12, iv.data());
|
key.data(), key.size() * 8);
|
||||||
|
}
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
~Crypto()
|
||||||
|
{
|
||||||
|
mbedtls_gcm_free(&m_aes_encrypt_context);
|
||||||
|
mbedtls_gcm_free(&m_aes_decrypt_context);
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
bool encryptConnectionRequest(BareNetworkString& ns);
|
bool encryptConnectionRequest(BareNetworkString& ns);
|
||||||
@ -150,6 +136,6 @@ public:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // HEADER_CRYPTO_NETTLE_HPP
|
#endif // HEADER_CRYPTO_MBEDTLS_HPP
|
||||||
|
|
||||||
#endif
|
#endif
|
Loading…
Reference in New Issue
Block a user