mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-16 07:30:42 +01:00
Core/Authserver: Authserver cleanup (PR#25093)
- Fix a handful of 1/256 bugs with most significant byte zero in BigNumber - Get rid of (most of) the C-style arrays in authserver - CryptoRandom as a unified source for cryptographic randomness - Bring our other crypto APIs into 2020 - BigNumber usability improvements - Authserver is now actually readable as a result of all of the above
This commit is contained in:
@@ -37,7 +37,7 @@ void Trinity::Crypto::AES::Init(Key const& key)
|
||||
ASSERT(status);
|
||||
}
|
||||
|
||||
bool Trinity::Crypto::AES::Process(IV const& iv, uint8* data, std::size_t length, Tag& tag)
|
||||
bool Trinity::Crypto::AES::Process(IV const& iv, uint8* data, size_t length, Tag& tag)
|
||||
{
|
||||
ASSERT(length <= std::numeric_limits<int>::max());
|
||||
int len = static_cast<int>(length);
|
||||
|
||||
@@ -22,33 +22,30 @@
|
||||
#include <array>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
namespace Trinity
|
||||
namespace Trinity::Crypto
|
||||
{
|
||||
namespace Crypto
|
||||
{
|
||||
class TC_COMMON_API AES
|
||||
{
|
||||
public:
|
||||
static constexpr std::size_t IV_SIZE_BYTES = 12;
|
||||
static constexpr std::size_t KEY_SIZE_BYTES = 16;
|
||||
static constexpr std::size_t TAG_SIZE_BYTES = 12;
|
||||
class TC_COMMON_API AES
|
||||
{
|
||||
public:
|
||||
static constexpr size_t IV_SIZE_BYTES = 12;
|
||||
static constexpr size_t KEY_SIZE_BYTES = 16;
|
||||
static constexpr size_t TAG_SIZE_BYTES = 12;
|
||||
|
||||
using IV = std::array<uint8, IV_SIZE_BYTES>;
|
||||
using Key = std::array<uint8, KEY_SIZE_BYTES>;
|
||||
using Tag = uint8[TAG_SIZE_BYTES];
|
||||
using IV = std::array<uint8, IV_SIZE_BYTES>;
|
||||
using Key = std::array<uint8, KEY_SIZE_BYTES>;
|
||||
using Tag = uint8[TAG_SIZE_BYTES];
|
||||
|
||||
AES(bool encrypting);
|
||||
~AES();
|
||||
AES(bool encrypting);
|
||||
~AES();
|
||||
|
||||
void Init(Key const& key);
|
||||
void Init(Key const& key);
|
||||
|
||||
bool Process(IV const& iv, uint8* data, std::size_t length, Tag& tag);
|
||||
bool Process(IV const& iv, uint8* data, size_t length, Tag& tag);
|
||||
|
||||
private:
|
||||
EVP_CIPHER_CTX* _ctx;
|
||||
bool _encrypting;
|
||||
};
|
||||
}
|
||||
private:
|
||||
EVP_CIPHER_CTX* _ctx;
|
||||
bool _encrypting;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // Trinity_AES_h__
|
||||
|
||||
@@ -16,35 +16,33 @@
|
||||
*/
|
||||
|
||||
#include "ARC4.h"
|
||||
#include "Errors.h"
|
||||
|
||||
ARC4::ARC4(uint32 len) : m_ctx(EVP_CIPHER_CTX_new())
|
||||
Trinity::Crypto::ARC4::ARC4() : _ctx(EVP_CIPHER_CTX_new())
|
||||
{
|
||||
EVP_CIPHER_CTX_init(m_ctx);
|
||||
EVP_EncryptInit_ex(m_ctx, EVP_rc4(), nullptr, nullptr, nullptr);
|
||||
EVP_CIPHER_CTX_set_key_length(m_ctx, len);
|
||||
EVP_CIPHER_CTX_init(_ctx);
|
||||
int result = EVP_EncryptInit_ex(_ctx, EVP_rc4(), nullptr, nullptr, nullptr);
|
||||
ASSERT(result == 1);
|
||||
}
|
||||
|
||||
ARC4::ARC4(uint8* seed, uint32 len) : m_ctx(EVP_CIPHER_CTX_new())
|
||||
Trinity::Crypto::ARC4::~ARC4()
|
||||
{
|
||||
EVP_CIPHER_CTX_init(m_ctx);
|
||||
EVP_EncryptInit_ex(m_ctx, EVP_rc4(), nullptr, nullptr, nullptr);
|
||||
EVP_CIPHER_CTX_set_key_length(m_ctx, len);
|
||||
EVP_EncryptInit_ex(m_ctx, nullptr, nullptr, seed, nullptr);
|
||||
EVP_CIPHER_CTX_free(_ctx);
|
||||
}
|
||||
|
||||
ARC4::~ARC4()
|
||||
void Trinity::Crypto::ARC4::Init(uint8 const* seed, size_t len)
|
||||
{
|
||||
EVP_CIPHER_CTX_free(m_ctx);
|
||||
int result1 = EVP_CIPHER_CTX_set_key_length(_ctx, len);
|
||||
ASSERT(result1 == 1);
|
||||
int result2 = EVP_EncryptInit_ex(_ctx, nullptr, nullptr, seed, nullptr);
|
||||
ASSERT(result2 == 1);
|
||||
}
|
||||
|
||||
void ARC4::Init(uint8* seed)
|
||||
{
|
||||
EVP_EncryptInit_ex(m_ctx, nullptr, nullptr, seed, nullptr);
|
||||
}
|
||||
|
||||
void ARC4::UpdateData(int len, uint8* data)
|
||||
void Trinity::Crypto::ARC4::UpdateData(uint8* data, size_t len)
|
||||
{
|
||||
int outlen = 0;
|
||||
EVP_EncryptUpdate(m_ctx, data, &outlen, data, len);
|
||||
EVP_EncryptFinal_ex(m_ctx, data, &outlen);
|
||||
int result1 = EVP_EncryptUpdate(_ctx, data, &outlen, data, len);
|
||||
ASSERT(result1 == 1);
|
||||
int result2 = EVP_EncryptFinal_ex(_ctx, data, &outlen);
|
||||
ASSERT(result2 == 1);
|
||||
}
|
||||
|
||||
@@ -19,18 +19,27 @@
|
||||
#define _AUTH_SARC4_H
|
||||
|
||||
#include "Define.h"
|
||||
#include <array>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
class TC_COMMON_API ARC4
|
||||
namespace Trinity::Crypto
|
||||
{
|
||||
public:
|
||||
ARC4(uint32 len);
|
||||
ARC4(uint8* seed, uint32 len);
|
||||
~ARC4();
|
||||
void Init(uint8* seed);
|
||||
void UpdateData(int len, uint8* data);
|
||||
private:
|
||||
EVP_CIPHER_CTX* m_ctx;
|
||||
};
|
||||
class TC_COMMON_API ARC4
|
||||
{
|
||||
public:
|
||||
ARC4();
|
||||
~ARC4();
|
||||
|
||||
void Init(uint8 const* seed, size_t len);
|
||||
template <typename Container>
|
||||
void Init(Container const& c) { Init(std::data(c), std::size(c)); }
|
||||
|
||||
void UpdateData(uint8* data, size_t len);
|
||||
template <typename Container>
|
||||
void UpdateData(Container& c) { UpdateData(std::data(c), std::size(c)); }
|
||||
private:
|
||||
EVP_CIPHER_CTX* _ctx;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -21,12 +21,13 @@
|
||||
/*static*/ Optional<std::string> Trinity::Crypto::Argon2::Hash(std::string const& password, BigNumber const& salt, uint32 nIterations, uint32 kibMemoryCost)
|
||||
{
|
||||
char buf[ENCODED_HASH_LEN];
|
||||
std::vector<uint8> saltBytes = salt.ToByteVector();
|
||||
int status = argon2id_hash_encoded(
|
||||
nIterations,
|
||||
kibMemoryCost,
|
||||
PARALLELISM,
|
||||
password.c_str(), password.length(),
|
||||
salt.AsByteArray().get(), salt.GetNumBytes(),
|
||||
saltBytes.data(), saltBytes.size(),
|
||||
HASH_LEN, buf, ENCODED_HASH_LEN
|
||||
);
|
||||
|
||||
|
||||
@@ -23,22 +23,19 @@
|
||||
#include "Optional.h"
|
||||
#include <string>
|
||||
|
||||
namespace Trinity
|
||||
namespace Trinity::Crypto
|
||||
{
|
||||
namespace Crypto
|
||||
{
|
||||
struct TC_COMMON_API Argon2
|
||||
{
|
||||
static constexpr uint32 HASH_LEN = 16; // 128 bits, in bytes
|
||||
static constexpr uint32 ENCODED_HASH_LEN = 100; // in chars
|
||||
static constexpr uint32 DEFAULT_ITERATIONS = 10; // determined by dice roll, guaranteed to be secure (not really)
|
||||
static constexpr uint32 DEFAULT_MEMORY_COST = (1u << 17); // 2^17 kibibytes is 2^7 mebibytes is ~100MB
|
||||
static constexpr uint32 PARALLELISM = 1; // we don't support threaded hashing
|
||||
struct TC_COMMON_API Argon2
|
||||
{
|
||||
static constexpr uint32 HASH_LEN = 16; // 128 bits, in bytes
|
||||
static constexpr uint32 ENCODED_HASH_LEN = 100; // in chars
|
||||
static constexpr uint32 DEFAULT_ITERATIONS = 10; // determined by dice roll, guaranteed to be secure (not really)
|
||||
static constexpr uint32 DEFAULT_MEMORY_COST = (1u << 17); // 2^17 kibibytes is 2^7 mebibytes is ~100MB
|
||||
static constexpr uint32 PARALLELISM = 1; // we don't support threaded hashing
|
||||
|
||||
static Optional<std::string> Hash(std::string const& password, BigNumber const& salt, uint32 nIterations = DEFAULT_ITERATIONS, uint32 kibMemoryCost = DEFAULT_MEMORY_COST);
|
||||
static bool Verify(std::string const& password, std::string const& hash);
|
||||
};
|
||||
}
|
||||
static Optional<std::string> Hash(std::string const& password, BigNumber const& salt, uint32 nIterations = DEFAULT_ITERATIONS, uint32 kibMemoryCost = DEFAULT_MEMORY_COST);
|
||||
static bool Verify(std::string const& password, std::string const& hash);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -16,58 +16,39 @@
|
||||
*/
|
||||
|
||||
#include "AuthCrypt.h"
|
||||
#include "Cryptography/HMACSHA1.h"
|
||||
#include "Cryptography/BigNumber.h"
|
||||
#include "BigNumber.h"
|
||||
#include "Errors.h"
|
||||
#include "HMAC.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
AuthCrypt::AuthCrypt() :
|
||||
_clientDecrypt(SHA_DIGEST_LENGTH), _serverEncrypt(SHA_DIGEST_LENGTH),
|
||||
_initialized(false)
|
||||
{ }
|
||||
|
||||
void AuthCrypt::Init(BigNumber* K)
|
||||
void AuthCrypt::Init(std::array<uint8, 40> const& K)
|
||||
{
|
||||
uint8 ServerEncryptionKey[SEED_KEY_SIZE] = { 0xCC, 0x98, 0xAE, 0x04, 0xE8, 0x97, 0xEA, 0xCA, 0x12, 0xDD, 0xC0, 0x93, 0x42, 0x91, 0x53, 0x57 };
|
||||
HmacHash serverEncryptHmac(SEED_KEY_SIZE, (uint8*)ServerEncryptionKey);
|
||||
uint8 *encryptHash = serverEncryptHmac.ComputeHash(K);
|
||||
|
||||
uint8 ServerDecryptionKey[SEED_KEY_SIZE] = { 0xC2, 0xB3, 0x72, 0x3C, 0xC6, 0xAE, 0xD9, 0xB5, 0x34, 0x3C, 0x53, 0xEE, 0x2F, 0x43, 0x67, 0xCE };
|
||||
HmacHash clientDecryptHmac(SEED_KEY_SIZE, (uint8*)ServerDecryptionKey);
|
||||
uint8 *decryptHash = clientDecryptHmac.ComputeHash(K);
|
||||
|
||||
//ARC4 _serverDecrypt(encryptHash);
|
||||
_clientDecrypt.Init(decryptHash);
|
||||
_serverEncrypt.Init(encryptHash);
|
||||
//ARC4 _clientEncrypt(decryptHash);
|
||||
uint8 ServerEncryptionKey[] = { 0xCC, 0x98, 0xAE, 0x04, 0xE8, 0x97, 0xEA, 0xCA, 0x12, 0xDD, 0xC0, 0x93, 0x42, 0x91, 0x53, 0x57 };
|
||||
_serverEncrypt.Init(Trinity::Crypto::HMAC_SHA1::GetDigestOf(ServerEncryptionKey, K));
|
||||
uint8 ServerDecryptionKey[] = { 0xC2, 0xB3, 0x72, 0x3C, 0xC6, 0xAE, 0xD9, 0xB5, 0x34, 0x3C, 0x53, 0xEE, 0x2F, 0x43, 0x67, 0xCE };
|
||||
_clientDecrypt.Init(Trinity::Crypto::HMAC_SHA1::GetDigestOf(ServerDecryptionKey, K));
|
||||
|
||||
// Drop first 1024 bytes, as WoW uses ARC4-drop1024.
|
||||
uint8 syncBuf[1024];
|
||||
memset(syncBuf, 0, 1024);
|
||||
|
||||
_serverEncrypt.UpdateData(1024, syncBuf);
|
||||
//_clientEncrypt.UpdateData(1024, syncBuf);
|
||||
|
||||
memset(syncBuf, 0, 1024);
|
||||
|
||||
//_serverDecrypt.UpdateData(1024, syncBuf);
|
||||
_clientDecrypt.UpdateData(1024, syncBuf);
|
||||
std::array<uint8, 1024> syncBuf;
|
||||
_serverEncrypt.UpdateData(syncBuf);
|
||||
_clientDecrypt.UpdateData(syncBuf);
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
|
||||
void AuthCrypt::DecryptRecv(uint8 *data, size_t len)
|
||||
{
|
||||
if (!_initialized)
|
||||
return;
|
||||
|
||||
_clientDecrypt.UpdateData(len, data);
|
||||
ASSERT(_initialized);
|
||||
_clientDecrypt.UpdateData(data, len);
|
||||
}
|
||||
|
||||
void AuthCrypt::EncryptSend(uint8 *data, size_t len)
|
||||
{
|
||||
if (!_initialized)
|
||||
return;
|
||||
|
||||
_serverEncrypt.UpdateData(len, data);
|
||||
ASSERT(_initialized);
|
||||
_serverEncrypt.UpdateData(data, len);
|
||||
}
|
||||
|
||||
@@ -18,24 +18,23 @@
|
||||
#ifndef _AUTHCRYPT_H
|
||||
#define _AUTHCRYPT_H
|
||||
|
||||
#include "Cryptography/ARC4.h"
|
||||
|
||||
class BigNumber;
|
||||
#include "ARC4.h"
|
||||
#include <array>
|
||||
|
||||
class TC_COMMON_API AuthCrypt
|
||||
{
|
||||
public:
|
||||
AuthCrypt();
|
||||
|
||||
void Init(BigNumber* K);
|
||||
void DecryptRecv(uint8 *, size_t);
|
||||
void EncryptSend(uint8 *, size_t);
|
||||
void Init(std::array<uint8, 40> const& K);
|
||||
void DecryptRecv(uint8* data, size_t len);
|
||||
void EncryptSend(uint8* data, size_t len);
|
||||
|
||||
bool IsInitialized() const { return _initialized; }
|
||||
|
||||
private:
|
||||
ARC4 _clientDecrypt;
|
||||
ARC4 _serverEncrypt;
|
||||
Trinity::Crypto::ARC4 _clientDecrypt;
|
||||
Trinity::Crypto::ARC4 _serverEncrypt;
|
||||
bool _initialized;
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -30,12 +30,6 @@ BigNumber::BigNumber(BigNumber const& bn)
|
||||
: _bn(BN_dup(bn._bn))
|
||||
{ }
|
||||
|
||||
BigNumber::BigNumber(uint32 val)
|
||||
: _bn(BN_new())
|
||||
{
|
||||
BN_set_word(_bn, val);
|
||||
}
|
||||
|
||||
BigNumber::~BigNumber()
|
||||
{
|
||||
BN_free(_bn);
|
||||
@@ -185,15 +179,14 @@ bool BigNumber::IsNegative() const
|
||||
return BN_is_negative(_bn);
|
||||
}
|
||||
|
||||
bool BigNumber::AsByteArray(uint8* buf, std::size_t bufsize, bool littleEndian) const
|
||||
void BigNumber::GetBytes(uint8* buf, std::size_t bufsize, bool littleEndian) const
|
||||
{
|
||||
int nBytes = GetNumBytes();
|
||||
ASSERT(!(nBytes < 0));
|
||||
ASSERT(nBytes >= 0, "Bignum has negative number of bytes (%d).", nBytes);
|
||||
std::size_t numBytes = static_cast<std::size_t>(nBytes);
|
||||
|
||||
// too large to store
|
||||
if (bufsize < numBytes)
|
||||
return false;
|
||||
ASSERT(numBytes <= bufsize, "Buffer of size %zu is too small to hold bignum with %zu bytes.\n", bufsize, numBytes);
|
||||
|
||||
// If we need more bytes than length of BigNumber set the rest to 0
|
||||
if (numBytes < bufsize)
|
||||
@@ -204,18 +197,15 @@ bool BigNumber::AsByteArray(uint8* buf, std::size_t bufsize, bool littleEndian)
|
||||
// openssl's BN stores data internally in big endian format, reverse if little endian desired
|
||||
if (littleEndian)
|
||||
std::reverse(buf, buf + bufsize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<uint8[]> BigNumber::AsByteArray(int32 minSize, bool littleEndian) const
|
||||
std::vector<uint8> BigNumber::ToByteVector(int32 minSize, bool littleEndian) const
|
||||
{
|
||||
std::size_t length = std::max(GetNumBytes(), minSize);
|
||||
uint8* array = new uint8[length];
|
||||
bool success = AsByteArray(array, length, littleEndian);
|
||||
ASSERT(success);
|
||||
|
||||
return std::unique_ptr<uint8[]>(array);
|
||||
std::vector<uint8> v;
|
||||
v.resize(length);
|
||||
GetBytes(v.data(), length, littleEndian);
|
||||
return v;
|
||||
}
|
||||
|
||||
std::string BigNumber::AsHexStr() const
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
struct bignum_st;
|
||||
|
||||
@@ -30,13 +31,20 @@ class TC_COMMON_API BigNumber
|
||||
public:
|
||||
BigNumber();
|
||||
BigNumber(BigNumber const& bn);
|
||||
BigNumber(uint32);
|
||||
BigNumber(uint32 v) : BigNumber() { SetDword(v); }
|
||||
BigNumber(std::string const& v) : BigNumber() { SetHexStr(v); }
|
||||
template <size_t Size>
|
||||
BigNumber(std::array<uint8, Size> const& v) : BigNumber() { SetBinary(v.data(), Size); }
|
||||
|
||||
~BigNumber();
|
||||
|
||||
void SetDword(uint32);
|
||||
void SetQword(uint64);
|
||||
void SetBinary(uint8 const* bytes, int32 len);
|
||||
template <typename Container>
|
||||
void SetBinary(Container const& c) { SetBinary(std::data(c), std::size(c)); }
|
||||
bool SetHexStr(char const* str);
|
||||
bool SetHexStr(std::string const& str) { return SetHexStr(str.c_str()); }
|
||||
|
||||
void SetRand(int32 numbits);
|
||||
|
||||
@@ -103,12 +111,14 @@ class TC_COMMON_API BigNumber
|
||||
|
||||
uint32 AsDword() const;
|
||||
|
||||
bool AsByteArray(uint8* buf, std::size_t bufsize, bool littleEndian = true) const;
|
||||
std::unique_ptr<uint8[]> AsByteArray(int32 minSize = 0, bool littleEndian = true) const;
|
||||
template <std::size_t N> std::array<uint8, N> AsByteArray(bool littleEndian = true) const
|
||||
void GetBytes(uint8* buf, size_t bufsize, bool littleEndian = true) const;
|
||||
std::vector<uint8> ToByteVector(int32 minSize = 0, bool littleEndian = true) const;
|
||||
|
||||
template <std::size_t Size>
|
||||
std::array<uint8, Size> ToByteArray(bool littleEndian = true) const
|
||||
{
|
||||
std::array<uint8, N> buf;
|
||||
AsByteArray(buf.data(), N, littleEndian);
|
||||
std::array<uint8, Size> buf;
|
||||
GetBytes(buf.data(), Size, littleEndian);
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,31 +15,18 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _AUTH_HMAC_H
|
||||
#define _AUTH_HMAC_H
|
||||
#ifndef TRINITY_CRYPTO_CONSTANTS_H
|
||||
#define TRINITY_CRYPTO_CONSTANTS_H
|
||||
|
||||
#include "Define.h"
|
||||
#include <string>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
class BigNumber;
|
||||
|
||||
#define SEED_KEY_SIZE 16
|
||||
|
||||
class TC_COMMON_API HmacHash
|
||||
namespace Trinity::Crypto
|
||||
{
|
||||
public:
|
||||
HmacHash(uint32 len, uint8* seed);
|
||||
~HmacHash();
|
||||
void UpdateData(std::string const& str);
|
||||
void UpdateData(uint8 const* data, size_t len);
|
||||
void Finalize();
|
||||
uint8* ComputeHash(BigNumber* bn);
|
||||
uint8* GetDigest() { return m_digest; }
|
||||
int GetLength() const { return SHA_DIGEST_LENGTH; }
|
||||
private:
|
||||
HMAC_CTX* m_ctx;
|
||||
uint8 m_digest[SHA_DIGEST_LENGTH];
|
||||
};
|
||||
struct Constants
|
||||
{
|
||||
static constexpr size_t SHA1_DIGEST_LENGTH_BYTES = 20;
|
||||
static constexpr size_t SHA256_DIGEST_LENGTH_BYTES = 32;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -19,96 +19,92 @@
|
||||
#define TRINITY_CRYPTO_GENERICS_HPP
|
||||
|
||||
#include "BigNumber.h"
|
||||
#include "CryptoRandom.h"
|
||||
#include "Define.h"
|
||||
#include "Errors.h"
|
||||
#include <iterator>
|
||||
#include <vector>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
namespace Trinity
|
||||
namespace Trinity::Impl
|
||||
{
|
||||
namespace Impl
|
||||
struct CryptoGenericsImpl
|
||||
{
|
||||
struct CryptoGenericsImpl
|
||||
template <typename Cipher>
|
||||
static typename Cipher::IV GenerateRandomIV()
|
||||
{
|
||||
template <typename Cipher>
|
||||
static typename Cipher::IV GenerateRandomIV()
|
||||
{
|
||||
typename Cipher::IV iv;
|
||||
int status = RAND_bytes(std::data(iv), std::size(iv));
|
||||
ASSERT(status);
|
||||
return iv;
|
||||
}
|
||||
typename Cipher::IV iv;
|
||||
Trinity::Crypto::GetRandomBytes(iv);
|
||||
return iv;
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
static void AppendToBack(std::vector<uint8>& data, C const& tail)
|
||||
{
|
||||
data.insert(data.end(), std::begin(tail), std::end(tail));
|
||||
}
|
||||
template <typename Container>
|
||||
static void AppendToBack(std::vector<uint8>& data, Container const& tail)
|
||||
{
|
||||
data.insert(data.end(), std::begin(tail), std::end(tail));
|
||||
}
|
||||
|
||||
template <typename C>
|
||||
static void SplitFromBack(std::vector<uint8>& data, C& tail)
|
||||
template <typename Container>
|
||||
static void SplitFromBack(std::vector<uint8>& data, Container& tail)
|
||||
{
|
||||
ASSERT(data.size() >= std::size(tail));
|
||||
for (size_t i = 1, N = std::size(tail); i <= N; ++i)
|
||||
{
|
||||
ASSERT(data.size() >= std::size(tail));
|
||||
for (size_t i = 1, N = std::size(tail); i <= N; ++i)
|
||||
{
|
||||
tail[N - i] = data.back();
|
||||
data.pop_back();
|
||||
}
|
||||
tail[N - i] = data.back();
|
||||
data.pop_back();
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace Trinity::Crypto
|
||||
{
|
||||
template <typename Cipher>
|
||||
void AEEncryptWithRandomIV(std::vector<uint8>& data, typename Cipher::Key const& key)
|
||||
{
|
||||
using IV = typename Cipher::IV;
|
||||
using Tag = typename Cipher::Tag;
|
||||
// select random IV
|
||||
IV iv = Trinity::Impl::CryptoGenericsImpl::GenerateRandomIV<Cipher>();
|
||||
Tag tag;
|
||||
|
||||
// encrypt data
|
||||
Cipher cipher(true);
|
||||
cipher.Init(key);
|
||||
bool success = cipher.Process(iv, data.data(), data.size(), tag);
|
||||
ASSERT(success);
|
||||
|
||||
// append trailing IV and tag
|
||||
Trinity::Impl::CryptoGenericsImpl::AppendToBack(data, iv);
|
||||
Trinity::Impl::CryptoGenericsImpl::AppendToBack(data, tag);
|
||||
}
|
||||
|
||||
namespace Crypto
|
||||
template <typename Cipher>
|
||||
void AEEncryptWithRandomIV(std::vector<uint8>& data, BigNumber const& key)
|
||||
{
|
||||
template <typename Cipher>
|
||||
void AEEncryptWithRandomIV(std::vector<uint8>& data, typename Cipher::Key const& key)
|
||||
{
|
||||
using IV = typename Cipher::IV;
|
||||
using Tag = typename Cipher::Tag;
|
||||
// select random IV
|
||||
IV iv = Trinity::Impl::CryptoGenericsImpl::GenerateRandomIV<Cipher>();
|
||||
Tag tag;
|
||||
AEEncryptWithRandomIV<Cipher>(data, key.ToByteArray<Cipher::KEY_SIZE_BYTES>());
|
||||
}
|
||||
|
||||
// encrypt data
|
||||
Cipher cipher(true);
|
||||
cipher.Init(key);
|
||||
bool success = cipher.Process(iv, data.data(), data.size(), tag);
|
||||
ASSERT(success);
|
||||
template <typename Cipher>
|
||||
bool AEDecrypt(std::vector<uint8>& data, typename Cipher::Key const& key)
|
||||
{
|
||||
using IV = typename Cipher::IV;
|
||||
using Tag = typename Cipher::Tag;
|
||||
// extract trailing IV and tag
|
||||
IV iv;
|
||||
Tag tag;
|
||||
Trinity::Impl::CryptoGenericsImpl::SplitFromBack(data, tag);
|
||||
Trinity::Impl::CryptoGenericsImpl::SplitFromBack(data, iv);
|
||||
|
||||
// append trailing IV and tag
|
||||
Trinity::Impl::CryptoGenericsImpl::AppendToBack(data, iv);
|
||||
Trinity::Impl::CryptoGenericsImpl::AppendToBack(data, tag);
|
||||
}
|
||||
// decrypt data
|
||||
Cipher cipher(false);
|
||||
cipher.Init(key);
|
||||
return cipher.Process(iv, data.data(), data.size(), tag);
|
||||
}
|
||||
|
||||
template <typename Cipher>
|
||||
void AEEncryptWithRandomIV(std::vector<uint8>& data, BigNumber const& key)
|
||||
{
|
||||
AEEncryptWithRandomIV<Cipher>(data, key.AsByteArray<Cipher::KEY_SIZE_BYTES>());
|
||||
}
|
||||
|
||||
template <typename Cipher>
|
||||
bool AEDecrypt(std::vector<uint8>& data, typename Cipher::Key const& key)
|
||||
{
|
||||
using IV = typename Cipher::IV;
|
||||
using Tag = typename Cipher::Tag;
|
||||
// extract trailing IV and tag
|
||||
IV iv;
|
||||
Tag tag;
|
||||
Trinity::Impl::CryptoGenericsImpl::SplitFromBack(data, tag);
|
||||
Trinity::Impl::CryptoGenericsImpl::SplitFromBack(data, iv);
|
||||
|
||||
// decrypt data
|
||||
Cipher cipher(false);
|
||||
cipher.Init(key);
|
||||
return cipher.Process(iv, data.data(), data.size(), tag);
|
||||
}
|
||||
|
||||
template <typename Cipher>
|
||||
bool AEDecrypt(std::vector<uint8>& data, BigNumber const& key)
|
||||
{
|
||||
return AEDecrypt<Cipher>(data, key.AsByteArray<Cipher::KEY_SIZE_BYTES>());
|
||||
}
|
||||
template <typename Cipher>
|
||||
bool AEDecrypt(std::vector<uint8>& data, BigNumber const& key)
|
||||
{
|
||||
return AEDecrypt<Cipher>(data, key.ToByteArray<Cipher::KEY_SIZE_BYTES>());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
119
src/common/Cryptography/CryptoHash.h
Normal file
119
src/common/Cryptography/CryptoHash.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* 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 2 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITY_CRYPTOHASH_H
|
||||
#define TRINITY_CRYPTOHASH_H
|
||||
|
||||
#include "CryptoConstants.h"
|
||||
#include "Define.h"
|
||||
#include "Errors.h"
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
class BigNumber;
|
||||
|
||||
namespace Trinity::Impl
|
||||
{
|
||||
struct GenericHashImpl
|
||||
{
|
||||
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 void DestroyCTX(EVP_MD_CTX* ctx) { EVP_MD_CTX_destroy(ctx); }
|
||||
#else
|
||||
static EVP_MD_CTX* MakeCTX() { return EVP_MD_CTX_new(); }
|
||||
static void DestroyCTX(EVP_MD_CTX* ctx) { EVP_MD_CTX_free(ctx); }
|
||||
#endif
|
||||
};
|
||||
|
||||
template <GenericHashImpl::HashCreator HashCreator, size_t DigestLength>
|
||||
class GenericHash
|
||||
{
|
||||
public:
|
||||
static constexpr size_t DIGEST_LENGTH = DigestLength;
|
||||
using Digest = std::array<uint8, DIGEST_LENGTH>;
|
||||
|
||||
static Digest GetDigestOf(uint8 const* data, size_t len)
|
||||
{
|
||||
GenericHash hash;
|
||||
hash.UpdateData(data, len);
|
||||
hash.Finalize();
|
||||
return hash.GetDigest();
|
||||
}
|
||||
|
||||
template <typename... Ts>
|
||||
static auto GetDigestOf(Ts&&... pack) -> std::enable_if_t<!(std::is_integral_v<std::decay_t<Ts>> || ...), Digest>
|
||||
{
|
||||
GenericHash hash;
|
||||
(hash.UpdateData(std::forward<Ts>(pack)), ...);
|
||||
hash.Finalize();
|
||||
return hash.GetDigest();
|
||||
}
|
||||
|
||||
GenericHash() : _ctx(GenericHashImpl::MakeCTX())
|
||||
{
|
||||
int result = EVP_DigestInit_ex(_ctx, HashCreator(), nullptr);
|
||||
ASSERT(result == 1);
|
||||
}
|
||||
|
||||
~GenericHash()
|
||||
{
|
||||
if (!_ctx)
|
||||
return;
|
||||
GenericHashImpl::DestroyCTX(_ctx);
|
||||
_ctx = nullptr;
|
||||
}
|
||||
|
||||
void UpdateData(uint8 const* data, size_t len)
|
||||
{
|
||||
int result = EVP_DigestUpdate(_ctx, data, len);
|
||||
ASSERT(result == 1);
|
||||
}
|
||||
void UpdateData(std::string_view str) { UpdateData(reinterpret_cast<uint8 const*>(str.data()), str.size()); }
|
||||
void UpdateData(std::string const& str) { UpdateData(std::string_view(str)); } /* explicit overload to avoid using the container template */
|
||||
void UpdateData(char const* str) { UpdateData(std::string_view(str)); } /* explicit overload to avoid using the container template */
|
||||
template <typename Container>
|
||||
void UpdateData(Container const& c) { UpdateData(std::data(c), std::size(c)); }
|
||||
|
||||
void Finalize()
|
||||
{
|
||||
uint32 length;
|
||||
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; }
|
||||
|
||||
private:
|
||||
EVP_MD_CTX* _ctx;
|
||||
Digest _digest;
|
||||
};
|
||||
}
|
||||
|
||||
namespace Trinity::Crypto
|
||||
{
|
||||
using SHA1 = Trinity::Impl::GenericHash<EVP_sha1, Constants::SHA1_DIGEST_LENGTH_BYTES>;
|
||||
using SHA256 = Trinity::Impl::GenericHash<EVP_sha256, Constants::SHA256_DIGEST_LENGTH_BYTES>;
|
||||
}
|
||||
|
||||
#endif
|
||||
26
src/common/Cryptography/CryptoRandom.cpp
Normal file
26
src/common/Cryptography/CryptoRandom.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* 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 2 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "CryptoRandom.h"
|
||||
#include "Errors.h"
|
||||
#include <openssl/rand.h>
|
||||
|
||||
void Trinity::Crypto::GetRandomBytes(uint8* buf, size_t len)
|
||||
{
|
||||
int result = RAND_bytes(buf, len);
|
||||
ASSERT(result == 1, "Not enough randomness in OpenSSL's entropy pool. What in the world are you running on?");
|
||||
}
|
||||
@@ -15,38 +15,29 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _AUTH_SHA1_H
|
||||
#define _AUTH_SHA1_H
|
||||
#ifndef TRINITY_CRYPTORANDOM_H
|
||||
#define TRINITY_CRYPTORANDOM_H
|
||||
|
||||
#include "Define.h"
|
||||
#include <string>
|
||||
#include <openssl/sha.h>
|
||||
#include <array>
|
||||
|
||||
class BigNumber;
|
||||
|
||||
class TC_COMMON_API SHA1Hash
|
||||
namespace Trinity::Crypto
|
||||
{
|
||||
public:
|
||||
SHA1Hash();
|
||||
~SHA1Hash();
|
||||
void TC_COMMON_API GetRandomBytes(uint8* buf, size_t len);
|
||||
|
||||
void UpdateBigNumbers(BigNumber* bn0, ...);
|
||||
template <typename Container>
|
||||
void GetRandomBytes(Container& c)
|
||||
{
|
||||
GetRandomBytes(std::data(c), std::size(c));
|
||||
}
|
||||
|
||||
void UpdateData(const uint8 *dta, int len);
|
||||
void UpdateData(const std::string &str);
|
||||
|
||||
void Initialize();
|
||||
void Finalize();
|
||||
|
||||
uint8 *GetDigest(void) { return mDigest; }
|
||||
int GetLength(void) const { return SHA_DIGEST_LENGTH; }
|
||||
|
||||
private:
|
||||
SHA_CTX mC;
|
||||
uint8 mDigest[SHA_DIGEST_LENGTH];
|
||||
};
|
||||
|
||||
/// Returns the SHA1 hash of the given content as hex string.
|
||||
TC_COMMON_API std::string CalculateSHA1Hash(std::string const& content);
|
||||
template <size_t S>
|
||||
std::array<uint8, S> GetRandomBytes()
|
||||
{
|
||||
std::array<uint8, S> arr;
|
||||
GetRandomBytes(arr);
|
||||
return arr;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
130
src/common/Cryptography/HMAC.h
Normal file
130
src/common/Cryptography/HMAC.h
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* 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 2 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef TRINITY_HMAC_H
|
||||
#define TRINITY_HMAC_H
|
||||
|
||||
#include "CryptoConstants.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>
|
||||
class GenericHMAC
|
||||
{
|
||||
public:
|
||||
static constexpr size_t DIGEST_LENGTH = DigestLength;
|
||||
using Digest = std::array<uint8, DIGEST_LENGTH>;
|
||||
|
||||
template <typename Container>
|
||||
static Digest GetDigestOf(Container const& seed, uint8 const* data, size_t len)
|
||||
{
|
||||
GenericHMAC hash(seed);
|
||||
hash.UpdateData(data, len);
|
||||
hash.Finalize();
|
||||
return hash.GetDigest();
|
||||
}
|
||||
|
||||
template <typename Container, typename... Ts>
|
||||
static auto GetDigestOf(Container const& seed, Ts&&... pack) -> std::enable_if_t<!(std::is_integral_v<std::decay_t<Ts>> || ...), Digest>
|
||||
{
|
||||
GenericHMAC hash(seed);
|
||||
(hash.UpdateData(std::forward<Ts>(pack)), ...);
|
||||
hash.Finalize();
|
||||
return hash.GetDigest();
|
||||
}
|
||||
|
||||
GenericHMAC(uint8 const* seed, size_t len) : _ctx(HMACImpl::MakeCTX())
|
||||
{
|
||||
int result = HMAC_Init_ex(_ctx, seed, len, HashCreator(), nullptr);
|
||||
ASSERT(result == 1);
|
||||
}
|
||||
template <typename Container>
|
||||
GenericHMAC(Container const& container) : GenericHMAC(std::data(container), std::size(container)) {}
|
||||
|
||||
~GenericHMAC()
|
||||
{
|
||||
if (!_ctx)
|
||||
return;
|
||||
HMACImpl::DestroyCTX(_ctx);
|
||||
_ctx = nullptr;
|
||||
}
|
||||
|
||||
void UpdateData(uint8 const* data, size_t len)
|
||||
{
|
||||
int result = HMAC_Update(_ctx, data, len);
|
||||
ASSERT(result == 1);
|
||||
}
|
||||
void UpdateData(std::string_view str) { UpdateData(reinterpret_cast<uint8 const*>(str.data()), str.size()); }
|
||||
void UpdateData(std::string const& str) { UpdateData(std::string_view(str)); } /* explicit overload to avoid using the container template */
|
||||
void UpdateData(char const* str) { UpdateData(std::string_view(str)); } /* explicit overload to avoid using the container template */
|
||||
template <typename Container>
|
||||
void UpdateData(Container const& c) { UpdateData(std::data(c), std::size(c)); }
|
||||
|
||||
void Finalize()
|
||||
{
|
||||
uint32 length = 0;
|
||||
int result = HMAC_Final(_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;
|
||||
Digest _digest;
|
||||
};
|
||||
}
|
||||
|
||||
namespace Trinity::Crypto
|
||||
{
|
||||
using HMAC_SHA1 = Trinity::Impl::GenericHMAC<EVP_sha1, Constants::SHA1_DIGEST_LENGTH_BYTES>;
|
||||
using HMAC_SHA256 = Trinity::Impl::GenericHMAC<EVP_sha256, Constants::SHA256_DIGEST_LENGTH_BYTES>;
|
||||
}
|
||||
#endif
|
||||
@@ -1,72 +0,0 @@
|
||||
/*
|
||||
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* 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 2 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "HMACSHA1.h"
|
||||
#include "BigNumber.h"
|
||||
#include "Errors.h"
|
||||
#include <cstring>
|
||||
|
||||
#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L
|
||||
HMAC_CTX* HMAC_CTX_new()
|
||||
{
|
||||
HMAC_CTX *ctx = new HMAC_CTX();
|
||||
HMAC_CTX_init(ctx);
|
||||
return ctx;
|
||||
}
|
||||
|
||||
void HMAC_CTX_free(HMAC_CTX* ctx)
|
||||
{
|
||||
HMAC_CTX_cleanup(ctx);
|
||||
delete ctx;
|
||||
}
|
||||
#endif
|
||||
|
||||
HmacHash::HmacHash(uint32 len, uint8* seed)
|
||||
{
|
||||
m_ctx = HMAC_CTX_new();
|
||||
HMAC_Init_ex(m_ctx, seed, len, EVP_sha1(), nullptr);
|
||||
memset(m_digest, 0, sizeof(m_digest));
|
||||
}
|
||||
|
||||
HmacHash::~HmacHash()
|
||||
{
|
||||
HMAC_CTX_free(m_ctx);
|
||||
}
|
||||
|
||||
void HmacHash::UpdateData(std::string const& str)
|
||||
{
|
||||
HMAC_Update(m_ctx, reinterpret_cast<uint8 const*>(str.c_str()), str.length());
|
||||
}
|
||||
|
||||
void HmacHash::UpdateData(uint8 const* data, size_t len)
|
||||
{
|
||||
HMAC_Update(m_ctx, data, len);
|
||||
}
|
||||
|
||||
void HmacHash::Finalize()
|
||||
{
|
||||
uint32 length = 0;
|
||||
HMAC_Final(m_ctx, m_digest, &length);
|
||||
ASSERT(length == SHA_DIGEST_LENGTH);
|
||||
}
|
||||
|
||||
uint8* HmacHash::ComputeHash(BigNumber* bn)
|
||||
{
|
||||
HMAC_Update(m_ctx, bn->AsByteArray().get(), bn->GetNumBytes());
|
||||
Finalize();
|
||||
return m_digest;
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* 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 2 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "SHA1.h"
|
||||
#include "BigNumber.h"
|
||||
#include "Util.h"
|
||||
#include <cstring>
|
||||
#include <stdarg.h>
|
||||
|
||||
SHA1Hash::SHA1Hash()
|
||||
{
|
||||
SHA1_Init(&mC);
|
||||
memset(mDigest, 0, SHA_DIGEST_LENGTH * sizeof(uint8));
|
||||
}
|
||||
|
||||
SHA1Hash::~SHA1Hash()
|
||||
{
|
||||
SHA1_Init(&mC);
|
||||
}
|
||||
|
||||
void SHA1Hash::UpdateData(const uint8 *dta, int len)
|
||||
{
|
||||
SHA1_Update(&mC, dta, len);
|
||||
}
|
||||
|
||||
void SHA1Hash::UpdateData(const std::string &str)
|
||||
{
|
||||
UpdateData((uint8 const*)str.c_str(), str.length());
|
||||
}
|
||||
|
||||
void SHA1Hash::UpdateBigNumbers(BigNumber* bn0, ...)
|
||||
{
|
||||
va_list v;
|
||||
BigNumber* bn;
|
||||
|
||||
va_start(v, bn0);
|
||||
bn = bn0;
|
||||
while (bn)
|
||||
{
|
||||
UpdateData(bn->AsByteArray().get(), bn->GetNumBytes());
|
||||
bn = va_arg(v, BigNumber*);
|
||||
}
|
||||
va_end(v);
|
||||
}
|
||||
|
||||
void SHA1Hash::Initialize()
|
||||
{
|
||||
SHA1_Init(&mC);
|
||||
}
|
||||
|
||||
void SHA1Hash::Finalize(void)
|
||||
{
|
||||
SHA1_Final(mDigest, &mC);
|
||||
}
|
||||
|
||||
std::string CalculateSHA1Hash(std::string const& content)
|
||||
{
|
||||
unsigned char digest[SHA_DIGEST_LENGTH];
|
||||
SHA1((unsigned char*)content.c_str(), content.length(), (unsigned char*)&digest);
|
||||
|
||||
return ByteArrayToHexStr(digest, SHA_DIGEST_LENGTH);
|
||||
}
|
||||
60
src/common/Cryptography/SessionKeyGenerator.h
Normal file
60
src/common/Cryptography/SessionKeyGenerator.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* 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 2 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <cstring>
|
||||
#include "CryptoHash.h"
|
||||
|
||||
#ifndef TRINITY_SESSIONKEYGENERATOR_HPP
|
||||
#define TRINITY_SESSIONKEYGENERATOR_HPP
|
||||
|
||||
template <typename Hash>
|
||||
class SessionKeyGenerator
|
||||
{
|
||||
public:
|
||||
template <typename C>
|
||||
SessionKeyGenerator(C const& buf) :
|
||||
o0it(o0.begin())
|
||||
{
|
||||
uint8 const* data = std::data(buf);
|
||||
size_t const len = std::size(buf);
|
||||
size_t const halflen = (len / 2);
|
||||
|
||||
o1 = Hash::GetDigestOf(data, halflen);
|
||||
o2 = Hash::GetDigestOf(data + halflen, len - halflen);
|
||||
o0 = Hash::GetDigestOf(o1, o0, o2);
|
||||
}
|
||||
|
||||
void Generate(uint8* buf, uint32 sz)
|
||||
{
|
||||
for (uint32 i = 0; i < sz; ++i)
|
||||
{
|
||||
if (o0it == o0.end())
|
||||
{
|
||||
o0 = Hash::GetDigestOf(o1, o0, o2);
|
||||
o0it = o0.begin();
|
||||
}
|
||||
|
||||
buf[i] = *(o0it++);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
typename Hash::Digest o0, o1, o2;
|
||||
typename Hash::Digest::const_iterator o0it;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -22,19 +22,16 @@
|
||||
#include <ctime>
|
||||
#include <vector>
|
||||
|
||||
namespace Trinity
|
||||
namespace Trinity::Crypto
|
||||
{
|
||||
namespace Crypto
|
||||
{
|
||||
struct TC_COMMON_API TOTP
|
||||
{
|
||||
static constexpr std::size_t RECOMMENDED_SECRET_LENGTH = 20;
|
||||
using Secret = std::vector<uint8>;
|
||||
struct TC_COMMON_API TOTP
|
||||
{
|
||||
static constexpr size_t RECOMMENDED_SECRET_LENGTH = 20;
|
||||
using Secret = std::vector<uint8>;
|
||||
|
||||
static uint32 GenerateToken(Secret const& key, time_t timestamp);
|
||||
static bool ValidateToken(Secret const& key, uint32 token);
|
||||
};
|
||||
}
|
||||
static uint32 GenerateToken(Secret const& key, time_t timestamp);
|
||||
static bool ValidateToken(Secret const& key, uint32 token);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
|
||||
*
|
||||
* 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 2 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "SHA1.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#ifndef _WARDEN_KEY_GENERATION_H
|
||||
#define _WARDEN_KEY_GENERATION_H
|
||||
|
||||
class SHA1Randx
|
||||
{
|
||||
public:
|
||||
SHA1Randx(uint8* buff, uint32 size)
|
||||
{
|
||||
uint32 halfSize = size / 2;
|
||||
|
||||
sh.Initialize();
|
||||
sh.UpdateData(buff, halfSize);
|
||||
sh.Finalize();
|
||||
|
||||
memcpy(o1, sh.GetDigest(), 20);
|
||||
|
||||
sh.Initialize();
|
||||
sh.UpdateData(buff + halfSize, size - halfSize);
|
||||
sh.Finalize();
|
||||
|
||||
memcpy(o2, sh.GetDigest(), 20);
|
||||
|
||||
memset(o0, 0x00, 20);
|
||||
|
||||
FillUp();
|
||||
}
|
||||
|
||||
void Generate(uint8* buf, uint32 sz)
|
||||
{
|
||||
for (uint32 i = 0; i < sz; ++i)
|
||||
{
|
||||
if (taken == 20)
|
||||
FillUp();
|
||||
|
||||
buf[i] = o0[taken];
|
||||
taken++;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void FillUp()
|
||||
{
|
||||
sh.Initialize();
|
||||
sh.UpdateData(o1, 20);
|
||||
sh.UpdateData(o0, 20);
|
||||
sh.UpdateData(o2, 20);
|
||||
sh.Finalize();
|
||||
|
||||
memcpy(o0, sh.GetDigest(), 20);
|
||||
|
||||
taken = 0;
|
||||
}
|
||||
|
||||
SHA1Hash sh;
|
||||
uint32 taken;
|
||||
uint8 o0[20], o1[20], o2[20];
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -611,7 +611,7 @@ bool Utf8ToUpperOnlyLatin(std::string& utf8String)
|
||||
return WStrToUtf8(wstr, utf8String);
|
||||
}
|
||||
|
||||
std::string ByteArrayToHexStr(uint8 const* bytes, uint32 arrayLen, bool reverse /* = false */)
|
||||
std::string ByteArrayToHexStr(uint8 const* bytes, size_t arrayLen, bool reverse /* = false */)
|
||||
{
|
||||
int32 init = 0;
|
||||
int32 end = arrayLen;
|
||||
|
||||
@@ -304,7 +304,9 @@ TC_COMMON_API bool IsIPAddress(char const* ipaddress);
|
||||
TC_COMMON_API uint32 CreatePIDFile(std::string const& filename);
|
||||
TC_COMMON_API uint32 GetPID();
|
||||
|
||||
TC_COMMON_API std::string ByteArrayToHexStr(uint8 const* bytes, uint32 length, bool reverse = false);
|
||||
TC_COMMON_API std::string ByteArrayToHexStr(uint8 const* bytes, size_t length, bool reverse = false);
|
||||
template <typename Container>
|
||||
std::string ByteArrayToHexStr(Container const& c, bool reverse = false) { return ByteArrayToHexStr(std::data(c), std::size(c), reverse); }
|
||||
TC_COMMON_API void HexStrToByteArray(std::string const& str, uint8* out, bool reverse = false);
|
||||
|
||||
TC_COMMON_API bool StringToBool(std::string const& str);
|
||||
|
||||
@@ -20,13 +20,14 @@
|
||||
#include "AuthCodes.h"
|
||||
#include "Config.h"
|
||||
#include "CryptoGenerics.h"
|
||||
#include "CryptoRandom.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "Errors.h"
|
||||
#include "CryptoHash.h"
|
||||
#include "IPLocation.h"
|
||||
#include "Log.h"
|
||||
#include "RealmList.h"
|
||||
#include "SecretMgr.h"
|
||||
#include "SHA1.h"
|
||||
#include "TOTP.h"
|
||||
#include "Util.h"
|
||||
#include <boost/lexical_cast.hpp>
|
||||
@@ -74,8 +75,7 @@ typedef struct AUTH_LOGON_PROOF_C
|
||||
{
|
||||
uint8 cmd;
|
||||
uint8 A[32];
|
||||
uint8 M1[20];
|
||||
uint8 crc_hash[20];
|
||||
Trinity::Crypto::SHA1::Digest M1, crc_hash;
|
||||
uint8 number_of_keys;
|
||||
uint8 securityFlags;
|
||||
} sAuthLogonProof_C;
|
||||
@@ -85,7 +85,7 @@ typedef struct AUTH_LOGON_PROOF_S
|
||||
{
|
||||
uint8 cmd;
|
||||
uint8 error;
|
||||
uint8 M2[20];
|
||||
Trinity::Crypto::SHA1::Digest M2;
|
||||
uint32 AccountFlags;
|
||||
uint32 SurveyId;
|
||||
uint16 LoginFlags;
|
||||
@@ -96,7 +96,7 @@ typedef struct AUTH_LOGON_PROOF_S_OLD
|
||||
{
|
||||
uint8 cmd;
|
||||
uint8 error;
|
||||
uint8 M2[20];
|
||||
Trinity::Crypto::SHA1::Digest M2;
|
||||
uint32 unk2;
|
||||
} sAuthLogonProof_S_Old;
|
||||
static_assert(sizeof(sAuthLogonProof_S_Old) == (1 + 1 + 20 + 4));
|
||||
@@ -105,8 +105,7 @@ typedef struct AUTH_RECONNECT_PROOF_C
|
||||
{
|
||||
uint8 cmd;
|
||||
uint8 R1[16];
|
||||
uint8 R2[20];
|
||||
uint8 R3[20];
|
||||
Trinity::Crypto::SHA1::Digest R2, R3;
|
||||
uint8 number_of_keys;
|
||||
} sAuthReconnectProof_C;
|
||||
static_assert(sizeof(sAuthReconnectProof_C) == (1 + 16 + 20 + 20 + 1));
|
||||
@@ -115,10 +114,10 @@ static_assert(sizeof(sAuthReconnectProof_C) == (1 + 16 + 20 + 20 + 1));
|
||||
|
||||
std::array<uint8, 16> VersionChallenge = { { 0xBA, 0xA3, 0x1E, 0x99, 0xA0, 0x0B, 0x21, 0x57, 0xFC, 0x37, 0x3F, 0xB3, 0x69, 0xCD, 0xD2, 0xF1 } };
|
||||
|
||||
enum class BufferSizes : uint32
|
||||
struct BufferSizes
|
||||
{
|
||||
SRP_6_V = 0x20,
|
||||
SRP_6_S = 0x20,
|
||||
static constexpr size_t SRP_6_V = 0x20;
|
||||
static constexpr size_t SRP_6_S = 0x20;
|
||||
};
|
||||
|
||||
#define MAX_ACCEPTED_CHALLENGE_SIZE (sizeof(AUTH_LOGON_CHALLENGE_C) + 16)
|
||||
@@ -436,12 +435,12 @@ void AuthSession::LogonChallengeCallback(PreparedQueryResult result)
|
||||
pkt << uint8(WOW_SUCCESS);
|
||||
|
||||
// B may be calculated < 32B so we force minimal length to 32B
|
||||
pkt.append(B.AsByteArray(32).get(), 32); // 32 bytes
|
||||
pkt.append(B.ToByteArray<32>()); // 32 bytes
|
||||
pkt << uint8(1);
|
||||
pkt.append(g.AsByteArray(1).get(), 1);
|
||||
pkt.append(g.ToByteArray<1>());
|
||||
pkt << uint8(32);
|
||||
pkt.append(N.AsByteArray(32).get(), 32);
|
||||
pkt.append(s.AsByteArray(int32(BufferSizes::SRP_6_S)).get(), size_t(BufferSizes::SRP_6_S)); // 32 bytes
|
||||
pkt.append(N.ToByteArray<32>());
|
||||
pkt.append(s.ToByteArray<BufferSizes::SRP_6_S>()); // 32 bytes
|
||||
pkt.append(VersionChallenge.data(), VersionChallenge.size());
|
||||
pkt << uint8(securityFlags); // security flags (0x0...0x04)
|
||||
|
||||
@@ -500,72 +499,42 @@ bool AuthSession::HandleLogonProof()
|
||||
if ((A % N).IsZero())
|
||||
return false;
|
||||
|
||||
SHA1Hash sha;
|
||||
sha.UpdateBigNumbers(&A, &B, nullptr);
|
||||
sha.Finalize();
|
||||
BigNumber u;
|
||||
u.SetBinary(sha.GetDigest(), 20);
|
||||
BigNumber u(Trinity::Crypto::SHA1::GetDigestOf(A.ToByteArray<32>(), B.ToByteArray<32>()));
|
||||
BigNumber S = (A * (v.ModExp(u, N))).ModExp(b, N);
|
||||
|
||||
uint8 t[32];
|
||||
uint8 t1[16];
|
||||
uint8 vK[40];
|
||||
memcpy(t, S.AsByteArray(32).get(), 32);
|
||||
std::array<uint8, 32> t = S.ToByteArray<32>();
|
||||
std::array<uint8, 16> buf;
|
||||
Trinity::Crypto::SHA1::Digest part;
|
||||
std::array<uint8, 40> sessionKey;
|
||||
|
||||
for (int i = 0; i < 16; ++i)
|
||||
t1[i] = t[i * 2];
|
||||
for (size_t i = 0; i < 16; ++i)
|
||||
buf[i] = t[i * 2];
|
||||
part = Trinity::Crypto::SHA1::GetDigestOf(buf);
|
||||
for (size_t i = 0; i < Trinity::Crypto::SHA1::DIGEST_LENGTH; ++i)
|
||||
sessionKey[i * 2] = part[i];
|
||||
|
||||
sha.Initialize();
|
||||
sha.UpdateData(t1, 16);
|
||||
for (size_t i = 0; i < 16; ++i)
|
||||
buf[i] = t[i * 2 + 1];
|
||||
part = Trinity::Crypto::SHA1::GetDigestOf(buf);
|
||||
for (size_t i = 0; i < Trinity::Crypto::SHA1::DIGEST_LENGTH; ++i)
|
||||
sessionKey[i * 2 + 1] = part[i];
|
||||
|
||||
Trinity::Crypto::SHA1::Digest hash = Trinity::Crypto::SHA1::GetDigestOf(N.ToByteArray<32>());
|
||||
Trinity::Crypto::SHA1::Digest hash2 = Trinity::Crypto::SHA1::GetDigestOf(g.ToByteArray<1>());
|
||||
std::transform(hash.begin(), hash.end(), hash2.begin(), hash.begin(), std::bit_xor<>()); // hash = H(N) xor H(g)
|
||||
|
||||
Trinity::Crypto::SHA1 sha;
|
||||
sha.UpdateData(hash);
|
||||
sha.UpdateData(Trinity::Crypto::SHA1::GetDigestOf(_accountInfo.Login));
|
||||
sha.UpdateData(s.ToByteArray<BufferSizes::SRP_6_S>());
|
||||
sha.UpdateData(A.ToByteArray<32>());
|
||||
sha.UpdateData(B.ToByteArray<32>());
|
||||
sha.UpdateData(sessionKey);
|
||||
sha.Finalize();
|
||||
|
||||
for (int i = 0; i < 20; ++i)
|
||||
vK[i * 2] = sha.GetDigest()[i];
|
||||
|
||||
for (int i = 0; i < 16; ++i)
|
||||
t1[i] = t[i * 2 + 1];
|
||||
|
||||
sha.Initialize();
|
||||
sha.UpdateData(t1, 16);
|
||||
sha.Finalize();
|
||||
|
||||
for (int i = 0; i < 20; ++i)
|
||||
vK[i * 2 + 1] = sha.GetDigest()[i];
|
||||
|
||||
K.SetBinary(vK, 40);
|
||||
|
||||
uint8 hash[20];
|
||||
|
||||
sha.Initialize();
|
||||
sha.UpdateBigNumbers(&N, nullptr);
|
||||
sha.Finalize();
|
||||
memcpy(hash, sha.GetDigest(), 20);
|
||||
sha.Initialize();
|
||||
sha.UpdateBigNumbers(&g, nullptr);
|
||||
sha.Finalize();
|
||||
|
||||
for (int i = 0; i < 20; ++i)
|
||||
hash[i] ^= sha.GetDigest()[i];
|
||||
|
||||
BigNumber t3;
|
||||
t3.SetBinary(hash, 20);
|
||||
|
||||
sha.Initialize();
|
||||
sha.UpdateData(_accountInfo.Login);
|
||||
sha.Finalize();
|
||||
uint8 t4[SHA_DIGEST_LENGTH];
|
||||
memcpy(t4, sha.GetDigest(), SHA_DIGEST_LENGTH);
|
||||
|
||||
sha.Initialize();
|
||||
sha.UpdateBigNumbers(&t3, nullptr);
|
||||
sha.UpdateData(t4, SHA_DIGEST_LENGTH);
|
||||
sha.UpdateBigNumbers(&s, &A, &B, &K, nullptr);
|
||||
sha.Finalize();
|
||||
BigNumber M;
|
||||
M.SetBinary(sha.GetDigest(), sha.GetLength());
|
||||
Trinity::Crypto::SHA1::Digest M = sha.GetDigest();
|
||||
|
||||
// Check if SRP6 results match (password is correct), else send an error
|
||||
if (!memcmp(M.AsByteArray(sha.GetLength()).get(), logonProof->M1, 20))
|
||||
if (M == logonProof->M1)
|
||||
{
|
||||
// Check auth token
|
||||
bool tokenSuccess = false;
|
||||
@@ -607,8 +576,8 @@ bool AuthSession::HandleLogonProof()
|
||||
// Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account
|
||||
// No SQL injection (escaped user name) and IP address as received by socket
|
||||
|
||||
LoginDatabasePreparedStatement*stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF);
|
||||
stmt->setString(0, K.AsHexStr());
|
||||
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF);
|
||||
stmt->setString(0, ByteArrayToHexStr(sessionKey));
|
||||
stmt->setString(1, GetRemoteIpAddress().to_string());
|
||||
stmt->setUInt32(2, GetLocaleByName(_localizationName));
|
||||
stmt->setString(3, _os);
|
||||
@@ -616,15 +585,13 @@ bool AuthSession::HandleLogonProof()
|
||||
LoginDatabase.DirectExecute(stmt);
|
||||
|
||||
// Finish SRP6 and send the final result to the client
|
||||
sha.Initialize();
|
||||
sha.UpdateBigNumbers(&A, &M, &K, nullptr);
|
||||
sha.Finalize();
|
||||
Trinity::Crypto::SHA1::Digest M2 = Trinity::Crypto::SHA1::GetDigestOf(A.ToByteArray<32>(), M, sessionKey);
|
||||
|
||||
ByteBuffer packet;
|
||||
if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients
|
||||
{
|
||||
sAuthLogonProof_S proof;
|
||||
memcpy(proof.M2, sha.GetDigest(), 20);
|
||||
proof.M2 = M2;
|
||||
proof.cmd = AUTH_LOGON_PROOF;
|
||||
proof.error = 0;
|
||||
proof.AccountFlags = 0x00800000; // 0x01 = GM, 0x08 = Trial, 0x00800000 = Pro pass (arena tournament)
|
||||
@@ -637,7 +604,7 @@ bool AuthSession::HandleLogonProof()
|
||||
else
|
||||
{
|
||||
sAuthLogonProof_S_Old proof;
|
||||
memcpy(proof.M2, sha.GetDigest(), 20);
|
||||
proof.M2 = M2;
|
||||
proof.cmd = AUTH_LOGON_PROOF;
|
||||
proof.error = 0;
|
||||
proof.unk2 = 0x00;
|
||||
@@ -760,12 +727,12 @@ void AuthSession::ReconnectChallengeCallback(PreparedQueryResult result)
|
||||
Field* fields = result->Fetch();
|
||||
|
||||
_accountInfo.LoadResult(fields);
|
||||
K.SetHexStr(fields[9].GetCString());
|
||||
_reconnectProof.SetRand(16 * 8);
|
||||
HexStrToByteArray(fields[9].GetCString(), sessionKey.data());
|
||||
Trinity::Crypto::GetRandomBytes(_reconnectProof);
|
||||
_status = STATUS_RECONNECT_PROOF;
|
||||
|
||||
pkt << uint8(WOW_SUCCESS);
|
||||
pkt.append(_reconnectProof.AsByteArray(16).get(), 16); // 16 bytes random
|
||||
pkt.append(_reconnectProof);
|
||||
pkt.append(VersionChallenge.data(), VersionChallenge.size());
|
||||
|
||||
SendPacket(pkt);
|
||||
@@ -778,19 +745,20 @@ bool AuthSession::HandleReconnectProof()
|
||||
|
||||
sAuthReconnectProof_C *reconnectProof = reinterpret_cast<sAuthReconnectProof_C*>(GetReadBuffer().GetReadPointer());
|
||||
|
||||
if (_accountInfo.Login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes())
|
||||
if (_accountInfo.Login.empty())
|
||||
return false;
|
||||
|
||||
BigNumber t1;
|
||||
t1.SetBinary(reconnectProof->R1, 16);
|
||||
|
||||
SHA1Hash sha;
|
||||
sha.Initialize();
|
||||
Trinity::Crypto::SHA1 sha;
|
||||
sha.UpdateData(_accountInfo.Login);
|
||||
sha.UpdateBigNumbers(&t1, &_reconnectProof, &K, nullptr);
|
||||
sha.UpdateData(t1.ToByteArray<16>());
|
||||
sha.UpdateData(_reconnectProof);
|
||||
sha.UpdateData(sessionKey);
|
||||
sha.Finalize();
|
||||
|
||||
if (!memcmp(sha.GetDigest(), reconnectProof->R2, SHA_DIGEST_LENGTH))
|
||||
if (sha.GetDigest() == reconnectProof->R2)
|
||||
{
|
||||
if (!VerifyVersion(reconnectProof->R1, sizeof(reconnectProof->R1), reconnectProof->R3, true))
|
||||
{
|
||||
@@ -939,17 +907,14 @@ void AuthSession::SetVSFields(const std::string& rI)
|
||||
I.SetHexStr(rI.c_str());
|
||||
|
||||
// In case of leading zeros in the rI hash, restore them
|
||||
uint8 mDigest[SHA_DIGEST_LENGTH];
|
||||
memcpy(mDigest, I.AsByteArray(SHA_DIGEST_LENGTH).get(), SHA_DIGEST_LENGTH);
|
||||
std::array<uint8, Trinity::Crypto::SHA1::DIGEST_LENGTH> mDigest = I.ToByteArray<Trinity::Crypto::SHA1::DIGEST_LENGTH>(false);
|
||||
|
||||
std::reverse(mDigest, mDigest + SHA_DIGEST_LENGTH);
|
||||
|
||||
SHA1Hash sha;
|
||||
sha.UpdateData(s.AsByteArray(uint32(BufferSizes::SRP_6_S)).get(), (uint32(BufferSizes::SRP_6_S)));
|
||||
sha.UpdateData(mDigest, SHA_DIGEST_LENGTH);
|
||||
Trinity::Crypto::SHA1 sha;
|
||||
sha.UpdateData(s.ToByteArray<BufferSizes::SRP_6_S>());
|
||||
sha.UpdateData(mDigest);
|
||||
sha.Finalize();
|
||||
BigNumber x;
|
||||
x.SetBinary(sha.GetDigest(), sha.GetLength());
|
||||
x.SetBinary(sha.GetDigest());
|
||||
v = g.ModExp(x, N);
|
||||
|
||||
// No SQL injection (username escaped)
|
||||
@@ -960,13 +925,13 @@ void AuthSession::SetVSFields(const std::string& rI)
|
||||
LoginDatabase.Execute(stmt);
|
||||
}
|
||||
|
||||
bool AuthSession::VerifyVersion(uint8 const* a, int32 aLength, uint8 const* versionProof, bool isReconnect)
|
||||
bool AuthSession::VerifyVersion(uint8 const* a, int32 aLength, Trinity::Crypto::SHA1::Digest const& versionProof, bool isReconnect)
|
||||
{
|
||||
if (!sConfigMgr->GetBoolDefault("StrictVersionCheck", false))
|
||||
return true;
|
||||
|
||||
std::array<uint8, 20> zeros = { {} };
|
||||
std::array<uint8, 20> const* versionHash = nullptr;
|
||||
Trinity::Crypto::SHA1::Digest zeros;
|
||||
Trinity::Crypto::SHA1::Digest const* versionHash = nullptr;
|
||||
if (!isReconnect)
|
||||
{
|
||||
RealmBuildInfo const* buildInfo = sRealmList->GetBuildInfo(_build);
|
||||
@@ -981,16 +946,16 @@ bool AuthSession::VerifyVersion(uint8 const* a, int32 aLength, uint8 const* vers
|
||||
if (!versionHash)
|
||||
return false;
|
||||
|
||||
if (!memcmp(versionHash->data(), zeros.data(), zeros.size()))
|
||||
if (zeros == *versionHash)
|
||||
return true; // not filled serverside
|
||||
}
|
||||
else
|
||||
versionHash = &zeros;
|
||||
|
||||
SHA1Hash version;
|
||||
Trinity::Crypto::SHA1 version;
|
||||
version.UpdateData(a, aLength);
|
||||
version.UpdateData(versionHash->data(), versionHash->size());
|
||||
version.UpdateData(*versionHash);
|
||||
version.Finalize();
|
||||
|
||||
return memcmp(versionProof, version.GetDigest(), version.GetLength()) == 0;
|
||||
return (versionProof == version.GetDigest());
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "BigNumber.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "Common.h"
|
||||
#include "CryptoHash.h"
|
||||
#include "Optional.h"
|
||||
#include "Socket.h"
|
||||
#include "QueryResult.h"
|
||||
@@ -89,12 +90,12 @@ private:
|
||||
|
||||
void SetVSFields(const std::string& rI);
|
||||
|
||||
bool VerifyVersion(uint8 const* a, int32 aLength, uint8 const* versionProof, bool isReconnect);
|
||||
bool VerifyVersion(uint8 const* a, int32 aLength, Trinity::Crypto::SHA1::Digest const& versionProof, bool isReconnect);
|
||||
|
||||
BigNumber N, s, g, v;
|
||||
BigNumber b, B;
|
||||
BigNumber K;
|
||||
BigNumber _reconnectProof;
|
||||
std::array<uint8, 40> sessionKey;
|
||||
std::array<uint8, 16> _reconnectProof;
|
||||
|
||||
AuthStatus _status;
|
||||
AccountInfo _accountInfo;
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
#include "Common.h"
|
||||
#include "DBUpdater.h"
|
||||
#include "Field.h"
|
||||
#include "CryptoHash.h"
|
||||
#include "Log.h"
|
||||
#include "QueryResult.h"
|
||||
#include "Util.h"
|
||||
#include "SHA1.h"
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
@@ -222,7 +222,7 @@ UpdateResult UpdateFetcher::Update(bool const redundancyChecks,
|
||||
}
|
||||
|
||||
// Calculate a Sha1 hash based on query content.
|
||||
std::string const hash = CalculateSHA1Hash(ReadSQLUpdate(availableQuery.first));
|
||||
std::string const hash = ByteArrayToHexStr(Trinity::Crypto::SHA1::GetDigestOf(ReadSQLUpdate(availableQuery.first)));
|
||||
|
||||
UpdateMode mode = MODE_APPLY;
|
||||
|
||||
|
||||
@@ -18,12 +18,12 @@
|
||||
#include "AccountMgr.h"
|
||||
#include "Config.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "CryptoHash.h"
|
||||
#include "Log.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Player.h"
|
||||
#include "Realm.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "SHA1.h"
|
||||
#include "Util.h"
|
||||
#include "World.h"
|
||||
#include "WorldSession.h"
|
||||
@@ -379,14 +379,7 @@ uint32 AccountMgr::GetCharactersCount(uint32 accountId)
|
||||
|
||||
std::string AccountMgr::CalculateShaPassHash(std::string const& name, std::string const& password)
|
||||
{
|
||||
SHA1Hash sha;
|
||||
sha.Initialize();
|
||||
sha.UpdateData(name);
|
||||
sha.UpdateData(":");
|
||||
sha.UpdateData(password);
|
||||
sha.Finalize();
|
||||
|
||||
return ByteArrayToHexStr(sha.GetDigest(), sha.GetLength());
|
||||
return ByteArrayToHexStr(Trinity::Crypto::SHA1::GetDigestOf(name, ":", password));
|
||||
}
|
||||
|
||||
bool AccountMgr::IsBannedAccount(std::string const& name)
|
||||
|
||||
@@ -40,13 +40,14 @@ ScriptReloadMgr* ScriptReloadMgr::instance()
|
||||
#include "BuiltInConfig.h"
|
||||
#include "Config.h"
|
||||
#include "GitRevision.h"
|
||||
#include "CryptoHash.h"
|
||||
#include "Log.h"
|
||||
#include "MPSCQueue.h"
|
||||
#include "Regex.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "SHA1.h"
|
||||
#include "StartProcess.h"
|
||||
#include "Timer.h"
|
||||
#include "Util.h"
|
||||
#include "World.h"
|
||||
#include <boost/algorithm/string/replace.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
@@ -756,7 +757,7 @@ private:
|
||||
auto path = fs::temp_directory_path();
|
||||
path /= Trinity::StringFormat("tc_script_cache_%s_%s",
|
||||
GitRevision::GetBranch(),
|
||||
CalculateSHA1Hash(sConfigMgr->GetFilename()).c_str());
|
||||
ByteArrayToHexStr(Trinity::Crypto::SHA1::GetDigestOf(sConfigMgr->GetFilename())).c_str());
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
@@ -1209,7 +1209,7 @@ TransactionCallback& WorldSession::AddTransactionCallback(TransactionCallback&&
|
||||
return _transactionCallbacks.AddCallback(std::move(callback));
|
||||
}
|
||||
|
||||
void WorldSession::InitWarden(BigNumber* k, std::string const& os)
|
||||
void WorldSession::InitWarden(std::array<uint8, 40> const& k, std::string const& os)
|
||||
{
|
||||
if (os == "Win")
|
||||
{
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#include <unordered_map>
|
||||
#include <boost/circular_buffer.hpp>
|
||||
|
||||
class BigNumber;
|
||||
class Creature;
|
||||
class GameObject;
|
||||
class InstanceSave;
|
||||
@@ -423,7 +422,7 @@ class TC_GAME_API WorldSession
|
||||
void SetPlayer(Player* player);
|
||||
uint8 Expansion() const { return m_expansion; }
|
||||
|
||||
void InitWarden(BigNumber* k, std::string const& os);
|
||||
void InitWarden(std::array<uint8, 40> const& k, std::string const& os);
|
||||
|
||||
/// Session in auth.queue currently
|
||||
void SetInQueue(bool state) { m_inQueue = state; }
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include "BigNumber.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "GameTime.h"
|
||||
#include "CryptoHash.h"
|
||||
#include "CryptoRandom.h"
|
||||
#include "IPLocation.h"
|
||||
#include "Opcodes.h"
|
||||
#include "PacketLog.h"
|
||||
@@ -26,7 +28,6 @@
|
||||
#include "RBAC.h"
|
||||
#include "Realm.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "SHA1.h"
|
||||
#include "World.h"
|
||||
#include "WorldSession.h"
|
||||
#include <memory>
|
||||
@@ -34,8 +35,9 @@
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
WorldSocket::WorldSocket(tcp::socket&& socket)
|
||||
: Socket(std::move(socket)), _authSeed(rand32()), _OverSpeedPings(0), _worldSession(nullptr), _authed(false), _sendBufferSize(4096)
|
||||
: Socket(std::move(socket)), _OverSpeedPings(0), _worldSession(nullptr), _authed(false), _sendBufferSize(4096)
|
||||
{
|
||||
Trinity::Crypto::GetRandomBytes(_authSeed);
|
||||
_headerBuffer.Resize(sizeof(ClientPktHeader));
|
||||
}
|
||||
|
||||
@@ -126,15 +128,9 @@ void WorldSocket::HandleSendAuthSession()
|
||||
{
|
||||
WorldPacket packet(SMSG_AUTH_CHALLENGE, 37);
|
||||
packet << uint32(1); // 1...31
|
||||
packet << uint32(_authSeed);
|
||||
packet.append(_authSeed);
|
||||
|
||||
BigNumber seed1;
|
||||
seed1.SetRand(16 * 8);
|
||||
packet.append(seed1.AsByteArray(16).get(), 16); // new encryption seeds
|
||||
|
||||
BigNumber seed2;
|
||||
seed2.SetRand(16 * 8);
|
||||
packet.append(seed2.AsByteArray(16).get(), 16); // new encryption seeds
|
||||
packet.append(Trinity::Crypto::GetRandomBytes<32>()); // new encryption seeds
|
||||
|
||||
SendPacketAndLogOpcode(packet);
|
||||
}
|
||||
@@ -212,7 +208,8 @@ bool WorldSocket::ReadHeaderHandler()
|
||||
{
|
||||
ASSERT(_headerBuffer.GetActiveSize() == sizeof(ClientPktHeader));
|
||||
|
||||
_authCrypt.DecryptRecv(_headerBuffer.GetReadPointer(), sizeof(ClientPktHeader));
|
||||
if (_authCrypt.IsInitialized())
|
||||
_authCrypt.DecryptRecv(_headerBuffer.GetReadPointer(), sizeof(ClientPktHeader));
|
||||
|
||||
ClientPktHeader* header = reinterpret_cast<ClientPktHeader*>(_headerBuffer.GetReadPointer());
|
||||
EndianConvertReverse(header->size);
|
||||
@@ -236,11 +233,11 @@ struct AuthSession
|
||||
uint32 LoginServerType = 0;
|
||||
uint32 RealmID = 0;
|
||||
uint32 Build = 0;
|
||||
uint32 LocalChallenge = 0;
|
||||
std::array<uint8, 4> LocalChallenge;
|
||||
uint32 LoginServerID = 0;
|
||||
uint32 RegionID = 0;
|
||||
uint64 DosResponse = 0;
|
||||
uint8 Digest[SHA_DIGEST_LENGTH] = {};
|
||||
Trinity::Crypto::SHA1::Digest Digest;
|
||||
std::string Account;
|
||||
ByteBuffer AddonInfo;
|
||||
};
|
||||
@@ -248,7 +245,7 @@ struct AuthSession
|
||||
struct AccountInfo
|
||||
{
|
||||
uint32 Id;
|
||||
BigNumber SessionKey;
|
||||
std::array<uint8, 40> SessionKey;
|
||||
std::string LastIP;
|
||||
bool IsLockedToIP;
|
||||
std::string LockCountry;
|
||||
@@ -273,7 +270,7 @@ struct AccountInfo
|
||||
// LEFT JOIN account r ON a.id = r.recruiter
|
||||
// WHERE a.username = ? ORDER BY aa.RealmID DESC LIMIT 1
|
||||
Id = fields[0].GetUInt32();
|
||||
SessionKey.SetHexStr(fields[1].GetCString());
|
||||
HexStrToByteArray(fields[1].GetCString(), SessionKey.data());
|
||||
LastIP = fields[2].GetString();
|
||||
IsLockedToIP = fields[3].GetBool();
|
||||
LockCountry = fields[4].GetString();
|
||||
@@ -428,12 +425,12 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
|
||||
recvPacket >> authSession->LoginServerID;
|
||||
recvPacket >> authSession->Account;
|
||||
recvPacket >> authSession->LoginServerType;
|
||||
recvPacket >> authSession->LocalChallenge;
|
||||
recvPacket.read(authSession->LocalChallenge);
|
||||
recvPacket >> authSession->RegionID;
|
||||
recvPacket >> authSession->BattlegroupID;
|
||||
recvPacket >> authSession->RealmID; // realmId from auth_database.realmlist table
|
||||
recvPacket >> authSession->DosResponse;
|
||||
recvPacket.read(authSession->Digest, 20);
|
||||
recvPacket.read(authSession->Digest);
|
||||
authSession->AddonInfo.resize(recvPacket.size() - recvPacket.rpos());
|
||||
recvPacket.read(authSession->AddonInfo.contents(), authSession->AddonInfo.size()); // .contents will throw if empty, thats what we want
|
||||
|
||||
@@ -470,7 +467,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<AuthSession> authSes
|
||||
// This also allows to check for possible "hack" attempts on account
|
||||
|
||||
// even if auth credentials are bad, try using the session key we have - client cannot read auth response error without it
|
||||
_authCrypt.Init(&account.SessionKey);
|
||||
_authCrypt.Init(account.SessionKey);
|
||||
|
||||
// First reject the connection if packet contains invalid data or realm state doesn't allow logging in
|
||||
if (sWorld->IsClosed())
|
||||
@@ -501,17 +498,17 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<AuthSession> authSes
|
||||
}
|
||||
|
||||
// Check that Key and account name are the same on client and server
|
||||
uint32 t = 0;
|
||||
uint8 t[4] = { 0x00,0x00,0x00,0x00 };
|
||||
|
||||
SHA1Hash sha;
|
||||
Trinity::Crypto::SHA1 sha;
|
||||
sha.UpdateData(authSession->Account);
|
||||
sha.UpdateData((uint8*)&t, 4);
|
||||
sha.UpdateData((uint8*)&authSession->LocalChallenge, 4);
|
||||
sha.UpdateData((uint8*)&_authSeed, 4);
|
||||
sha.UpdateBigNumbers(&account.SessionKey, nullptr);
|
||||
sha.UpdateData(t);
|
||||
sha.UpdateData(authSession->LocalChallenge);
|
||||
sha.UpdateData(_authSeed);
|
||||
sha.UpdateData(account.SessionKey);
|
||||
sha.Finalize();
|
||||
|
||||
if (memcmp(sha.GetDigest(), authSession->Digest, SHA_DIGEST_LENGTH) != 0)
|
||||
if (sha.GetDigest() != authSession->Digest)
|
||||
{
|
||||
SendAuthResponseError(AUTH_FAILED);
|
||||
TC_LOG_ERROR("network", "WorldSocket::HandleAuthSession: Authentication failed for account: %u ('%s') address: %s", account.Id, authSession->Account.c_str(), address.c_str());
|
||||
@@ -601,7 +598,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<AuthSession> authSes
|
||||
|
||||
// Initialize Warden system only if it is enabled by config
|
||||
if (wardenActive)
|
||||
_worldSession->InitWarden(&account.SessionKey, account.OS);
|
||||
_worldSession->InitWarden(account.SessionKey, account.OS);
|
||||
|
||||
_queryProcessor.AddCallback(_worldSession->LoadPermissionsAsync().WithPreparedCallback(std::bind(&WorldSocket::LoadSessionPermissionsCallback, this, std::placeholders::_1)));
|
||||
AsyncRead();
|
||||
|
||||
@@ -112,7 +112,7 @@ private:
|
||||
|
||||
bool HandlePing(WorldPacket& recvPacket);
|
||||
|
||||
uint32 _authSeed;
|
||||
std::array<uint8, 4> _authSeed;
|
||||
AuthCrypt _authCrypt;
|
||||
|
||||
TimePoint _LastPingTime;
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
|
||||
#include <openssl/sha.h>
|
||||
|
||||
Warden::Warden() : _session(nullptr), _inputCrypto(16), _outputCrypto(16), _checkTimer(10000/*10 sec*/), _clientResponseTimer(0),
|
||||
Warden::Warden() : _session(nullptr), _checkTimer(10000/*10 sec*/), _clientResponseTimer(0),
|
||||
_dataSent(false), _previousTimestamp(0), _module(nullptr), _initialized(false)
|
||||
{
|
||||
memset(_inputKey, 0, sizeof(_inputKey));
|
||||
@@ -130,12 +130,12 @@ void Warden::Update()
|
||||
|
||||
void Warden::DecryptData(uint8* buffer, uint32 length)
|
||||
{
|
||||
_inputCrypto.UpdateData(length, buffer);
|
||||
_inputCrypto.UpdateData(buffer, length);
|
||||
}
|
||||
|
||||
void Warden::EncryptData(uint8* buffer, uint32 length)
|
||||
{
|
||||
_outputCrypto.UpdateData(length, buffer);
|
||||
_outputCrypto.UpdateData(buffer, length);
|
||||
}
|
||||
|
||||
bool Warden::IsValidCheckSum(uint32 checksum, uint8 const* data, const uint16 length)
|
||||
|
||||
@@ -18,11 +18,10 @@
|
||||
#ifndef _WARDEN_BASE_H
|
||||
#define _WARDEN_BASE_H
|
||||
|
||||
#include <map>
|
||||
#include "Cryptography/ARC4.h"
|
||||
#include "Cryptography/BigNumber.h"
|
||||
#include "ARC4.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "WardenCheckMgr.h"
|
||||
#include <array>
|
||||
|
||||
enum WardenOpcodes
|
||||
{
|
||||
@@ -100,7 +99,7 @@ class TC_GAME_API Warden
|
||||
Warden();
|
||||
virtual ~Warden();
|
||||
|
||||
virtual void Init(WorldSession* session, BigNumber* k) = 0;
|
||||
virtual void Init(WorldSession* session, std::array<uint8, 40> const& K) = 0;
|
||||
virtual ClientWardenModule* GetModuleForClient() = 0;
|
||||
virtual void InitializeModule() = 0;
|
||||
virtual void RequestHash() = 0;
|
||||
@@ -125,8 +124,8 @@ class TC_GAME_API Warden
|
||||
uint8 _inputKey[16];
|
||||
uint8 _outputKey[16];
|
||||
uint8 _seed[16];
|
||||
ARC4 _inputCrypto;
|
||||
ARC4 _outputCrypto;
|
||||
Trinity::Crypto::ARC4 _inputCrypto;
|
||||
Trinity::Crypto::ARC4 _outputCrypto;
|
||||
uint32 _checkTimer; // Timer for sending check requests
|
||||
uint32 _clientResponseTimer; // Timer for client response delay
|
||||
bool _dataSent;
|
||||
|
||||
@@ -85,19 +85,7 @@ void WardenCheckMgr::LoadWardenChecks()
|
||||
wardenCheck->Action = WardenActions(sWorld->getIntConfig(CONFIG_WARDEN_CLIENT_FAIL_ACTION));
|
||||
|
||||
if (checkType == PAGE_CHECK_A || checkType == PAGE_CHECK_B || checkType == DRIVER_CHECK)
|
||||
{
|
||||
wardenCheck->Data.SetHexStr(data.c_str());
|
||||
int len = data.size() / 2;
|
||||
|
||||
if (wardenCheck->Data.GetNumBytes() < len)
|
||||
{
|
||||
uint8 temp[24];
|
||||
memset(temp, 0, len);
|
||||
memcpy(temp, wardenCheck->Data.AsByteArray().get(), wardenCheck->Data.GetNumBytes());
|
||||
std::reverse(temp, temp + len);
|
||||
wardenCheck->Data.SetBinary((uint8*)temp, len);
|
||||
}
|
||||
}
|
||||
|
||||
if (checkType == MEM_CHECK || checkType == MODULE_CHECK)
|
||||
MemChecksIdPool.push_back(id);
|
||||
@@ -120,16 +108,6 @@ void WardenCheckMgr::LoadWardenChecks()
|
||||
{
|
||||
WardenCheckResult* wr = new WardenCheckResult();
|
||||
wr->Result.SetHexStr(checkResult.c_str());
|
||||
int len = checkResult.size() / 2;
|
||||
if (wr->Result.GetNumBytes() < len)
|
||||
{
|
||||
uint8 *temp = new uint8[len];
|
||||
memset(temp, 0, len);
|
||||
memcpy(temp, wr->Result.AsByteArray().get(), wr->Result.GetNumBytes());
|
||||
std::reverse(temp, temp + len);
|
||||
wr->Result.SetBinary((uint8*)temp, len);
|
||||
delete [] temp;
|
||||
}
|
||||
CheckResultStore[id] = wr;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,18 +15,18 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Cryptography/WardenKeyGeneration.h"
|
||||
#include "WardenMac.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "Common.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "GameTime.h"
|
||||
#include "Log.h"
|
||||
#include "Opcodes.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "GameTime.h"
|
||||
#include "Player.h"
|
||||
#include "SessionKeyGenerator.h"
|
||||
#include "Util.h"
|
||||
#include "WardenMac.h"
|
||||
#include "WardenModuleMac.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
#include <openssl/md5.h>
|
||||
|
||||
@@ -34,11 +34,11 @@ WardenMac::WardenMac() : Warden() { }
|
||||
|
||||
WardenMac::~WardenMac() { }
|
||||
|
||||
void WardenMac::Init(WorldSession* pClient, BigNumber* K)
|
||||
void WardenMac::Init(WorldSession* pClient, std::array<uint8, 40> const& K)
|
||||
{
|
||||
_session = pClient;
|
||||
// Generate Warden Key
|
||||
SHA1Randx WK(K->AsByteArray().get(), K->GetNumBytes());
|
||||
SessionKeyGenerator<Trinity::Crypto::SHA1> WK(K);
|
||||
WK.Generate(_inputKey, 16);
|
||||
WK.Generate(_outputKey, 16);
|
||||
/*
|
||||
@@ -154,14 +154,14 @@ void WardenMac::HandleHashResult(ByteBuffer &buff)
|
||||
|
||||
buff.rpos(buff.wpos());
|
||||
|
||||
SHA1Hash sha1;
|
||||
Trinity::Crypto::SHA1 sha1;
|
||||
sha1.UpdateData((uint8*)keyIn, 16);
|
||||
sha1.Finalize();
|
||||
|
||||
//const uint8 validHash[20] = { 0x56, 0x8C, 0x05, 0x4C, 0x78, 0x1A, 0x97, 0x2A, 0x60, 0x37, 0xA2, 0x29, 0x0C, 0x22, 0xB5, 0x25, 0x71, 0xA0, 0x6F, 0x4E };
|
||||
|
||||
// Verify key
|
||||
if (memcmp(buff.contents() + 1, sha1.GetDigest(), 20) != 0)
|
||||
if (memcmp(buff.contents() + 1, sha1.GetDigest().data(), 20) != 0)
|
||||
{
|
||||
TC_LOG_WARN("warden", "%s failed hash reply. Action: %s", _session->GetPlayerInfo().c_str(), Penalty().c_str());
|
||||
return;
|
||||
@@ -235,16 +235,16 @@ void WardenMac::HandleData(ByteBuffer &buff)
|
||||
|
||||
std::string str = "Test string!";
|
||||
|
||||
SHA1Hash sha1;
|
||||
Trinity::Crypto::SHA1 sha1;
|
||||
sha1.UpdateData(str);
|
||||
uint32 magic = 0xFEEDFACE; // unsure
|
||||
sha1.UpdateData((uint8*)&magic, 4);
|
||||
sha1.Finalize();
|
||||
|
||||
uint8 sha1Hash[20];
|
||||
buff.read(sha1Hash, 20);
|
||||
std::array<uint8, Trinity::Crypto::SHA1::DIGEST_LENGTH> sha1Hash;
|
||||
buff.read(sha1Hash.data(), sha1Hash.size());
|
||||
|
||||
if (memcmp(sha1Hash, sha1.GetDigest(), 20) != 0)
|
||||
if (sha1Hash != sha1.GetDigest())
|
||||
{
|
||||
TC_LOG_DEBUG("warden", "Handle data failed: SHA1 hash is wrong!");
|
||||
//found = true;
|
||||
|
||||
@@ -18,9 +18,7 @@
|
||||
#ifndef _WARDEN_MAC_H
|
||||
#define _WARDEN_MAC_H
|
||||
|
||||
#include "Cryptography/ARC4.h"
|
||||
#include <map>
|
||||
#include "Cryptography/BigNumber.h"
|
||||
#include "ARC4.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "Warden.h"
|
||||
|
||||
@@ -33,7 +31,7 @@ class TC_GAME_API WardenMac : public Warden
|
||||
WardenMac();
|
||||
~WardenMac();
|
||||
|
||||
void Init(WorldSession* session, BigNumber* k) override;
|
||||
void Init(WorldSession* session, std::array<uint8, 40> const& k) override;
|
||||
ClientWardenModule* GetModuleForClient() override;
|
||||
void InitializeModule() override;
|
||||
void RequestHash() override;
|
||||
|
||||
@@ -15,34 +15,35 @@
|
||||
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Cryptography/HMACSHA1.h"
|
||||
#include "Cryptography/WardenKeyGeneration.h"
|
||||
#include "WardenWin.h"
|
||||
#include "Common.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "CryptoRandom.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "GameTime.h"
|
||||
#include "HMAC.h"
|
||||
#include "Log.h"
|
||||
#include "Opcodes.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "GameTime.h"
|
||||
#include "World.h"
|
||||
#include "Player.h"
|
||||
#include "Random.h"
|
||||
#include "SessionKeyGenerator.h"
|
||||
#include "Util.h"
|
||||
#include "WardenWin.h"
|
||||
#include "WardenModuleWin.h"
|
||||
#include "WardenCheckMgr.h"
|
||||
#include "Random.h"
|
||||
#include "World.h"
|
||||
#include "WorldPacket.h"
|
||||
#include "WorldSession.h"
|
||||
#include <openssl/md5.h>
|
||||
|
||||
WardenWin::WardenWin() : Warden(), _serverTicks(0) {}
|
||||
|
||||
WardenWin::~WardenWin() { }
|
||||
|
||||
void WardenWin::Init(WorldSession* session, BigNumber* k)
|
||||
void WardenWin::Init(WorldSession* session, std::array<uint8, 40> const& K)
|
||||
{
|
||||
_session = session;
|
||||
// Generate Warden Key
|
||||
SHA1Randx WK(k->AsByteArray().get(), k->GetNumBytes());
|
||||
SessionKeyGenerator<Trinity::Crypto::SHA1> WK(K);
|
||||
WK.Generate(_inputKey, 16);
|
||||
WK.Generate(_outputKey, 16);
|
||||
|
||||
@@ -262,7 +263,8 @@ void WardenWin::RequestData()
|
||||
case PAGE_CHECK_A:
|
||||
case PAGE_CHECK_B:
|
||||
{
|
||||
buff.append(wd->Data.AsByteArray(0, false).get(), wd->Data.GetNumBytes());
|
||||
std::vector<uint8> data = wd->Data.ToByteVector(0, false);
|
||||
buff.append(data.data(), data.size());
|
||||
buff << uint32(wd->Address);
|
||||
buff << uint8(wd->Length);
|
||||
break;
|
||||
@@ -275,18 +277,16 @@ void WardenWin::RequestData()
|
||||
}
|
||||
case DRIVER_CHECK:
|
||||
{
|
||||
buff.append(wd->Data.AsByteArray(0, false).get(), wd->Data.GetNumBytes());
|
||||
std::vector<uint8> data = wd->Data.ToByteVector(0, false);
|
||||
buff.append(data.data(), data.size());
|
||||
buff << uint8(index++);
|
||||
break;
|
||||
}
|
||||
case MODULE_CHECK:
|
||||
{
|
||||
uint32 seed = rand32();
|
||||
buff << uint32(seed);
|
||||
HmacHash hmac(4, (uint8*)&seed);
|
||||
hmac.UpdateData(wd->Str);
|
||||
hmac.Finalize();
|
||||
buff.append(hmac.GetDigest(), hmac.GetLength());
|
||||
std::array<uint8, 4> seed = Trinity::Crypto::GetRandomBytes<4>();
|
||||
buff.append(seed);
|
||||
buff.append(Trinity::Crypto::HMAC_SHA1::GetDigestOf(seed, wd->Str));
|
||||
break;
|
||||
}
|
||||
/*case PROC_CHECK:
|
||||
@@ -391,7 +391,8 @@ void WardenWin::HandleData(ByteBuffer &buff)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (memcmp(buff.contents() + buff.rpos(), rs->Result.AsByteArray(0, false).get(), rd->Length) != 0)
|
||||
std::vector<uint8> result = rs->Result.ToByteVector();
|
||||
if (memcmp(buff.contents() + buff.rpos(), result.data(), rd->Length) != 0)
|
||||
{
|
||||
TC_LOG_DEBUG("warden", "RESULT MEM_CHECK fail CheckId %u account Id %u", *itr, _session->GetAccountId());
|
||||
checkFailed = *itr;
|
||||
@@ -470,7 +471,7 @@ void WardenWin::HandleData(ByteBuffer &buff)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (memcmp(buff.contents() + buff.rpos(), rs->Result.AsByteArray(0, false).get(), 20) != 0) // SHA1
|
||||
if (memcmp(buff.contents() + buff.rpos(), rs->Result.ToByteArray<20>(false).data(), 20) != 0) // SHA1
|
||||
{
|
||||
TC_LOG_DEBUG("warden", "RESULT MPQ_CHECK fail, CheckId %u account Id %u", *itr, _session->GetAccountId());
|
||||
checkFailed = *itr;
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
#ifndef _WARDEN_WIN_H
|
||||
#define _WARDEN_WIN_H
|
||||
|
||||
#include <map>
|
||||
#include "Cryptography/ARC4.h"
|
||||
#include "Cryptography/BigNumber.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "Warden.h"
|
||||
#include <list>
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
@@ -67,7 +67,7 @@ class TC_GAME_API WardenWin : public Warden
|
||||
WardenWin();
|
||||
~WardenWin();
|
||||
|
||||
void Init(WorldSession* session, BigNumber* K) override;
|
||||
void Init(WorldSession* session, std::array<uint8, 40> const& K) override;
|
||||
ClientWardenModule* GetModuleForClient() override;
|
||||
void InitializeModule() override;
|
||||
void RequestHash() override;
|
||||
|
||||
@@ -27,6 +27,7 @@ EndScriptData */
|
||||
#include "Base32.h"
|
||||
#include "Chat.h"
|
||||
#include "CryptoGenerics.h"
|
||||
#include "CryptoRandom.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "IpAddress.h"
|
||||
#include "IPLocation.h"
|
||||
@@ -39,7 +40,6 @@ EndScriptData */
|
||||
#include "World.h"
|
||||
#include "WorldSession.h"
|
||||
#include <unordered_map>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
using namespace Trinity::ChatCommands;
|
||||
|
||||
@@ -131,7 +131,7 @@ public:
|
||||
static std::unordered_map<uint32, Trinity::Crypto::TOTP::Secret> suggestions;
|
||||
auto pair = suggestions.emplace(std::piecewise_construct, std::make_tuple(accountId), std::make_tuple(Trinity::Crypto::TOTP::RECOMMENDED_SECRET_LENGTH)); // std::vector 1-argument size_t constructor invokes resize
|
||||
if (pair.second) // no suggestion yet, generate random secret
|
||||
RAND_bytes(pair.first->second.data(), pair.first->second.size());
|
||||
Trinity::Crypto::GetRandomBytes(pair.first->second);
|
||||
|
||||
if (!pair.second && token) // suggestion already existed and token specified - validate
|
||||
{
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "Define.h"
|
||||
#include "ByteConverter.h"
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
@@ -351,6 +352,12 @@ class TC_SHARED_API ByteBuffer
|
||||
_rpos += len;
|
||||
}
|
||||
|
||||
template <size_t Size>
|
||||
void read(std::array<uint8, Size>& arr)
|
||||
{
|
||||
read(arr.data(), Size);
|
||||
}
|
||||
|
||||
void readPackGUID(uint64& guid)
|
||||
{
|
||||
if (rpos() + 1 > size())
|
||||
@@ -438,6 +445,12 @@ class TC_SHARED_API ByteBuffer
|
||||
append(buffer.contents(), buffer.wpos());
|
||||
}
|
||||
|
||||
template <size_t Size>
|
||||
void append(std::array<uint8, Size> const& arr)
|
||||
{
|
||||
append(arr.data(), Size);
|
||||
}
|
||||
|
||||
// can be used in SMSG_MONSTER_MOVE opcode
|
||||
void appendPackXYZ(float x, float y, float z)
|
||||
{
|
||||
|
||||
@@ -190,13 +190,13 @@ Optional<std::string> SecretMgr::AttemptTransition(Secrets i, Optional<BigNumber
|
||||
if (!oldSecret)
|
||||
return Trinity::StringFormat("Cannot decrypt old TOTP tokens - add config key '%s' to authserver.conf!", secret_info[i].oldKey);
|
||||
|
||||
bool success = Trinity::Crypto::AEDecrypt<Trinity::Crypto::AES>(totpSecret, oldSecret->AsByteArray<Trinity::Crypto::AES::KEY_SIZE_BYTES>());
|
||||
bool success = Trinity::Crypto::AEDecrypt<Trinity::Crypto::AES>(totpSecret, oldSecret->ToByteArray<Trinity::Crypto::AES::KEY_SIZE_BYTES>());
|
||||
if (!success)
|
||||
return Trinity::StringFormat("Cannot decrypt old TOTP tokens - value of '%s' is incorrect for some users!", secret_info[i].oldKey);
|
||||
}
|
||||
|
||||
if (newSecret)
|
||||
Trinity::Crypto::AEEncryptWithRandomIV<Trinity::Crypto::AES>(totpSecret, newSecret->AsByteArray<Trinity::Crypto::AES::KEY_SIZE_BYTES>());
|
||||
Trinity::Crypto::AEEncryptWithRandomIV<Trinity::Crypto::AES>(totpSecret, newSecret->ToByteArray<Trinity::Crypto::AES::KEY_SIZE_BYTES>());
|
||||
|
||||
LoginDatabasePreparedStatement* updateStmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_ACCOUNT_TOTP_SECRET);
|
||||
updateStmt->setBinary(0, totpSecret);
|
||||
|
||||
Reference in New Issue
Block a user