mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-19 08:55:32 +01:00
Core/Crypto: Switch away from most deprecated openssl functions and removed upper version limit
This commit is contained in:
@@ -80,7 +80,6 @@ Set ``OPENSSL_MSVC_STATIC_RT`` set ``TRUE`` to choose the MT version of the lib.
|
||||
#]=======================================================================]
|
||||
|
||||
set(OPENSSL_EXPECTED_VERSION "1.0")
|
||||
set(OPENSSL_MAX_VERSION "1.2")
|
||||
|
||||
macro(_OpenSSL_test_and_find_dependencies ssl_library crypto_library)
|
||||
if((CMAKE_SYSTEM_NAME STREQUAL "Linux") AND
|
||||
@@ -604,7 +603,7 @@ if(OPENSSL_FOUND)
|
||||
message(STATUS "Found OpenSSL library: ${OPENSSL_LIBRARIES}")
|
||||
message(STATUS "Found OpenSSL headers: ${OPENSSL_INCLUDE_DIR}")
|
||||
include(EnsureVersion)
|
||||
ENSURE_VERSION_RANGE("${OPENSSL_EXPECTED_VERSION}" "${OPENSSL_VERSION}" "${OPENSSL_MAX_VERSION}" OPENSSL_VERSION_OK)
|
||||
ENSURE_VERSION("${OPENSSL_EXPECTED_VERSION}" "${OPENSSL_VERSION}" OPENSSL_VERSION_OK)
|
||||
if(NOT OPENSSL_VERSION_OK)
|
||||
message(FATAL_ERROR "TrinityCore needs OpenSSL version ${OPENSSL_EXPECTED_VERSION} but found too new version ${OPENSSL_VERSION}. TrinityCore needs OpenSSL 1.0.x or 1.1.x to work properly. If you still have problems please install OpenSSL 1.0.x if you still have problems search on forum for TCE00022")
|
||||
endif()
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace Crypto
|
||||
{
|
||||
struct Constants
|
||||
{
|
||||
static constexpr size_t MD5_DIGEST_LENGTH_BYTES = 16;
|
||||
static constexpr size_t SHA1_DIGEST_LENGTH_BYTES = 20;
|
||||
static constexpr size_t SHA256_DIGEST_LENGTH_BYTES = 32;
|
||||
};
|
||||
|
||||
@@ -35,10 +35,10 @@ namespace Trinity::Impl
|
||||
typedef EVP_MD const* (*HashCreator)();
|
||||
|
||||
#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
static EVP_MD_CTX* MakeCTX() { return EVP_MD_CTX_create(); }
|
||||
static EVP_MD_CTX* MakeCTX() noexcept { return EVP_MD_CTX_create(); }
|
||||
static void DestroyCTX(EVP_MD_CTX* ctx) { EVP_MD_CTX_destroy(ctx); }
|
||||
#else
|
||||
static EVP_MD_CTX* MakeCTX() { return EVP_MD_CTX_new(); }
|
||||
static EVP_MD_CTX* MakeCTX() noexcept { return EVP_MD_CTX_new(); }
|
||||
static void DestroyCTX(EVP_MD_CTX* ctx) { EVP_MD_CTX_free(ctx); }
|
||||
#endif
|
||||
};
|
||||
@@ -73,6 +73,16 @@ namespace Trinity::Impl
|
||||
ASSERT(result == 1);
|
||||
}
|
||||
|
||||
GenericHash(GenericHash const& right) : _ctx(GenericHashImpl::MakeCTX())
|
||||
{
|
||||
*this = right;
|
||||
}
|
||||
|
||||
GenericHash(GenericHash&& right) noexcept
|
||||
{
|
||||
*this = std::move(right);
|
||||
}
|
||||
|
||||
~GenericHash()
|
||||
{
|
||||
if (!_ctx)
|
||||
@@ -81,6 +91,27 @@ namespace Trinity::Impl
|
||||
_ctx = nullptr;
|
||||
}
|
||||
|
||||
GenericHash& operator=(GenericHash const& right)
|
||||
{
|
||||
if (this == &right)
|
||||
return *this;
|
||||
|
||||
int result = EVP_MD_CTX_copy(_ctx, right._ctx);
|
||||
ASSERT(result == 1);
|
||||
_digest = right._digest;
|
||||
return *this;
|
||||
}
|
||||
|
||||
GenericHash& operator=(GenericHash&& right) noexcept
|
||||
{
|
||||
if (this == &right)
|
||||
return *this;
|
||||
|
||||
_ctx = std::exchange(right._ctx, GenericHashImpl::MakeCTX());
|
||||
_digest = std::exchange(right._digest, Digest{});
|
||||
return *this;
|
||||
}
|
||||
|
||||
void UpdateData(uint8 const* data, size_t len)
|
||||
{
|
||||
int result = EVP_DigestUpdate(_ctx, data, len);
|
||||
@@ -98,8 +129,6 @@ namespace Trinity::Impl
|
||||
int result = EVP_DigestFinal_ex(_ctx, _digest.data(), &length);
|
||||
ASSERT(result == 1);
|
||||
ASSERT(length == DIGEST_LENGTH);
|
||||
GenericHashImpl::DestroyCTX(_ctx);
|
||||
_ctx = nullptr;
|
||||
}
|
||||
|
||||
Digest const& GetDigest() const { return _digest; }
|
||||
@@ -112,6 +141,7 @@ namespace Trinity::Impl
|
||||
|
||||
namespace Trinity::Crypto
|
||||
{
|
||||
using MD5 = Trinity::Impl::GenericHash<EVP_md5, Constants::MD5_DIGEST_LENGTH_BYTES>;
|
||||
using SHA1 = Trinity::Impl::GenericHash<EVP_sha1, Constants::SHA1_DIGEST_LENGTH_BYTES>;
|
||||
using SHA256 = Trinity::Impl::GenericHash<EVP_sha256, Constants::SHA256_DIGEST_LENGTH_BYTES>;
|
||||
}
|
||||
|
||||
@@ -19,41 +19,18 @@
|
||||
#define TRINITY_HMAC_H
|
||||
|
||||
#include "CryptoConstants.h"
|
||||
#include "CryptoHash.h"
|
||||
#include "Define.h"
|
||||
#include "Errors.h"
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <openssl/hmac.h>
|
||||
|
||||
class BigNumber;
|
||||
|
||||
namespace Trinity::Impl
|
||||
{
|
||||
struct HMACImpl
|
||||
{
|
||||
typedef EVP_MD const* (*HashCreator)();
|
||||
|
||||
#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
static HMAC_CTX* MakeCTX()
|
||||
{
|
||||
HMAC_CTX* ctx = new HMAC_CTX();
|
||||
HMAC_CTX_init(ctx);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static void DestroyCTX(HMAC_CTX* ctx)
|
||||
{
|
||||
HMAC_CTX_cleanup(ctx);
|
||||
delete ctx;
|
||||
}
|
||||
#else
|
||||
static HMAC_CTX* MakeCTX() { return HMAC_CTX_new(); }
|
||||
static void DestroyCTX(HMAC_CTX* ctx) { HMAC_CTX_free(ctx); }
|
||||
#endif
|
||||
};
|
||||
|
||||
template <HMACImpl::HashCreator HashCreator, size_t DigestLength>
|
||||
template <GenericHashImpl::HashCreator HashCreator, size_t DigestLength>
|
||||
class GenericHMAC
|
||||
{
|
||||
public:
|
||||
@@ -78,25 +55,58 @@ namespace Trinity::Impl
|
||||
return hash.GetDigest();
|
||||
}
|
||||
|
||||
GenericHMAC(uint8 const* seed, size_t len) : _ctx(HMACImpl::MakeCTX())
|
||||
GenericHMAC(uint8 const* seed, size_t len) : _ctx(GenericHashImpl::MakeCTX()), _key(EVP_PKEY_new_mac_key(EVP_PKEY_HMAC, nullptr, seed, len))
|
||||
{
|
||||
int result = HMAC_Init_ex(_ctx, seed, len, HashCreator(), nullptr);
|
||||
int result = EVP_DigestSignInit(_ctx, nullptr, HashCreator(), nullptr, _key);
|
||||
ASSERT(result == 1);
|
||||
}
|
||||
template <typename Container>
|
||||
GenericHMAC(Container const& container) : GenericHMAC(std::data(container), std::size(container)) {}
|
||||
|
||||
GenericHMAC(GenericHMAC const& right) : _ctx(GenericHashImpl::MakeCTX())
|
||||
{
|
||||
*this = right;
|
||||
}
|
||||
|
||||
GenericHMAC(GenericHMAC&& right) noexcept
|
||||
{
|
||||
*this = std::move(right);
|
||||
}
|
||||
|
||||
~GenericHMAC()
|
||||
{
|
||||
if (!_ctx)
|
||||
return;
|
||||
HMACImpl::DestroyCTX(_ctx);
|
||||
GenericHashImpl::DestroyCTX(_ctx);
|
||||
_ctx = nullptr;
|
||||
EVP_PKEY_free(_key);
|
||||
_key = nullptr;
|
||||
}
|
||||
|
||||
GenericHMAC& operator=(GenericHMAC const& right)
|
||||
{
|
||||
if (this == &right)
|
||||
return *this;
|
||||
|
||||
int result = EVP_MD_CTX_copy(_ctx, right._ctx);
|
||||
ASSERT(result == 1);
|
||||
_key = right._key; // EVP_PKEY uses reference counting internally, just copy the pointer
|
||||
_digest = right._digest;
|
||||
return *this;
|
||||
}
|
||||
|
||||
GenericHMAC& operator=(GenericHMAC&& right) noexcept
|
||||
{
|
||||
if (this == &right)
|
||||
return *this;
|
||||
|
||||
_ctx = std::exchange(right._ctx, GenericHashImpl::MakeCTX());
|
||||
_key = std::exchange(right._key, EVP_PKEY_new());
|
||||
_digest = std::exchange(right._digest, Digest{});
|
||||
return *this;
|
||||
}
|
||||
|
||||
void UpdateData(uint8 const* data, size_t len)
|
||||
{
|
||||
int result = HMAC_Update(_ctx, data, len);
|
||||
int result = EVP_DigestSignUpdate(_ctx, data, len);
|
||||
ASSERT(result == 1);
|
||||
}
|
||||
void UpdateData(std::string_view str) { UpdateData(reinterpret_cast<uint8 const*>(str.data()), str.size()); }
|
||||
@@ -107,17 +117,16 @@ namespace Trinity::Impl
|
||||
|
||||
void Finalize()
|
||||
{
|
||||
uint32 length = 0;
|
||||
int result = HMAC_Final(_ctx, _digest.data(), &length);
|
||||
size_t length = 0;
|
||||
int result = EVP_DigestSignFinal(_ctx, _digest.data(), &length);
|
||||
ASSERT(result == 1);
|
||||
ASSERT(length == DIGEST_LENGTH);
|
||||
HMACImpl::DestroyCTX(_ctx);
|
||||
_ctx = nullptr;
|
||||
}
|
||||
|
||||
Digest const& GetDigest() const { return _digest; }
|
||||
private:
|
||||
HMAC_CTX* _ctx;
|
||||
EVP_MD_CTX* _ctx;
|
||||
EVP_PKEY* _key;
|
||||
Digest _digest = { };
|
||||
};
|
||||
}
|
||||
|
||||
@@ -16,22 +16,12 @@
|
||||
*/
|
||||
|
||||
#include "RSA.h"
|
||||
#include "BigNumber.h"
|
||||
#include <openssl/bn.h>
|
||||
#include "HMAC.h"
|
||||
#include <openssl/pem.h>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#define CHECK_AND_DECLARE_FUNCTION_TYPE(name, publicKey, privateKey) \
|
||||
static_assert(std::is_same<decltype(&publicKey), decltype(&privateKey)>::value, \
|
||||
"Public key and private key functions must have the same signature"); \
|
||||
using name ## _t = decltype(&publicKey); \
|
||||
template <typename KeyTag> inline name ## _t get_ ## name () { return nullptr; } \
|
||||
template <> inline name ## _t get_ ## name<Trinity::Crypto::RSA::PublicKey>() { return &publicKey; } \
|
||||
template <> inline name ## _t get_ ## name<Trinity::Crypto::RSA::PrivateKey>() { return &privateKey; }
|
||||
|
||||
namespace
|
||||
{
|
||||
struct BIODeleter
|
||||
@@ -42,41 +32,170 @@ struct BIODeleter
|
||||
}
|
||||
};
|
||||
|
||||
CHECK_AND_DECLARE_FUNCTION_TYPE(PEM_read, PEM_read_bio_RSAPublicKey, PEM_read_bio_RSAPrivateKey);
|
||||
CHECK_AND_DECLARE_FUNCTION_TYPE(RSA_encrypt, RSA_public_encrypt, RSA_private_encrypt);
|
||||
}
|
||||
|
||||
Trinity::Crypto::RSA::RSA()
|
||||
struct HMAC_SHA256_MD
|
||||
{
|
||||
_rsa = RSA_new();
|
||||
struct CTX_DATA
|
||||
{
|
||||
Trinity::Crypto::HMAC_SHA256* hmac;
|
||||
};
|
||||
|
||||
#if TRINITY_COMPILER == TRINITY_COMPILER_GNU
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#else
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4996)
|
||||
#endif
|
||||
|
||||
HMAC_SHA256_MD()
|
||||
{
|
||||
_md = EVP_MD_meth_new(NID_sha256, NID_sha256WithRSAEncryption);
|
||||
EVP_MD_meth_set_result_size(_md, Trinity::Crypto::Constants::SHA256_DIGEST_LENGTH_BYTES);
|
||||
EVP_MD_meth_set_flags(_md, EVP_MD_FLAG_DIGALGID_ABSENT);
|
||||
EVP_MD_meth_set_init(_md, &Init);
|
||||
EVP_MD_meth_set_update(_md, &UpdateData);
|
||||
EVP_MD_meth_set_final(_md, &Finalize);
|
||||
EVP_MD_meth_set_copy(_md, &Copy);
|
||||
EVP_MD_meth_set_cleanup(_md, &Cleanup);
|
||||
EVP_MD_meth_set_input_blocksize(_md, SHA256_CBLOCK);
|
||||
EVP_MD_meth_set_app_datasize(_md, sizeof(EVP_MD*) + sizeof(CTX_DATA*));
|
||||
}
|
||||
|
||||
HMAC_SHA256_MD(HMAC_SHA256_MD const&) = delete;
|
||||
HMAC_SHA256_MD(HMAC_SHA256_MD&&) = delete;
|
||||
|
||||
HMAC_SHA256_MD& operator=(HMAC_SHA256_MD const&) = delete;
|
||||
HMAC_SHA256_MD& operator=(HMAC_SHA256_MD&&) = delete;
|
||||
|
||||
~HMAC_SHA256_MD()
|
||||
{
|
||||
EVP_MD_meth_free(_md);
|
||||
_md = nullptr;
|
||||
}
|
||||
|
||||
#if TRINITY_COMPILER == TRINITY_COMPILER_GNU
|
||||
#pragma GCC diagnostic pop
|
||||
#else
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
operator EVP_MD const* () const
|
||||
{
|
||||
return _md;
|
||||
}
|
||||
|
||||
static int Init(EVP_MD_CTX* ctx)
|
||||
{
|
||||
Cleanup(ctx);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int UpdateData(EVP_MD_CTX* ctx, const void* data, size_t count)
|
||||
{
|
||||
CTX_DATA* ctxData = reinterpret_cast<CTX_DATA*>(EVP_MD_CTX_md_data(ctx));
|
||||
if (!ctxData->hmac)
|
||||
return 0;
|
||||
|
||||
ctxData->hmac->UpdateData(reinterpret_cast<uint8 const*>(data), count);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int Finalize(EVP_MD_CTX* ctx, unsigned char* md)
|
||||
{
|
||||
CTX_DATA* ctxData = reinterpret_cast<CTX_DATA*>(EVP_MD_CTX_md_data(ctx));
|
||||
if (!ctxData->hmac)
|
||||
return 0;
|
||||
|
||||
ctxData->hmac->Finalize();
|
||||
memcpy(md, ctxData->hmac->GetDigest().data(), ctxData->hmac->GetDigest().size());
|
||||
return 1;
|
||||
}
|
||||
|
||||
// post-processing after openssl memcpys from source to dest (no need to cleanup dest)
|
||||
static int Copy(EVP_MD_CTX* to, EVP_MD_CTX const* from)
|
||||
{
|
||||
CTX_DATA const* ctxDataFrom = reinterpret_cast<CTX_DATA const*>(EVP_MD_CTX_md_data(from));
|
||||
CTX_DATA* ctxDataTo = reinterpret_cast<CTX_DATA*>(EVP_MD_CTX_md_data(to));
|
||||
|
||||
if (ctxDataFrom->hmac)
|
||||
ctxDataTo->hmac = new Trinity::Crypto::HMAC_SHA256(*ctxDataFrom->hmac);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int Cleanup(EVP_MD_CTX* ctx)
|
||||
{
|
||||
CTX_DATA* data = reinterpret_cast<CTX_DATA*>(EVP_MD_CTX_md_data(ctx));
|
||||
if (data->hmac)
|
||||
{
|
||||
delete data->hmac;
|
||||
data->hmac = nullptr;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private:
|
||||
EVP_MD* _md;
|
||||
} HmacSha256Md;
|
||||
}
|
||||
|
||||
Trinity::Crypto::RSA::RSA(RSA&& rsa)
|
||||
namespace Trinity::Crypto
|
||||
{
|
||||
_rsa = rsa._rsa;
|
||||
rsa._rsa = RSA_new();
|
||||
}
|
||||
|
||||
Trinity::Crypto::RSA::~RSA()
|
||||
EVP_MD const* RsaSignature::SHA256::GetGenerator() const
|
||||
{
|
||||
RSA_free(_rsa);
|
||||
return EVP_sha256();
|
||||
}
|
||||
|
||||
template <typename KeyTag>
|
||||
bool Trinity::Crypto::RSA::LoadFromFile(std::string const& fileName, KeyTag)
|
||||
void RsaSignature::SHA256::PostInitCustomizeContext(EVP_MD_CTX*)
|
||||
{
|
||||
}
|
||||
|
||||
EVP_MD const* RsaSignature::HMAC_SHA256::GetGenerator() const
|
||||
{
|
||||
return HmacSha256Md;
|
||||
}
|
||||
|
||||
void RsaSignature::HMAC_SHA256::PostInitCustomizeContext(EVP_MD_CTX* ctx)
|
||||
{
|
||||
HMAC_SHA256_MD::CTX_DATA* ctxData = reinterpret_cast<HMAC_SHA256_MD::CTX_DATA*>(EVP_MD_CTX_md_data(ctx));
|
||||
if (ctxData->hmac)
|
||||
delete ctxData->hmac;
|
||||
|
||||
ctxData->hmac = new Crypto::HMAC_SHA256(_key, _keyLength);
|
||||
}
|
||||
|
||||
RsaSignature::RsaSignature()
|
||||
{
|
||||
_ctx = Impl::GenericHashImpl::MakeCTX();
|
||||
}
|
||||
|
||||
RsaSignature::RsaSignature(RsaSignature&& rsa) noexcept
|
||||
{
|
||||
_ctx = rsa._ctx;
|
||||
rsa._ctx = Impl::GenericHashImpl::MakeCTX();
|
||||
}
|
||||
|
||||
RsaSignature::~RsaSignature()
|
||||
{
|
||||
EVP_MD_CTX_free(_ctx);
|
||||
}
|
||||
|
||||
bool RsaSignature::LoadKeyFromFile(std::string const& fileName)
|
||||
{
|
||||
std::unique_ptr<BIO, BIODeleter> keyBIO(BIO_new_file(fileName.c_str(), "r"));
|
||||
if (!keyBIO)
|
||||
return false;
|
||||
|
||||
if (!get_PEM_read<KeyTag>()(keyBIO.get(), &_rsa, nullptr, nullptr))
|
||||
_key = EVP_PKEY_new();
|
||||
if (!PEM_read_bio_PrivateKey(keyBIO.get(), &_key, nullptr, nullptr))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename KeyTag>
|
||||
bool Trinity::Crypto::RSA::LoadFromString(std::string const& keyPem, KeyTag)
|
||||
bool RsaSignature::LoadKeyFromString(std::string const& keyPem)
|
||||
{
|
||||
std::unique_ptr<BIO, BIODeleter> keyBIO(BIO_new_mem_buf(
|
||||
const_cast<char*>(keyPem.c_str()) /*api hack - this function assumes memory is readonly but lacks const modifier*/,
|
||||
@@ -84,51 +203,26 @@ bool Trinity::Crypto::RSA::LoadFromString(std::string const& keyPem, KeyTag)
|
||||
if (!keyBIO)
|
||||
return false;
|
||||
|
||||
if (!get_PEM_read<KeyTag>()(keyBIO.get(), &_rsa, nullptr, nullptr))
|
||||
_key = EVP_PKEY_new();
|
||||
if (!PEM_read_bio_PrivateKey(keyBIO.get(), &_key, nullptr, nullptr))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
BigNumber Trinity::Crypto::RSA::GetModulus() const
|
||||
bool RsaSignature::Sign(uint8 const* message, std::size_t messageLength, DigestGenerator& generator, std::vector<uint8>& output)
|
||||
{
|
||||
BigNumber bn;
|
||||
#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L
|
||||
const BIGNUM* rsa_n;
|
||||
RSA_get0_key(_rsa, &rsa_n, nullptr, nullptr);
|
||||
BN_copy(bn.BN(), rsa_n);
|
||||
#else
|
||||
BN_copy(bn.BN(), _rsa->n);
|
||||
#endif
|
||||
return bn;
|
||||
}
|
||||
size_t signatureLength = 0;
|
||||
EVP_DigestSignInit(_ctx, nullptr, generator.GetGenerator(), nullptr, _key);
|
||||
generator.PostInitCustomizeContext(_ctx);
|
||||
EVP_DigestSignUpdate(_ctx, message, messageLength);
|
||||
int result = EVP_DigestSignFinal(_ctx, nullptr, &signatureLength);
|
||||
if (result == 0)
|
||||
return false;
|
||||
|
||||
template <typename KeyTag>
|
||||
bool Trinity::Crypto::RSA::Encrypt(uint8 const* data, std::size_t dataLength, uint8* output, int32 paddingType)
|
||||
{
|
||||
std::vector<uint8> inputData(std::make_reverse_iterator(data + dataLength), std::make_reverse_iterator(data));
|
||||
int result = get_RSA_encrypt<KeyTag>()(inputData.size(), inputData.data(), output, _rsa, paddingType);
|
||||
std::reverse(output, output + GetOutputSize());
|
||||
return result != -1;
|
||||
}
|
||||
|
||||
bool Trinity::Crypto::RSA::Sign(int32 hashType, uint8 const* dataHash, std::size_t dataHashLength, uint8* output)
|
||||
{
|
||||
uint32 signatureLength = 0;
|
||||
int result = RSA_sign(hashType, dataHash, dataHashLength, output, &signatureLength, _rsa);
|
||||
std::reverse(output, output + GetOutputSize());
|
||||
output.resize(signatureLength);
|
||||
result = EVP_DigestSignFinal(_ctx, output.data(), &signatureLength);
|
||||
std::reverse(output.begin(), output.end());
|
||||
return result != 0;
|
||||
}
|
||||
|
||||
namespace Trinity
|
||||
{
|
||||
namespace Crypto
|
||||
{
|
||||
template TC_COMMON_API bool RSA::LoadFromFile(std::string const& fileName, RSA::PublicKey);
|
||||
template TC_COMMON_API bool RSA::LoadFromFile(std::string const& fileName, RSA::PrivateKey);
|
||||
template TC_COMMON_API bool RSA::LoadFromString(std::string const& keyPem, RSA::PublicKey);
|
||||
template TC_COMMON_API bool RSA::LoadFromString(std::string const& keyPem, RSA::PrivateKey);
|
||||
template TC_COMMON_API bool RSA::Encrypt<RSA::PublicKey>(uint8 const* data, std::size_t dataLength, uint8* output, int32 paddingType);
|
||||
template TC_COMMON_API bool RSA::Encrypt<RSA::PrivateKey>(uint8 const* data, std::size_t dataLength, uint8* output, int32 paddingType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,77 +15,75 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITYCORE_RSA_H
|
||||
#define TRINITYCORE_RSA_H
|
||||
|
||||
#include "Define.h"
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/rsa.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
class BigNumber;
|
||||
#include <vector>
|
||||
|
||||
namespace Trinity
|
||||
{
|
||||
namespace Crypto
|
||||
{
|
||||
class TC_COMMON_API RSA
|
||||
class TC_COMMON_API RsaSignature
|
||||
{
|
||||
public:
|
||||
struct PublicKey {};
|
||||
struct PrivateKey {};
|
||||
|
||||
struct NoPadding : std::integral_constant<int32, RSA_NO_PADDING> {};
|
||||
struct PKCS1Padding : std::integral_constant<int32, RSA_PKCS1_PADDING> {};
|
||||
|
||||
struct SHA256 : std::integral_constant<int32, NID_sha256> {};
|
||||
|
||||
RSA();
|
||||
RSA(RSA&& rsa);
|
||||
~RSA();
|
||||
|
||||
template <typename KeyTag>
|
||||
bool LoadFromFile(std::string const& fileName, KeyTag);
|
||||
|
||||
template <typename KeyTag>
|
||||
bool LoadFromString(std::string const& keyPem, KeyTag);
|
||||
|
||||
uint32 GetOutputSize() const { return uint32(RSA_size(_rsa)); }
|
||||
BigNumber GetModulus() const;
|
||||
|
||||
template <typename KeyTag, typename PaddingTag>
|
||||
bool Encrypt(uint8 const* data, std::size_t dataLength, uint8* output, KeyTag, PaddingTag)
|
||||
class TC_COMMON_API DigestGenerator
|
||||
{
|
||||
return Encrypt<KeyTag>(data, dataLength, output, PaddingTag::value);
|
||||
public:
|
||||
virtual ~DigestGenerator() = default;
|
||||
virtual EVP_MD const* GetGenerator() const = 0;
|
||||
virtual void PostInitCustomizeContext(EVP_MD_CTX* ctx) = 0;
|
||||
};
|
||||
|
||||
class TC_COMMON_API SHA256 : public DigestGenerator
|
||||
{
|
||||
public:
|
||||
EVP_MD const* GetGenerator() const override;
|
||||
void PostInitCustomizeContext(EVP_MD_CTX* ctx) override;
|
||||
};
|
||||
|
||||
class TC_COMMON_API HMAC_SHA256 : public DigestGenerator
|
||||
{
|
||||
public:
|
||||
explicit HMAC_SHA256(uint8 const* key, size_t keyLength) : _key(key), _keyLength(keyLength) { }
|
||||
|
||||
EVP_MD const* GetGenerator() const override;
|
||||
void PostInitCustomizeContext(EVP_MD_CTX* ctx) override;
|
||||
|
||||
private:
|
||||
uint8 const* _key;
|
||||
size_t _keyLength;
|
||||
};
|
||||
|
||||
|
||||
RsaSignature();
|
||||
RsaSignature(RsaSignature&& rsa) noexcept;
|
||||
~RsaSignature();
|
||||
|
||||
RsaSignature(RsaSignature const& rsa) = delete;
|
||||
RsaSignature& operator=(RsaSignature const& rsa) = delete;
|
||||
|
||||
bool LoadKeyFromFile(std::string const& fileName);
|
||||
|
||||
bool LoadKeyFromString(std::string const& keyPem);
|
||||
|
||||
template <std::size_t N>
|
||||
bool Sign(std::array<uint8, N> const& message, DigestGenerator& generator, std::vector<uint8>& output)
|
||||
{
|
||||
return this->Sign(message.data(), message.size(), generator, output);
|
||||
}
|
||||
|
||||
template <std::size_t N, typename KeyTag, typename PaddingTag>
|
||||
bool Encrypt(std::array<uint8, N> const& data, uint8* output, KeyTag, PaddingTag)
|
||||
{
|
||||
return Encrypt<KeyTag>(data.data(), data.size(), output, PaddingTag::value);
|
||||
}
|
||||
|
||||
template <typename HashTag>
|
||||
bool Sign(uint8 const* dataHash, std::size_t dataHashLength, uint8* output, HashTag)
|
||||
{
|
||||
return Sign(HashTag::value, dataHash, dataHashLength, output);
|
||||
}
|
||||
|
||||
template <std::size_t N, typename HashTag>
|
||||
bool Sign(std::array<uint8, N> const& dataHash, uint8* output, HashTag)
|
||||
{
|
||||
return Sign(HashTag::value, dataHash.data(), dataHash.size(), output);
|
||||
}
|
||||
bool Sign(uint8 const* message, std::size_t messageLength, DigestGenerator& generator, std::vector<uint8>& output);
|
||||
|
||||
private:
|
||||
template <typename KeyTag>
|
||||
bool Encrypt(uint8 const* data, std::size_t dataLength, uint8* output, int32 paddingType);
|
||||
|
||||
bool Sign(int32 hashType, uint8 const* dataHash, std::size_t dataHashLength, uint8* output);
|
||||
|
||||
RSA(RSA const& rsa) = delete;
|
||||
RSA& operator=(RSA const& rsa) = delete;
|
||||
|
||||
::RSA* _rsa;
|
||||
EVP_MD_CTX* _ctx = nullptr;
|
||||
EVP_PKEY* _key = nullptr;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TRINITYCORE_RSA_H
|
||||
|
||||
@@ -126,7 +126,7 @@ int main(int argc, char** argv)
|
||||
[]()
|
||||
{
|
||||
TC_LOG_INFO("server.bnetserver", "Using configuration file %s.", sConfigMgr->GetFilename().c_str());
|
||||
TC_LOG_INFO("server.bnetserver", "Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION));
|
||||
TC_LOG_INFO("server.bnetserver", "Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, OpenSSL_version(OPENSSL_VERSION));
|
||||
TC_LOG_INFO("server.bnetserver", "Using Boost version: %i.%i.%i", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -234,13 +234,13 @@ OHYtKG3GK3GEcFDwZU2LPHq21EroUAdtRfbrJ4KW2yc8igtXKxTBYw==
|
||||
-----END RSA PRIVATE KEY-----
|
||||
)";
|
||||
|
||||
std::unique_ptr<Trinity::Crypto::RSA> ConnectToRSA;
|
||||
std::unique_ptr<Trinity::Crypto::RsaSignature> ConnectToRSA;
|
||||
}
|
||||
|
||||
bool WorldPackets::Auth::ConnectTo::InitializeEncryption()
|
||||
{
|
||||
std::unique_ptr<Trinity::Crypto::RSA> rsa = std::make_unique<Trinity::Crypto::RSA>();
|
||||
if (!rsa->LoadFromString(RSAPrivateKey, Trinity::Crypto::RSA::PrivateKey{}))
|
||||
std::unique_ptr<Trinity::Crypto::RsaSignature> rsa = std::make_unique<Trinity::Crypto::RsaSignature>();
|
||||
if (!rsa->LoadKeyFromString(RSAPrivateKey))
|
||||
return false;
|
||||
|
||||
ConnectToRSA = std::move(rsa);
|
||||
@@ -270,16 +270,15 @@ WorldPacket const* WorldPackets::Auth::ConnectTo::Write()
|
||||
break;
|
||||
}
|
||||
|
||||
uint32 type = Payload.Where.Type;
|
||||
Trinity::Crypto::SHA256 hash;
|
||||
hash.UpdateData(whereBuffer.contents(), whereBuffer.size());
|
||||
hash.UpdateData(reinterpret_cast<uint8 const*>(&type), 4);
|
||||
hash.UpdateData(reinterpret_cast<uint8 const*>(&Payload.Port), 2);
|
||||
hash.Finalize();
|
||||
ByteBuffer signBuffer;
|
||||
signBuffer.append(whereBuffer);
|
||||
signBuffer << uint32(Payload.Where.Type);
|
||||
signBuffer << uint16(Payload.Port);
|
||||
Trinity::Crypto::RsaSignature::SHA256 digestGenerator;
|
||||
std::vector<uint8> signature;
|
||||
ConnectToRSA->Sign(signBuffer.contents(), signBuffer.size(), digestGenerator, signature);
|
||||
|
||||
ConnectToRSA->Sign(hash.GetDigest(), Payload.Signature.data(), Trinity::Crypto::RSA::SHA256{});
|
||||
|
||||
_worldPacket.append(Payload.Signature.data(), Payload.Signature.size());
|
||||
_worldPacket.append(signature.data(), signature.size());
|
||||
_worldPacket.append(whereBuffer);
|
||||
_worldPacket << uint16(Payload.Port);
|
||||
_worldPacket << uint32(Serial);
|
||||
@@ -307,15 +306,16 @@ uint8 constexpr EnableEncryptionSeed[16] = { 0x90, 0x9C, 0xD0, 0x50, 0x5A, 0x2C,
|
||||
|
||||
WorldPacket const* WorldPackets::Auth::EnterEncryptedMode::Write()
|
||||
{
|
||||
Trinity::Crypto::HMAC_SHA256 hash(EncryptionKey, 16);
|
||||
hash.UpdateData(reinterpret_cast<uint8 const*>(&Enabled), 1);
|
||||
hash.UpdateData(EnableEncryptionSeed, 16);
|
||||
hash.Finalize();
|
||||
std::array<uint8, 17> msg{};
|
||||
msg[0] = Enabled ? 1 : 0;
|
||||
std::copy_n(std::begin(EnableEncryptionSeed), std::size(EnableEncryptionSeed), &msg[1]);
|
||||
|
||||
_worldPacket.resize(_worldPacket.size() + ConnectToRSA->GetOutputSize());
|
||||
Trinity::Crypto::RsaSignature::HMAC_SHA256 digestGenerator(EncryptionKey, 16);
|
||||
std::vector<uint8> signature;
|
||||
|
||||
ConnectToRSA->Sign(hash.GetDigest(), _worldPacket.contents(), Trinity::Crypto::RSA::SHA256{});
|
||||
ConnectToRSA->Sign(msg, digestGenerator, signature);
|
||||
|
||||
_worldPacket.append(signature.data(), signature.size());
|
||||
_worldPacket.WriteBit(Enabled);
|
||||
_worldPacket.FlushBits();
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "AccountMgr.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "Common.h"
|
||||
#include "CryptoHash.h"
|
||||
#include "GameTime.h"
|
||||
#include "Log.h"
|
||||
#include "SmartEnum.h"
|
||||
@@ -27,10 +28,6 @@
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
#include <openssl/md5.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#include <charconv>
|
||||
|
||||
Warden::Warden() : _session(nullptr), _checkTimer(10 * IN_MILLISECONDS), _clientResponseTimer(0),
|
||||
@@ -48,10 +45,7 @@ void Warden::MakeModuleForClient()
|
||||
TC_LOG_DEBUG("warden", "Make module for client");
|
||||
InitializeModuleForClient(_module.emplace());
|
||||
|
||||
MD5_CTX ctx;
|
||||
MD5_Init(&ctx);
|
||||
MD5_Update(&ctx, _module->CompressedData, _module->CompressedSize);
|
||||
MD5_Final(_module->Id.data(), &ctx);
|
||||
_module->Id = Trinity::Crypto::MD5::GetDigestOf(_module->CompressedData, _module->CompressedSize);
|
||||
}
|
||||
|
||||
void Warden::SendModuleToClient()
|
||||
@@ -161,28 +155,19 @@ bool Warden::IsValidCheckSum(uint32 checksum, uint8 const* data, const uint16 le
|
||||
}
|
||||
}
|
||||
|
||||
struct keyData {
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8 bytes[20];
|
||||
} bytes;
|
||||
|
||||
struct
|
||||
{
|
||||
uint32 ints[5];
|
||||
} ints;
|
||||
};
|
||||
union keyData
|
||||
{
|
||||
std::array<uint8, 20> bytes;
|
||||
std::array<uint32, 5> ints;
|
||||
};
|
||||
|
||||
uint32 Warden::BuildChecksum(uint8 const* data, uint32 length)
|
||||
{
|
||||
keyData hash;
|
||||
SHA1(data, length, hash.bytes.bytes);
|
||||
hash.bytes = Trinity::Crypto::SHA1::GetDigestOf(data, size_t(length));
|
||||
uint32 checkSum = 0;
|
||||
for (uint8 i = 0; i < 5; ++i)
|
||||
checkSum = checkSum ^ hash.ints.ints[i];
|
||||
checkSum = checkSum ^ hash.ints[i];
|
||||
|
||||
return checkSum;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "WardenMac.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "Common.h"
|
||||
#include "CryptoHash.h"
|
||||
#include "GameTime.h"
|
||||
#include "Log.h"
|
||||
#include "Opcodes.h"
|
||||
@@ -27,7 +28,6 @@
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
#include <openssl/md5.h>
|
||||
#include <array>
|
||||
|
||||
WardenMac::WardenMac() : Warden() { }
|
||||
@@ -230,12 +230,7 @@ void WardenMac::HandleCheckResult(ByteBuffer &buff)
|
||||
//found = true;
|
||||
}
|
||||
|
||||
MD5_CTX ctx;
|
||||
MD5_Init(&ctx);
|
||||
MD5_Update(&ctx, str.c_str(), str.size());
|
||||
std::array<uint8, 16> ourMD5Hash;
|
||||
MD5_Final(ourMD5Hash.data(), &ctx);
|
||||
|
||||
std::array<uint8, 16> ourMD5Hash = Trinity::Crypto::MD5::GetDigestOf(str);
|
||||
std::array<uint8, 16> theirsMD5Hash;
|
||||
buff.read(theirsMD5Hash);
|
||||
|
||||
|
||||
@@ -208,7 +208,7 @@ extern int main(int argc, char** argv)
|
||||
[]()
|
||||
{
|
||||
TC_LOG_INFO("server.worldserver", "Using configuration file %s.", sConfigMgr->GetFilename().c_str());
|
||||
TC_LOG_INFO("server.worldserver", "Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, SSLeay_version(SSLEAY_VERSION));
|
||||
TC_LOG_INFO("server.worldserver", "Using SSL version: %s (library: %s)", OPENSSL_VERSION_TEXT, OpenSSL_version(OPENSSL_VERSION));
|
||||
TC_LOG_INFO("server.worldserver", "Using Boost version: %i.%i.%i", BOOST_VERSION / 100000, BOOST_VERSION / 100 % 1000, BOOST_VERSION % 100);
|
||||
}
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user