feat(Core/DB/Authserver): remove sha_pass_hash (#4827)

This commit is contained in:
UltraNix
2021-03-21 15:17:57 +01:00
committed by GitHub
parent e9ed6380a6
commit 485f7e7639
54 changed files with 1095 additions and 744 deletions
@@ -0,0 +1,27 @@
INSERT INTO `version_db_auth` (`sql_rev`) VALUES ('1615629613255169700');
-- update `account` structure
-- sha_pass_hash/s/v kept around for now, for backwards compatibility
ALTER TABLE `account`
DROP COLUMN `sessionkey`,
ADD COLUMN `salt` BINARY(32) AFTER `username`,
ADD COLUMN `verifier` BINARY(32) AFTER `salt`,
ADD COLUMN `session_key` BINARY(40) AFTER `verifier`,
MODIFY COLUMN `s` VARCHAR(64) NOT NULL DEFAULT 'dummy value, use `salt` instead',
MODIFY COLUMN `v` VARCHAR(64) NOT NULL DEFAULT 'dummy value, use `verifier` instead';
UPDATE `account` SET `salt`=REVERSE(UNHEX(`s`)), `s`=DEFAULT WHERE LENGTH(`s`)=64;
UPDATE `account` SET `verifier`=REVERSE(UNHEX(`v`)), `v`=DEFAULT WHERE LENGTH(`v`)=64;
ALTER TABLE `account`
DROP COLUMN `session_key`,
ADD COLUMN `session_key` BINARY(40) DEFAULT NULL AFTER `verifier`;
UPDATE `account` SET `salt`=UNHEX(CONCAT(MD5(RAND()),MD5(RAND()))), `verifier`=UNHEX(CONCAT(MD5(RAND()),MD5(RAND()))) WHERE `salt` IS NULL OR `verifier` IS NULL;
ALTER TABLE `account`
DROP COLUMN `s`,
DROP COLUMN `v`,
DROP COLUMN `sha_pass_hash`,
MODIFY COLUMN `salt` BINARY(32) NOT NULL,
MODIFY COLUMN `verifier` BINARY(32) NOT NULL;
+18 -20
View File
@@ -5,36 +5,34 @@
*/ */
#include "ARC4.h" #include "ARC4.h"
#include <openssl/sha.h> #include "Errors.h"
ARC4::ARC4(uint32 len) : m_ctx(EVP_CIPHER_CTX_new()) acore::Crypto::ARC4::ARC4()
: _ctx(EVP_CIPHER_CTX_new())
{ {
EVP_CIPHER_CTX_init(m_ctx); EVP_CIPHER_CTX_init(_ctx);
EVP_EncryptInit_ex(m_ctx, EVP_rc4(), nullptr, nullptr, nullptr); int result = EVP_EncryptInit_ex(_ctx, EVP_rc4(), nullptr, nullptr, nullptr);
EVP_CIPHER_CTX_set_key_length(m_ctx, len); ASSERT(result == 1);
} }
ARC4::ARC4(uint8* seed, uint32 len) : m_ctx(EVP_CIPHER_CTX_new()) acore::Crypto::ARC4::~ARC4()
{ {
EVP_CIPHER_CTX_init(m_ctx); EVP_CIPHER_CTX_free(_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);
} }
ARC4::~ARC4() void acore::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) void acore::Crypto::ARC4::UpdateData(uint8* data, size_t len)
{
EVP_EncryptInit_ex(m_ctx, nullptr, nullptr, seed, nullptr);
}
void ARC4::UpdateData(int len, uint8* data)
{ {
int outlen = 0; int outlen = 0;
EVP_EncryptUpdate(m_ctx, data, &outlen, data, len); int result1 = EVP_EncryptUpdate(_ctx, data, &outlen, data, len);
EVP_EncryptFinal_ex(m_ctx, data, &outlen); ASSERT(result1 == 1);
int result2 = EVP_EncryptFinal_ex(_ctx, data, &outlen);
ASSERT(result2 == 1);
} }
+20 -10
View File
@@ -8,18 +8,28 @@
#define _AUTH_SARC4_H #define _AUTH_SARC4_H
#include "Define.h" #include "Define.h"
#include <array>
#include <openssl/evp.h> #include <openssl/evp.h>
class ARC4 namespace acore::Crypto
{ {
public: class ARC4
ARC4(uint32 len); {
ARC4(uint8* seed, uint32 len); public:
~ARC4(); ARC4();
void Init(uint8* seed); ~ARC4();
void UpdateData(int len, uint8* data);
private: void Init(uint8 const* seed, size_t len);
EVP_CIPHER_CTX* m_ctx; 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 #endif
+15
View File
@@ -0,0 +1,15 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#ifndef AZEROTHCORE_AUTHDEFINES_H
#define AZEROTHCORE_AUTHDEFINES_H
#include "Define.h"
#include <array>
constexpr size_t SESSION_KEY_LENGTH = 40;
using SessionKey = std::array<uint8, SESSION_KEY_LENGTH>;
#endif
@@ -5,56 +5,37 @@
*/ */
#include "AuthCrypt.h" #include "AuthCrypt.h"
#include "Cryptography/HMACSHA1.h" #include "BigNumber.h"
#include "Cryptography/BigNumber.h" #include "Errors.h"
#include "HMAC.h"
AuthCrypt::AuthCrypt() : AuthCrypt::AuthCrypt() : _initialized(false)
_clientDecrypt(SHA_DIGEST_LENGTH), _serverEncrypt(SHA_DIGEST_LENGTH),
_initialized(false)
{ }
void AuthCrypt::Init(BigNumber* 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 }; void AuthCrypt::Init(SessionKey const& K)
HmacHash clientDecryptHmac(SEED_KEY_SIZE, (uint8*)ServerDecryptionKey); {
uint8* decryptHash = clientDecryptHmac.ComputeHash(K); uint8 ServerEncryptionKey[] = { 0xCC, 0x98, 0xAE, 0x04, 0xE8, 0x97, 0xEA, 0xCA, 0x12, 0xDD, 0xC0, 0x93, 0x42, 0x91, 0x53, 0x57 };
_serverEncrypt.Init(acore::Crypto::HMAC_SHA1::GetDigestOf(ServerEncryptionKey, K));
//ARC4 _serverDecrypt(encryptHash); uint8 ServerDecryptionKey[] = { 0xC2, 0xB3, 0x72, 0x3C, 0xC6, 0xAE, 0xD9, 0xB5, 0x34, 0x3C, 0x53, 0xEE, 0x2F, 0x43, 0x67, 0xCE };
_clientDecrypt.Init(decryptHash); _clientDecrypt.Init(acore::Crypto::HMAC_SHA1::GetDigestOf(ServerDecryptionKey, K));
_serverEncrypt.Init(encryptHash);
//ARC4 _clientEncrypt(decryptHash);
// Drop first 1024 bytes, as WoW uses ARC4-drop1024. // Drop first 1024 bytes, as WoW uses ARC4-drop1024.
uint8 syncBuf[1024]; std::array<uint8, 1024> syncBuf;
memset(syncBuf, 0, 1024); _serverEncrypt.UpdateData(syncBuf);
_clientDecrypt.UpdateData(syncBuf);
_serverEncrypt.UpdateData(1024, syncBuf);
//_clientEncrypt.UpdateData(1024, syncBuf);
memset(syncBuf, 0, 1024);
//_serverDecrypt.UpdateData(1024, syncBuf);
_clientDecrypt.UpdateData(1024, syncBuf);
_initialized = true; _initialized = true;
} }
void AuthCrypt::DecryptRecv(uint8* data, size_t len) void AuthCrypt::DecryptRecv(uint8* data, size_t len)
{ {
if (!_initialized) ASSERT(_initialized);
return; _clientDecrypt.UpdateData(data, len);
_clientDecrypt.UpdateData(len, data);
} }
void AuthCrypt::EncryptSend(uint8* data, size_t len) void AuthCrypt::EncryptSend(uint8* data, size_t len)
{ {
if (!_initialized) ASSERT(_initialized);
return; _serverEncrypt.UpdateData(data, len);
_serverEncrypt.UpdateData(len, data);
} }
@@ -7,24 +7,24 @@
#ifndef _AUTHCRYPT_H #ifndef _AUTHCRYPT_H
#define _AUTHCRYPT_H #define _AUTHCRYPT_H
#include "Cryptography/ARC4.h" #include "ARC4.h"
#include "AuthDefines.h"
class BigNumber; #include <array>
class AuthCrypt class AuthCrypt
{ {
public: public:
AuthCrypt(); AuthCrypt();
void Init(BigNumber* K); void Init(SessionKey const& K);
void DecryptRecv(uint8*, size_t); void DecryptRecv(uint8* data, size_t len);
void EncryptSend(uint8*, size_t); void EncryptSend(uint8* data, size_t len);
bool IsInitialized() const { return _initialized; } bool IsInitialized() const { return _initialized; }
private: private:
ARC4 _clientDecrypt; acore::Crypto::ARC4 _clientDecrypt;
ARC4 _serverEncrypt; acore::Crypto::ARC4 _serverEncrypt;
bool _initialized; bool _initialized;
}; };
#endif #endif
+51 -26
View File
@@ -11,16 +11,12 @@
BigNumber::BigNumber() BigNumber::BigNumber()
: _bn(BN_new()) : _bn(BN_new())
{ } {
}
BigNumber::BigNumber(BigNumber const& bn) BigNumber::BigNumber(BigNumber const& bn)
: _bn(BN_dup(bn._bn)) : _bn(BN_dup(bn.BN()))
{ }
BigNumber::BigNumber(uint32 val)
: _bn(BN_new())
{ {
BN_set_word(_bn, val);
} }
BigNumber::~BigNumber() BigNumber::~BigNumber()
@@ -28,6 +24,13 @@ BigNumber::~BigNumber()
BN_free(_bn); BN_free(_bn);
} }
void BigNumber::SetDword(int32 val)
{
SetDword(uint32(abs(val)));
if (val < 0)
BN_set_negative(_bn, 1);
}
void BigNumber::SetDword(uint32 val) void BigNumber::SetDword(uint32 val)
{ {
BN_set_word(_bn, val); BN_set_word(_bn, val);
@@ -40,16 +43,25 @@ void BigNumber::SetQword(uint64 val)
BN_add_word(_bn, (uint32)(val & 0xFFFFFFFF)); BN_add_word(_bn, (uint32)(val & 0xFFFFFFFF));
} }
void BigNumber::SetBinary(uint8 const* bytes, int32 len) void BigNumber::SetBinary(uint8 const* bytes, int32 len, bool littleEndian)
{ {
uint8* array = new uint8[len]; if (littleEndian)
{
#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L
uint8* array = new uint8[len];
for (int i = 0; i < len; i++) for (int i = 0; i < len; i++)
array[i] = bytes[len - 1 - i]; array[i] = bytes[len - 1 - i];
BN_bin2bn(array, len, _bn); BN_bin2bn(array, len, _bn);
delete[] array; delete[] array;
#else
BN_lebin2bn(bytes, len, _bn);
#endif
}
else
BN_bin2bn(bytes, len, _bn);
} }
void BigNumber::SetHexStr(char const* str) void BigNumber::SetHexStr(char const* str)
@@ -116,7 +128,7 @@ BigNumber BigNumber::operator%=(BigNumber const& bn)
return *this; return *this;
} }
BigNumber BigNumber::Exp(BigNumber const& bn) BigNumber BigNumber::Exp(BigNumber const& bn) const
{ {
BigNumber ret; BigNumber ret;
BN_CTX* bnctx; BN_CTX* bnctx;
@@ -128,7 +140,7 @@ BigNumber BigNumber::Exp(BigNumber const& bn)
return ret; return ret;
} }
BigNumber BigNumber::ModExp(BigNumber const& bn1, BigNumber const& bn2) BigNumber BigNumber::ModExp(BigNumber const& bn1, BigNumber const& bn2) const
{ {
BigNumber ret; BigNumber ret;
BN_CTX* bnctx; BN_CTX* bnctx;
@@ -140,7 +152,7 @@ BigNumber BigNumber::ModExp(BigNumber const& bn1, BigNumber const& bn2)
return ret; return ret;
} }
int32 BigNumber::GetNumBytes(void) int32 BigNumber::GetNumBytes() const
{ {
return BN_num_bytes(_bn); return BN_num_bytes(_bn);
} }
@@ -155,25 +167,38 @@ bool BigNumber::isZero() const
return BN_is_zero(_bn); return BN_is_zero(_bn);
} }
std::unique_ptr<uint8[]> BigNumber::AsByteArray(int32 minSize, bool littleEndian) void BigNumber::GetBytes(uint8* buf, size_t bufsize, bool littleEndian) const
{ {
int numBytes = GetNumBytes(); #if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100000L
int length = (minSize >= numBytes) ? minSize : numBytes; int nBytes = GetNumBytes();
ASSERT(nBytes >= 0, "Bignum has negative number of bytes (%d).", nBytes);
std::size_t numBytes = static_cast<std::size_t>(nBytes);
uint8* array = new uint8[length]; // too large to store
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 we need more bytes than length of BigNumber set the rest to 0
if (length > numBytes) if (numBytes < bufsize)
memset((void*)array, 0, length); memset((void*)buf, 0, bufsize);
BN_bn2bin(_bn, (unsigned char*)array); BN_bn2bin(_bn, buf + (bufsize - numBytes));
// openssl's BN stores data internally in big endian format, reverse if little endian desired // openssl's BN stores data internally in big endian format, reverse if little endian desired
if (littleEndian) if (littleEndian)
std::reverse(array, array + length); std::reverse(buf, buf + bufsize);
#else
int res = littleEndian ? BN_bn2lebinpad(_bn, buf, bufsize) : BN_bn2binpad(_bn, buf, bufsize);
ASSERT(res > 0, "Buffer of size %zu is too small to hold bignum with %d bytes.\n", bufsize, BN_num_bytes(_bn));
#endif
}
std::unique_ptr<uint8[]> ret(array); std::vector<uint8> BigNumber::ToByteVector(int32 minSize, bool littleEndian) const
return ret; {
std::size_t length = std::max(GetNumBytes(), minSize);
std::vector<uint8> v;
v.resize(length);
GetBytes(v.data(), length, littleEndian);
return v;
} }
char* BigNumber::AsHexStr() const char* BigNumber::AsHexStr() const
+31 -11
View File
@@ -12,6 +12,7 @@
#include <array> #include <array>
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector>
struct bignum_st; struct bignum_st;
@@ -20,48 +21,57 @@ class BigNumber
public: public:
BigNumber(); BigNumber();
BigNumber(BigNumber const& bn); BigNumber(BigNumber const& bn);
BigNumber(uint32); BigNumber(uint32 v) : BigNumber() { SetDword(v); }
BigNumber(int32 v) : BigNumber() { SetDword(v); }
BigNumber(std::string const& v) : BigNumber() { SetHexStr(v); }
template<size_t Size>
BigNumber(std::array<uint8, Size> const& v, bool littleEndian = true) : BigNumber() { SetBinary(v.data(), Size, littleEndian); }
~BigNumber(); ~BigNumber();
void SetDword(int32);
void SetDword(uint32); void SetDword(uint32);
void SetQword(uint64); void SetQword(uint64);
void SetBinary(uint8 const* bytes, int32 len); void SetBinary(uint8 const* bytes, int32 len, bool littleEndian = true);
template<typename Container>
auto SetBinary(Container const& c, bool littleEndian = true) -> std::enable_if_t<!std::is_pointer_v<std::decay_t<Container>>> { SetBinary(std::data(c), std::size(c), littleEndian); }
void SetHexStr(char const* str); void SetHexStr(char const* str);
void SetHexStr(std::string const& str) { SetHexStr(str.c_str()); }
void SetRand(int32 numbits); void SetRand(int32 numbits);
BigNumber& operator=(BigNumber const& bn); BigNumber& operator=(BigNumber const& bn);
BigNumber operator+=(BigNumber const& bn); BigNumber operator+=(BigNumber const& bn);
BigNumber operator+(BigNumber const& bn) BigNumber operator+(BigNumber const& bn) const
{ {
BigNumber t(*this); BigNumber t(*this);
return t += bn; return t += bn;
} }
BigNumber operator-=(BigNumber const& bn); BigNumber operator-=(BigNumber const& bn);
BigNumber operator-(BigNumber const& bn) BigNumber operator-(BigNumber const& bn) const
{ {
BigNumber t(*this); BigNumber t(*this);
return t -= bn; return t -= bn;
} }
BigNumber operator*=(BigNumber const& bn); BigNumber operator*=(BigNumber const& bn);
BigNumber operator*(BigNumber const& bn) BigNumber operator*(BigNumber const& bn) const
{ {
BigNumber t(*this); BigNumber t(*this);
return t *= bn; return t *= bn;
} }
BigNumber operator/=(BigNumber const& bn); BigNumber operator/=(BigNumber const& bn);
BigNumber operator/(BigNumber const& bn) BigNumber operator/(BigNumber const& bn) const
{ {
BigNumber t(*this); BigNumber t(*this);
return t /= bn; return t /= bn;
} }
BigNumber operator%=(BigNumber const& bn); BigNumber operator%=(BigNumber const& bn);
BigNumber operator%(BigNumber const& bn) BigNumber operator%(BigNumber const& bn) const
{ {
BigNumber t(*this); BigNumber t(*this);
return t %= bn; return t %= bn;
@@ -69,16 +79,26 @@ public:
[[nodiscard]] bool isZero() const; [[nodiscard]] bool isZero() const;
BigNumber ModExp(BigNumber const& bn1, BigNumber const& bn2); BigNumber ModExp(BigNumber const& bn1, BigNumber const& bn2) const;
BigNumber Exp(BigNumber const&); BigNumber Exp(BigNumber const&) const;
int32 GetNumBytes(); int32 GetNumBytes() const;
struct bignum_st* BN() { return _bn; } struct bignum_st* BN() { return _bn; }
struct bignum_st const* BN() const { return _bn; }
uint32 AsDword(); uint32 AsDword();
std::unique_ptr<uint8[]> AsByteArray(int32 minSize = 0, bool littleEndian = true); 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, Size> buf;
GetBytes(buf.data(), Size, littleEndian);
return buf;
}
[[nodiscard]] char* AsHexStr() const; [[nodiscard]] char* AsHexStr() const;
[[nodiscard]] char* AsDecStr() const; [[nodiscard]] char* AsDecStr() const;
+20
View File
@@ -0,0 +1,20 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#ifndef AZEROTHCORE_CRYPTO_CONSTANTS_H
#define AZEROTHCORE_CRYPTO_CONSTANTS_H
#include "Define.h"
namespace acore::Crypto
{
struct Constants
{
static constexpr size_t SHA1_DIGEST_LENGTH_BYTES = 20;
static constexpr size_t SHA256_DIGEST_LENGTH_BYTES = 32;
};
}
#endif
+99
View File
@@ -0,0 +1,99 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#ifndef AZEROTHCORE_CRYPTO_GENERICS_HPP
#define AZEROTHCORE_CRYPTO_GENERICS_HPP
#include "BigNumber.h"
#include "CryptoRandom.h"
#include "Define.h"
#include "Errors.h"
#include <iterator>
#include <vector>
namespace acore::Impl
{
struct CryptoGenericsImpl
{
template <typename Cipher>
static typename Cipher::IV GenerateRandomIV()
{
typename Cipher::IV iv;
acore::Crypto::GetRandomBytes(iv);
return iv;
}
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 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)
{
tail[N - i] = data.back();
data.pop_back();
}
}
};
}
namespace acore::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 = acore::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
acore::Impl::CryptoGenericsImpl::AppendToBack(data, iv);
acore::Impl::CryptoGenericsImpl::AppendToBack(data, tag);
}
template <typename Cipher>
void AEEncryptWithRandomIV(std::vector<uint8>& data, BigNumber const& key)
{
AEEncryptWithRandomIV<Cipher>(data, key.ToByteArray<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;
acore::Impl::CryptoGenericsImpl::SplitFromBack(data, tag);
acore::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.ToByteArray<Cipher::KEY_SIZE_BYTES>());
}
}
#endif
+107
View File
@@ -0,0 +1,107 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#ifndef AZEROTHCORE_CRYPTOHASH_H
#define AZEROTHCORE_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 acore::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 acore::Crypto
{
using SHA1 = acore::Impl::GenericHash<EVP_sha1, Constants::SHA1_DIGEST_LENGTH_BYTES>;
using SHA256 = acore::Impl::GenericHash<EVP_sha256, Constants::SHA256_DIGEST_LENGTH_BYTES>;
}
#endif
+14
View File
@@ -0,0 +1,14 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#include "CryptoRandom.h"
#include "Errors.h"
#include <openssl/rand.h>
void acore::Crypto::GetRandomBytes(uint8* buf, size_t len)
{
int result = RAND_bytes(buf, len);
ASSERT(result == 1);
}
+31
View File
@@ -0,0 +1,31 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#ifndef AZEROTHCORE_CRYPTORANDOM_H
#define AZEROTHCORE_CRYPTORANDOM_H
#include "Define.h"
#include <array>
namespace acore::Crypto
{
void GetRandomBytes(uint8* buf, size_t len);
template <typename Container>
void GetRandomBytes(Container& c)
{
GetRandomBytes(std::data(c), std::size(c));
}
template <size_t S>
std::array<uint8, S> GetRandomBytes()
{
std::array<uint8, S> arr;
GetRandomBytes(arr);
return arr;
}
}
#endif
+118
View File
@@ -0,0 +1,118 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#ifndef AZEROTHCORE_HMAC_H
#define AZEROTHCORE_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 acore::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 acore::Crypto
{
using HMAC_SHA1 = acore::Impl::GenericHMAC<EVP_sha1, Constants::SHA1_DIGEST_LENGTH_BYTES>;
using HMAC_SHA256 = acore::Impl::GenericHMAC<EVP_sha256, Constants::SHA256_DIGEST_LENGTH_BYTES>;
}
#endif
-61
View File
@@ -1,61 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*/
#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;
}
-34
View File
@@ -1,34 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*/
#ifndef _AUTH_HMAC_H
#define _AUTH_HMAC_H
#include "Define.h"
#include <string>
#include <openssl/hmac.h>
#include <openssl/sha.h>
class BigNumber;
#define SEED_KEY_SIZE 16
class HmacHash
{
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];
};
#endif
-55
View File
@@ -1,55 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*/
#include "SHA1.h"
#include "BigNumber.h"
#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);
}
-37
View File
@@ -1,37 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*/
#ifndef _AUTH_SHA1_H
#define _AUTH_SHA1_H
#include "Define.h"
#include <string>
#include <openssl/sha.h>
class BigNumber;
class SHA1Hash
{
public:
SHA1Hash();
~SHA1Hash();
void UpdateBigNumbers(BigNumber* bn0, ...);
void UpdateData(const uint8* dta, int len);
void UpdateData(const std::string& str);
void Initialize();
void Finalize();
uint8* GetDigest() { return mDigest; };
[[nodiscard]] int GetLength() const { return SHA_DIGEST_LENGTH; };
private:
SHA_CTX mC;
uint8 mDigest[SHA_DIGEST_LENGTH];
};
#endif
+97
View File
@@ -0,0 +1,97 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#include "SRP6.h"
#include "CryptoRandom.h"
#include "Util.h"
#include <algorithm>
#include <functional>
using SHA1 = acore::Crypto::SHA1;
using SRP6 = acore::Crypto::SRP6;
/*static*/ std::array<uint8, 1> const SRP6::g = { 7 };
/*static*/ std::array<uint8, 32> const SRP6::N = HexStrToByteArray<32>("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7", true);
/*static*/ BigNumber const SRP6::_g(SRP6::g);
/*static*/ BigNumber const SRP6::_N(N);
/*static*/ std::pair<SRP6::Salt, SRP6::Verifier> SRP6::MakeRegistrationData(std::string const& username, std::string const& password)
{
std::pair<SRP6::Salt, SRP6::Verifier> res;
Crypto::GetRandomBytes(res.first); // random salt
res.second = CalculateVerifier(username, password, res.first);
return res;
}
/*static*/ SRP6::Verifier SRP6::CalculateVerifier(std::string const& username, std::string const& password, SRP6::Salt const& salt)
{
// v = g ^ H(s || H(u || ':' || p)) mod N
return _g.ModExp(
SHA1::GetDigestOf(
salt,
SHA1::GetDigestOf(username, ":", password)
)
,_N).ToByteArray<32>();
}
/*static*/ SessionKey SRP6::SHA1Interleave(SRP6::EphemeralKey const& S)
{
// split S into two buffers
std::array<uint8, EPHEMERAL_KEY_LENGTH/2> buf0, buf1;
for (size_t i = 0; i < EPHEMERAL_KEY_LENGTH/2; ++i)
{
buf0[i] = S[2 * i + 0];
buf1[i] = S[2 * i + 1];
}
// find position of first nonzero byte
size_t p = 0;
while (p < EPHEMERAL_KEY_LENGTH && !S[p]) ++p;
if (p & 1) ++p; // skip one extra byte if p is odd
p /= 2; // offset into buffers
// hash each of the halves, starting at the first nonzero byte
SHA1::Digest const hash0 = SHA1::GetDigestOf(buf0.data() + p, EPHEMERAL_KEY_LENGTH/2 - p);
SHA1::Digest const hash1 = SHA1::GetDigestOf(buf1.data() + p, EPHEMERAL_KEY_LENGTH/2 - p);
// stick the two hashes back together
SessionKey K;
for (size_t i = 0; i < SHA1::DIGEST_LENGTH; ++i)
{
K[2 * i + 0] = hash0[i];
K[2 * i + 1] = hash1[i];
}
return K;
}
SRP6::SRP6(std::string const& username, Salt const& salt, Verifier const& verifier)
: _I(SHA1::GetDigestOf(username)), _b(Crypto::GetRandomBytes<32>()), _v(verifier), s(salt), B(_B(_b, _v)) {}
std::optional<SessionKey> SRP6::VerifyChallengeResponse(EphemeralKey const& A, SHA1::Digest const& clientM)
{
ASSERT(!_used);
_used = true;
BigNumber const _A(A);
if ((_A % _N).isZero())
return std::nullopt;
BigNumber const u(SHA1::GetDigestOf(A, B));
EphemeralKey const S = (_A * (_v.ModExp(u, _N))).ModExp(_b, N).ToByteArray<32>();
SessionKey K = SHA1Interleave(S);
// NgHash = H(N) xor H(g)
SHA1::Digest const NHash = SHA1::GetDigestOf(N);
SHA1::Digest const gHash = SHA1::GetDigestOf(g);
SHA1::Digest NgHash;
std::transform(NHash.begin(), NHash.end(), gHash.begin(), NgHash.begin(), std::bit_xor<>());
SHA1::Digest const ourM = SHA1::GetDigestOf(NgHash, _I, s, A, B, K);
if (ourM == clientM)
return K;
else
return std::nullopt;
}
+71
View File
@@ -0,0 +1,71 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#ifndef AZEROTHCORE_SRP6_H
#define AZEROTHCORE_SRP6_H
#include "AuthDefines.h"
#include "BigNumber.h"
#include "Define.h"
#include "Common.h"
#include "CryptoHash.h"
#include <array>
#include <optional>
namespace acore::Crypto
{
class SRP6
{
public:
static constexpr size_t SALT_LENGTH = 32;
using Salt = std::array<uint8, SALT_LENGTH>;
static constexpr size_t VERIFIER_LENGTH = 32;
using Verifier = std::array<uint8, VERIFIER_LENGTH>;
static constexpr size_t EPHEMERAL_KEY_LENGTH = 32;
using EphemeralKey = std::array<uint8, EPHEMERAL_KEY_LENGTH>;
static std::array<uint8, 1> const g;
static std::array<uint8, 32> const N;
// username + password must be passed through Utf8ToUpperOnlyLatin FIRST!
static std::pair<Salt, Verifier> MakeRegistrationData(std::string const& username, std::string const& password);
// username + password must be passed through Utf8ToUpperOnlyLatin FIRST!
static bool CheckLogin(std::string const& username, std::string const& password, Salt const& salt, Verifier const& verifier)
{
return (verifier == CalculateVerifier(username, password, salt));
}
static SHA1::Digest GetSessionVerifier(EphemeralKey const& A, SHA1::Digest const& clientM, SessionKey const& K)
{
return SHA1::GetDigestOf(A, clientM, K);
}
SRP6(std::string const& username, Salt const& salt, Verifier const& verifier);
std::optional<SessionKey> VerifyChallengeResponse(EphemeralKey const& A, SHA1::Digest const& clientM);
private:
bool _used = false; // a single instance can only be used to verify once
static Verifier CalculateVerifier(std::string const& username, std::string const& password, Salt const& salt);
static SessionKey SHA1Interleave(EphemeralKey const& S);
/* global algorithm parameters */
static BigNumber const _g; // a [g]enerator for the ring of integers mod N, algorithm parameter
static BigNumber const _N; // the modulus, an algorithm parameter; all operations are mod this
static EphemeralKey _B(BigNumber const& b, BigNumber const& v) { return ((_g.ModExp(b,_N) + (v * 3)) % N).ToByteArray<EPHEMERAL_KEY_LENGTH>(); }
/* per-instantiation parameters, set on construction */
SHA1::Digest const _I; // H(I) - the username, all uppercase
BigNumber const _b; // b - randomly chosen by the server, 19 bytes, never given out
BigNumber const _v; // v - the user's password verifier, derived from s + H(USERNAME || ":" || PASSWORD)
public:
Salt const s; // s - the user's password salt, random, used to calculate v on registration
EphemeralKey const B; // B = 3v + g^b
};
}
#endif
@@ -0,0 +1,50 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
* Copyright (C) 2008-2021 TrinityCore <http://www.trinitycore.org/>
*/
#include <cstring>
#include "CryptoHash.h"
#ifndef AZEROTHCORE_SESSIONKEYGENERATOR_HPP
#define AZEROTHCORE_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 = { };
typename Hash::Digest o1 = { };
typename Hash::Digest o2 = { };
typename Hash::Digest::const_iterator o0it;
};
#endif
@@ -1,67 +0,0 @@
/*
* Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU GPL v2 license, you may redistribute it and/or modify it under version 2 of the License, or (at your option), any later version.
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
* Copyright (C) 2005-2009 MaNGOS <http://getmangos.com/>
*/
#include "SHA1.h"
#ifndef _WARDEN_KEY_GENERATION_H
#define _WARDEN_KEY_GENERATION_H
class SHA1Randx
{
public:
SHA1Randx(uint8* buff, uint32 size)
{
uint32 taken = size / 2;
sh.Initialize();
sh.UpdateData(buff, taken);
sh.Finalize();
memcpy(o1, sh.GetDigest(), 20);
sh.Initialize();
sh.UpdateData(buff + taken, size - taken);
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
+23 -5
View File
@@ -5,6 +5,7 @@
*/ */
#include "Field.h" #include "Field.h"
#include "Errors.h"
Field::Field() Field::Field()
{ {
@@ -35,7 +36,7 @@ void Field::SetByteValue(const void* newValue, const size_t newSize, enum_field_
data.raw = true; data.raw = true;
} }
void Field::SetStructuredValue(char* newValue, enum_field_types newType) void Field::SetStructuredValue(char* newValue, enum_field_types newType, uint32 length)
{ {
if (data.value) if (data.value)
CleanUp(); CleanUp();
@@ -43,12 +44,29 @@ void Field::SetStructuredValue(char* newValue, enum_field_types newType)
// This value stores somewhat structured data that needs function style casting // This value stores somewhat structured data that needs function style casting
if (newValue) if (newValue)
{ {
size_t size = strlen(newValue); data.value = new char[length + 1];
data.value = new char [size + 1]; memcpy(data.value, newValue, length);
strcpy((char*)data.value, newValue); *(reinterpret_cast<char*>(data.value) + length) = '\0';
data.length = size; data.length = length;
} }
data.type = newType; data.type = newType;
data.raw = false; data.raw = false;
} }
std::vector<uint8> Field::GetBinary() const
{
std::vector<uint8> result;
if (!data.value || !data.length)
return result;
result.resize(data.length);
memcpy(result.data(), data.value, data.length);
return result;
}
void Field::GetBinarySizeChecked(uint8* buf, size_t length) const
{
ASSERT(data.value && (data.length == length));
memcpy(buf, data.value, length);
}
+13 -1
View File
@@ -11,6 +11,7 @@
#include "Log.h" #include "Log.h"
#include <mysql.h> #include <mysql.h>
#include <array>
class Field class Field
{ {
@@ -245,6 +246,15 @@ public:
return data.value == nullptr; return data.value == nullptr;
} }
[[nodiscard]] std::vector<uint8> GetBinary() const;
template<size_t S>
[[nodiscard]] std::array<uint8, S> GetBinary() const
{
std::array<uint8, S> buf;
GetBinarySizeChecked(buf.data(), S);
return buf;
}
protected: protected:
Field(); Field();
~Field(); ~Field();
@@ -268,7 +278,7 @@ protected:
#endif #endif
void SetByteValue(void const* newValue, size_t const newSize, enum_field_types newType, uint32 length); void SetByteValue(void const* newValue, size_t const newSize, enum_field_types newType, uint32 length);
void SetStructuredValue(char* newValue, enum_field_types newType); void SetStructuredValue(char* newValue, enum_field_types newType, uint32 length);
void CleanUp() void CleanUp()
{ {
@@ -342,6 +352,8 @@ protected:
data.type == MYSQL_TYPE_LONGLONG ); data.type == MYSQL_TYPE_LONGLONG );
} }
void GetBinarySizeChecked(uint8* buf, size_t size) const;
private: private:
#ifdef ACORE_DEBUG #ifdef ACORE_DEBUG
static char const* FieldTypeToString(enum_field_types type) static char const* FieldTypeToString(enum_field_types type)
@@ -23,16 +23,16 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_SEL_ACCOUNT_BANNED_BY_USERNAME, "SELECT account.id, username FROM account, account_banned WHERE account.id = account_banned.id AND active = 1 AND username LIKE CONCAT('%%', ?, '%%') GROUP BY account.id", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_BANNED_BY_USERNAME, "SELECT account.id, username FROM account, account_banned WHERE account.id = account_banned.id AND active = 1 AND username LIKE CONCAT('%%', ?, '%%') GROUP BY account.id", CONNECTION_SYNCH);
PrepareStatement(LOGIN_INS_ACCOUNT_AUTO_BANNED, "INSERT INTO account_banned VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, 'Trinity realmd', 'Failed login autoban', 1)", CONNECTION_ASYNC); PrepareStatement(LOGIN_INS_ACCOUNT_AUTO_BANNED, "INSERT INTO account_banned VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, 'Trinity realmd', 'Failed login autoban', 1)", CONNECTION_ASYNC);
PrepareStatement(LOGIN_DEL_ACCOUNT_BANNED, "DELETE FROM account_banned WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_DEL_ACCOUNT_BANNED, "DELETE FROM account_banned WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_SESSIONKEY, "SELECT a.sessionkey, a.id, aa.gmlevel FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_SESSIONKEY, "SELECT a.session_key, a.id, aa.gmlevel FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE username = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_UPD_VS, "UPDATE account SET v = ?, s = ? WHERE username = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_LOGON, "UPDATE account SET salt = ?, verifier = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_LOGONPROOF, "UPDATE account SET sessionkey = ?, last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_UPD_LOGONPROOF, "UPDATE account SET session_key = ?, last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE username = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_LOGONCHALLENGE, "SELECT a.sha_pass_hash, a.id, a.locked, a.lock_country, a.last_ip, aa.gmlevel, a.v, a.s, a.token_key FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE a.username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_LOGONCHALLENGE, "SELECT a.id, a.locked, a.lock_country, a.last_ip, aa.gmlevel, a.salt, a.verifier, a.token_key FROM account a LEFT JOIN account_access aa ON (a.id = aa.id) WHERE a.username = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_LOGON_COUNTRY, "SELECT country FROM ip2nation WHERE ip < ? ORDER BY ip DESC LIMIT 0,1", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_LOGON_COUNTRY, "SELECT country FROM ip2nation WHERE ip < ? ORDER BY ip DESC LIMIT 0,1", CONNECTION_SYNCH);
PrepareStatement(LOGIN_UPD_FAILEDLOGINS, "UPDATE account SET failed_logins = failed_logins + 1 WHERE username = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_FAILEDLOGINS, "UPDATE account SET failed_logins = failed_logins + 1 WHERE username = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_FAILEDLOGINS, "SELECT id, failed_logins FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_FAILEDLOGINS, "SELECT id, failed_logins FROM account WHERE username = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME, "SELECT id FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME, "SELECT id FROM account WHERE username = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_NAME, "SELECT id, username FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_NAME, "SELECT id, username FROM account WHERE username = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME, "SELECT id, sessionkey, last_ip, locked, lock_country, expansion, mutetime, locale, recruiter, os, totaltime FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME, "SELECT id, session_key, last_ip, locked, lock_country, expansion, mutetime, locale, recruiter, os, totaltime FROM account WHERE username = ? AND session_key IS NOT NULL", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_EMAIL, "SELECT id, username FROM account WHERE email = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_EMAIL, "SELECT id, username FROM account WHERE email = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_NUM_CHARS_ON_REALM, "SELECT numchars FROM realmcharacters WHERE realmid = ? AND acctid= ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_NUM_CHARS_ON_REALM, "SELECT numchars FROM realmcharacters WHERE realmid = ? AND acctid= ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_ACCOUNT_BY_IP, "SELECT id, username FROM account WHERE last_ip = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_BY_IP, "SELECT id, username FROM account WHERE last_ip = ?", CONNECTION_SYNCH);
@@ -45,13 +45,12 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_DEL_REALM_CHARACTERS, "DELETE FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_DEL_REALM_CHARACTERS, "DELETE FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_INS_REALM_CHARACTERS, "INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(LOGIN_INS_REALM_CHARACTERS, "INSERT INTO realmcharacters (numchars, acctid, realmid) VALUES (?, ?, ?)", CONNECTION_ASYNC);
PrepareStatement(LOGIN_SEL_SUM_REALM_CHARACTERS, "SELECT SUM(numchars) FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_SUM_REALM_CHARACTERS, "SELECT SUM(numchars) FROM realmcharacters WHERE acctid = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_INS_ACCOUNT, "INSERT INTO account(username, sha_pass_hash, expansion, joindate) VALUES(?, ?, ?, NOW())", CONNECTION_ASYNC); PrepareStatement(LOGIN_INS_ACCOUNT, "INSERT INTO account(username, salt, verifier, expansion, joindate) VALUES(?, ?, ?, ?, NOW())", CONNECTION_ASYNC);
PrepareStatement(LOGIN_INS_REALM_CHARACTERS_INIT, "INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist, account LEFT JOIN realmcharacters ON acctid=account.id WHERE acctid IS NULL", CONNECTION_ASYNC); PrepareStatement(LOGIN_INS_REALM_CHARACTERS_INIT, "INSERT INTO realmcharacters (realmid, acctid, numchars) SELECT realmlist.id, account.id, 0 FROM realmlist, account LEFT JOIN realmcharacters ON acctid=account.id WHERE acctid IS NULL", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_EXPANSION, "UPDATE account SET expansion = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_EXPANSION, "UPDATE account SET expansion = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_ACCOUNT_LOCK, "UPDATE account SET locked = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_ACCOUNT_LOCK, "UPDATE account SET locked = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_ACCOUNT_LOCK_CONTRY, "UPDATE account SET lock_country = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_ACCOUNT_LOCK_CONTRY, "UPDATE account SET lock_country = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_USERNAME, "UPDATE account SET v = 0, s = 0, username = ?, sha_pass_hash = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_USERNAME, "UPDATE account SET username = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_PASSWORD, "UPDATE account SET v = 0, s = 0, sha_pass_hash = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_MUTE_TIME, "UPDATE account SET mutetime = ? , mutereason = ? , muteby = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_MUTE_TIME, "UPDATE account SET mutetime = ? , mutereason = ? , muteby = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_MUTE_TIME_LOGIN, "UPDATE account SET mutetime = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_MUTE_TIME_LOGIN, "UPDATE account SET mutetime = ? WHERE id = ?", CONNECTION_ASYNC);
PrepareStatement(LOGIN_UPD_LAST_IP, "UPDATE account SET last_ip = ? WHERE username = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_LAST_IP, "UPDATE account SET last_ip = ? WHERE username = ?", CONNECTION_ASYNC);
@@ -66,8 +65,8 @@ void LoginDatabaseConnection::DoPrepareStatements()
PrepareStatement(LOGIN_GET_ACCOUNT_ACCESS_GMLEVEL, "SELECT gmlevel FROM account_access WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_GET_ACCOUNT_ACCESS_GMLEVEL, "SELECT gmlevel FROM account_access WHERE id = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_GET_GMLEVEL_BY_REALMID, "SELECT gmlevel FROM account_access WHERE id = ? AND (RealmID = ? OR RealmID = -1)", CONNECTION_SYNCH); PrepareStatement(LOGIN_GET_GMLEVEL_BY_REALMID, "SELECT gmlevel FROM account_access WHERE id = ? AND (RealmID = ? OR RealmID = -1)", CONNECTION_SYNCH);
PrepareStatement(LOGIN_GET_USERNAME_BY_ID, "SELECT username FROM account WHERE id = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_GET_USERNAME_BY_ID, "SELECT username FROM account WHERE id = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_CHECK_PASSWORD, "SELECT 1 FROM account WHERE id = ? AND sha_pass_hash = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_CHECK_PASSWORD, "SELECT salt, verifier FROM account WHERE id = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_CHECK_PASSWORD_BY_NAME, "SELECT 1 FROM account WHERE username = ? AND sha_pass_hash = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_CHECK_PASSWORD_BY_NAME, "SELECT salt, verifier FROM account WHERE username = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_PINFO, "SELECT a.username, aa.gmlevel, a.email, a.reg_mail, a.last_ip, DATE_FORMAT(a.last_login, '%Y-%m-%d %T'), a.mutetime, a.mutereason, a.muteby, a.failed_logins, a.locked, a.OS FROM account a LEFT JOIN account_access aa ON (a.id = aa.id AND (aa.RealmID = ? OR aa.RealmID = -1)) WHERE a.id = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_PINFO, "SELECT a.username, aa.gmlevel, a.email, a.reg_mail, a.last_ip, DATE_FORMAT(a.last_login, '%Y-%m-%d %T'), a.mutetime, a.mutereason, a.muteby, a.failed_logins, a.locked, a.OS FROM account a LEFT JOIN account_access aa ON (a.id = aa.id AND (aa.RealmID = ? OR aa.RealmID = -1)) WHERE a.id = ?", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_PINFO_BANS, "SELECT unbandate, bandate = unbandate, bannedby, banreason FROM account_banned WHERE id = ? AND active ORDER BY bandate ASC LIMIT 1", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_PINFO_BANS, "SELECT unbandate, bandate = unbandate, bannedby, banreason FROM account_banned WHERE id = ? AND active ORDER BY bandate ASC LIMIT 1", CONNECTION_SYNCH);
PrepareStatement(LOGIN_SEL_GM_ACCOUNTS, "SELECT a.username, aa.gmlevel FROM account a, account_access aa WHERE a.id=aa.id AND aa.gmlevel >= ? AND (aa.realmid = -1 OR aa.realmid = ?)", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_GM_ACCOUNTS, "SELECT a.username, aa.gmlevel FROM account a, account_access aa WHERE a.id=aa.id AND aa.gmlevel >= ? AND (aa.realmid = -1 OR aa.realmid = ?)", CONNECTION_SYNCH);
@@ -42,7 +42,7 @@ enum LoginDatabaseStatements
LOGIN_INS_ACCOUNT_AUTO_BANNED, LOGIN_INS_ACCOUNT_AUTO_BANNED,
LOGIN_DEL_ACCOUNT_BANNED, LOGIN_DEL_ACCOUNT_BANNED,
LOGIN_SEL_SESSIONKEY, LOGIN_SEL_SESSIONKEY,
LOGIN_UPD_VS, LOGIN_UPD_LOGON,
LOGIN_UPD_LOGONPROOF, LOGIN_UPD_LOGONPROOF,
LOGIN_SEL_LOGONCHALLENGE, LOGIN_SEL_LOGONCHALLENGE,
LOGIN_SEL_LOGON_COUNTRY, LOGIN_SEL_LOGON_COUNTRY,
@@ -71,7 +71,6 @@ enum LoginDatabaseStatements
LOGIN_UPD_ACCOUNT_LOCK, LOGIN_UPD_ACCOUNT_LOCK,
LOGIN_UPD_ACCOUNT_LOCK_CONTRY, LOGIN_UPD_ACCOUNT_LOCK_CONTRY,
LOGIN_UPD_USERNAME, LOGIN_UPD_USERNAME,
LOGIN_UPD_PASSWORD,
LOGIN_UPD_MUTE_TIME, LOGIN_UPD_MUTE_TIME,
LOGIN_UPD_MUTE_TIME_LOGIN, LOGIN_UPD_MUTE_TIME_LOGIN,
LOGIN_UPD_LAST_IP, LOGIN_UPD_LAST_IP,
+29 -8
View File
@@ -61,7 +61,10 @@ void PreparedStatement::BindParameters()
m_stmt->setDouble(i, statement_data[i].data.d); m_stmt->setDouble(i, statement_data[i].data.d);
break; break;
case TYPE_STRING: case TYPE_STRING:
m_stmt->setString(i, statement_data[i].str.c_str()); m_stmt->setBinary(i, statement_data[i].binary, true);
break;
case TYPE_BINARY:
m_stmt->setBinary(i, statement_data[i].binary, false);
break; break;
case TYPE_NULL: case TYPE_NULL:
m_stmt->setNull(i); m_stmt->setNull(i);
@@ -179,10 +182,20 @@ void PreparedStatement::setString(const uint8 index, const std::string& value)
if (index >= statement_data.size()) if (index >= statement_data.size())
statement_data.resize(index + 1); statement_data.resize(index + 1);
statement_data[index].str = value; statement_data[index].binary.resize(value.length() + 1);
memcpy(statement_data[index].binary.data(), value.c_str(), value.length() + 1);
statement_data[index].type = TYPE_STRING; statement_data[index].type = TYPE_STRING;
} }
void PreparedStatement::setBinary(const uint8 index, const std::vector<uint8>& value)
{
if (index >= statement_data.size())
statement_data.resize(index + 1);
statement_data[index].binary = value;
statement_data[index].type = TYPE_BINARY;
}
void PreparedStatement::setNull(const uint8 index) void PreparedStatement::setNull(const uint8 index)
{ {
if (index >= statement_data.size()) if (index >= statement_data.size())
@@ -332,21 +345,26 @@ void MySQLPreparedStatement::setDouble(const uint8 index, const double value)
setValue(param, MYSQL_TYPE_DOUBLE, &value, sizeof(double), (value > 0.0f)); setValue(param, MYSQL_TYPE_DOUBLE, &value, sizeof(double), (value > 0.0f));
} }
void MySQLPreparedStatement::setString(const uint8 index, const char* value) void MySQLPreparedStatement::setBinary(const uint8 index, const std::vector<uint8>& value, bool isString)
{ {
CheckValidIndex(index); CheckValidIndex(index);
m_paramsSet[index] = true; m_paramsSet[index] = true;
MYSQL_BIND* param = &m_bind[index]; MYSQL_BIND* param = &m_bind[index];
size_t len = strlen(value) + 1; uint32 len = uint32(value.size());
param->buffer_type = MYSQL_TYPE_VAR_STRING; param->buffer_type = MYSQL_TYPE_BLOB;
delete [] static_cast<char*>(param->buffer); delete [] static_cast<char*>(param->buffer);
param->buffer = new char[len]; param->buffer = new char[len];
param->buffer_length = len; param->buffer_length = len;
param->is_null_value = 0; param->is_null_value = 0;
delete param->length; delete param->length;
param->length = new unsigned long(len - 1); param->length = new unsigned long(len);
if (isString)
{
*param->length -= 1;
param->buffer_type = MYSQL_TYPE_VAR_STRING;
}
memcpy(param->buffer, value, len); memcpy(param->buffer, value.data(), len);
} }
void MySQLPreparedStatement::setNull(const uint8 index) void MySQLPreparedStatement::setNull(const uint8 index)
@@ -422,7 +440,10 @@ std::string MySQLPreparedStatement::getQueryString(std::string const& sqlPattern
ss << m_stmt->statement_data[i].data.d; ss << m_stmt->statement_data[i].data.d;
break; break;
case TYPE_STRING: case TYPE_STRING:
ss << '\'' << m_stmt->statement_data[i].str << '\''; ss << '\'' << (char const*)m_stmt->statement_data[i].binary.data() << '\'';
break;
case TYPE_BINARY:
ss << "BINARY";
break; break;
case TYPE_NULL: case TYPE_NULL:
ss << "nullptr"; ss << "nullptr";
+10 -2
View File
@@ -45,6 +45,7 @@ enum PreparedStatementValueType
TYPE_FLOAT, TYPE_FLOAT,
TYPE_DOUBLE, TYPE_DOUBLE,
TYPE_STRING, TYPE_STRING,
TYPE_BINARY,
TYPE_NULL TYPE_NULL
}; };
@@ -52,7 +53,7 @@ struct PreparedStatementData
{ {
PreparedStatementDataUnion data; PreparedStatementDataUnion data;
PreparedStatementValueType type; PreparedStatementValueType type;
std::string str; std::vector<uint8> binary;
}; };
//- Forward declare //- Forward declare
@@ -81,6 +82,13 @@ public:
void setFloat(const uint8 index, const float value); void setFloat(const uint8 index, const float value);
void setDouble(const uint8 index, const double value); void setDouble(const uint8 index, const double value);
void setString(const uint8 index, const std::string& value); void setString(const uint8 index, const std::string& value);
void setBinary(const uint8 index, const std::vector<uint8>& value);
template<size_t Size>
void setBinary(const uint8 index, std::array<uint8, Size> const& value)
{
std::vector<uint8> vec(value.begin(), value.end());
setBinary(index, vec);
}
void setNull(const uint8 index); void setNull(const uint8 index);
protected: protected:
@@ -115,7 +123,7 @@ public:
void setInt64(const uint8 index, const int64 value); void setInt64(const uint8 index, const int64 value);
void setFloat(const uint8 index, const float value); void setFloat(const uint8 index, const float value);
void setDouble(const uint8 index, const double value); void setDouble(const uint8 index, const double value);
void setString(const uint8 index, const char* value); void setBinary(const uint8 index, const std::vector<uint8>& value, bool isString);
void setNull(const uint8 index); void setNull(const uint8 index);
protected: protected:
+8 -1
View File
@@ -151,8 +151,15 @@ bool ResultSet::NextRow()
return false; return false;
} }
unsigned long* lengths = mysql_fetch_lengths(_result);
if (!lengths)
{
CleanUp();
return false;
}
for (uint32 i = 0; i < _fieldCount; i++) for (uint32 i = 0; i < _fieldCount; i++)
_currentRow[i].SetStructuredValue(row[i], _fields[i].type); _currentRow[i].SetStructuredValue(row[i], _fields[i].type, lengths[i]);
return true; return true;
} }
+1 -1
View File
@@ -9,9 +9,9 @@
#include "WorldPacket.h" #include "WorldPacket.h"
#include "Configuration/Config.h" #include "Configuration/Config.h"
#include "Util.h" #include "Util.h"
#include "SHA1.h"
#include "Implementation/LoginDatabase.h" // For logging #include "Implementation/LoginDatabase.h" // For logging
extern LoginDatabaseWorkerPool LoginDatabase; extern LoginDatabaseWorkerPool LoginDatabase;
#include <stdarg.h> #include <stdarg.h>
+13
View File
@@ -17,6 +17,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <cstring> #include <cstring>
#include <array>
// Root of ByteBuffer exception hierarchy // Root of ByteBuffer exception hierarchy
class ByteBufferException : public std::exception class ByteBufferException : public std::exception
@@ -330,6 +331,12 @@ public:
_rpos += len; _rpos += len;
} }
template<size_t Size>
void read(std::array<uint8, Size>& arr)
{
read(arr.data(), Size);
}
void readPackGUID(uint64& guid) void readPackGUID(uint64& guid)
{ {
if (rpos() + 1 > size()) if (rpos() + 1 > size())
@@ -452,6 +459,12 @@ public:
append(buffer.contents(), buffer.wpos()); 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 // can be used in SMSG_MONSTER_MOVE opcode
void appendPackXYZ(float x, float y, float z) void appendPackXYZ(float x, float y, float z)
{ {
+3 -5
View File
@@ -633,7 +633,7 @@ bool Utf8ToUpperOnlyLatin(std::string& utf8String)
return WStrToUtf8(wstr, utf8String); return WStrToUtf8(wstr, utf8String);
} }
std::string ByteArrayToHexStr(uint8 const* bytes, uint32 arrayLen, bool reverse /* = false */) std::string acore::Impl::ByteArrayToHexStr(uint8 const* bytes, size_t arrayLen, bool reverse /* = false */)
{ {
int32 init = 0; int32 init = 0;
int32 end = arrayLen; int32 end = arrayLen;
@@ -657,11 +657,9 @@ std::string ByteArrayToHexStr(uint8 const* bytes, uint32 arrayLen, bool reverse
return ss.str(); return ss.str();
} }
void HexStrToByteArray(std::string const& str, uint8* out, bool reverse /*= false*/) void acore::Impl::HexStrToByteArray(std::string const& str, uint8* out, size_t outlen, bool reverse /*= false*/)
{ {
// string must have even number of characters ASSERT(str.size() == (2 * outlen));
if (str.length() & 1)
return;
int32 init = 0; int32 init = 0;
int32 end = int32(str.length()); int32 end = int32(str.length());
+25 -2
View File
@@ -17,6 +17,7 @@
#include <list> #include <list>
#include <map> #include <map>
#include <ace/INET_Addr.h> #include <ace/INET_Addr.h>
#include <array>
// Searcher for map of structs // Searcher for map of structs
template<typename T, class S> struct Finder template<typename T, class S> struct Finder
@@ -345,8 +346,30 @@ uint32 GetPID();
bool StringEqualI(std::string_view str1, std::string_view str2); bool StringEqualI(std::string_view str1, std::string_view str2);
std::string ByteArrayToHexStr(uint8 const* bytes, uint32 length, bool reverse = false); namespace acore::Impl
void HexStrToByteArray(std::string const& str, uint8* out, bool reverse = false); {
std::string ByteArrayToHexStr(uint8 const* bytes, size_t length, bool reverse = false);
void HexStrToByteArray(std::string const& str, uint8* out, size_t outlen, bool reverse = false);
}
template<typename Container>
std::string ByteArrayToHexStr(Container const& c, bool reverse = false)
{
return acore::Impl::ByteArrayToHexStr(std::data(c), std::size(c), reverse);
}
template<size_t Size>
void HexStrToByteArray(std::string const& str, std::array<uint8, Size>& buf, bool reverse = false)
{
acore::Impl::HexStrToByteArray(str, buf.data(), Size, reverse);
}
template<size_t Size>
std::array<uint8, Size> HexStrToByteArray(std::string const& str, bool reverse = false)
{
std::array<uint8, Size> arr;
HexStrToByteArray(str, arr, reverse);
return arr;
}
bool StringContainsStringI(std::string const& haystack, std::string const& needle); bool StringContainsStringI(std::string const& haystack, std::string const& needle);
template <typename T> template <typename T>
+36 -182
View File
@@ -8,6 +8,8 @@
#include <openssl/md5.h> #include <openssl/md5.h>
#include "Common.h" #include "Common.h"
#include "CryptoRandom.h"
#include "CryptoHash.h"
#include "Database/DatabaseEnv.h" #include "Database/DatabaseEnv.h"
#include "ByteBuffer.h" #include "ByteBuffer.h"
#include "Configuration/Config.h" #include "Configuration/Config.h"
@@ -16,7 +18,6 @@
#include "AuthSocket.h" #include "AuthSocket.h"
#include "AuthCodes.h" #include "AuthCodes.h"
#include "TOTP.h" #include "TOTP.h"
#include "SHA1.h"
#include "openssl/crypto.h" #include "openssl/crypto.h"
#define ChunkSize 2048 #define ChunkSize 2048
@@ -64,9 +65,9 @@ typedef struct AUTH_LOGON_CHALLENGE_C
typedef struct AUTH_LOGON_PROOF_C typedef struct AUTH_LOGON_PROOF_C
{ {
uint8 cmd; uint8 cmd;
uint8 A[32]; acore::Crypto::SRP6::EphemeralKey A;
uint8 M1[20]; acore::Crypto::SHA1::Digest clientM;
uint8 crc_hash[20]; acore::Crypto::SHA1::Digest crc_hash;
uint8 number_of_keys; uint8 number_of_keys;
uint8 securityFlags; // 0x00-0x04 uint8 securityFlags; // 0x00-0x04
} sAuthLogonProof_C; } sAuthLogonProof_C;
@@ -75,7 +76,7 @@ typedef struct AUTH_LOGON_PROOF_S
{ {
uint8 cmd; uint8 cmd;
uint8 error; uint8 error;
uint8 M2[20]; acore::Crypto::SHA1::Digest M2;
uint32 unk1; uint32 unk1;
uint32 unk2; uint32 unk2;
uint16 unk3; uint16 unk3;
@@ -85,7 +86,7 @@ typedef struct AUTH_LOGON_PROOF_S_OLD
{ {
uint8 cmd; uint8 cmd;
uint8 error; uint8 error;
uint8 M2[20]; acore::Crypto::SHA1::Digest M2;
uint32 unk2; uint32 unk2;
} sAuthLogonProof_S_Old; } sAuthLogonProof_S_Old;
@@ -93,8 +94,7 @@ typedef struct AUTH_RECONNECT_PROOF_C
{ {
uint8 cmd; uint8 cmd;
uint8 R1[16]; uint8 R1[16];
uint8 R2[20]; acore::Crypto::SHA1::Digest R2, R3;
uint8 R3[20];
uint8 number_of_keys; uint8 number_of_keys;
} sAuthReconnectProof_C; } sAuthReconnectProof_C;
@@ -183,8 +183,6 @@ AuthSocket::AuthSocket(RealmSocket& socket) :
pPatch(nullptr), socket_(socket), _status(STATUS_CHALLENGE), _build(0), pPatch(nullptr), socket_(socket), _status(STATUS_CHALLENGE), _build(0),
_expversion(0), _accountSecurityLevel(SEC_PLAYER) _expversion(0), _accountSecurityLevel(SEC_PLAYER)
{ {
N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7");
g.SetDword(7);
} }
// Close patch file descriptor before leaving // Close patch file descriptor before leaving
@@ -273,45 +271,6 @@ void AuthSocket::OnRead()
} }
} }
// Make the SRP6 calculation from hash in dB
void AuthSocket::_SetVSFields(const std::string& rI)
{
s.SetRand(s_BYTE_SIZE * 8);
BigNumber I;
I.SetHexStr(rI.c_str());
// In case of leading zeros in the rI hash, restore them
uint8 mDigest[SHA_DIGEST_LENGTH];
memset(mDigest, 0, SHA_DIGEST_LENGTH);
if (I.GetNumBytes() <= SHA_DIGEST_LENGTH)
memcpy(mDigest, I.AsByteArray().get(), I.GetNumBytes());
std::reverse(mDigest, mDigest + SHA_DIGEST_LENGTH);
SHA1Hash sha;
sha.UpdateData(s.AsByteArray().get(), s.GetNumBytes());
sha.UpdateData(mDigest, SHA_DIGEST_LENGTH);
sha.Finalize();
BigNumber x;
x.SetBinary(sha.GetDigest(), sha.GetLength());
v = g.ModExp(x, N);
// No SQL injection (username escaped)
char* v_hex, *s_hex;
v_hex = v.AsHexStr();
s_hex = s.AsHexStr();
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_VS);
stmt->setString(0, v_hex);
stmt->setString(1, s_hex);
stmt->setString(2, _login);
LoginDatabase.Execute(stmt);
OPENSSL_free(v_hex);
OPENSSL_free(s_hex);
}
std::map<std::string, uint32> LastLoginAttemptTimeForIP; std::map<std::string, uint32> LastLoginAttemptTimeForIP;
uint32 LastLoginAttemptCleanTime = 0; uint32 LastLoginAttemptCleanTime = 0;
ACE_Thread_Mutex LastLoginAttemptMutex; ACE_Thread_Mutex LastLoginAttemptMutex;
@@ -434,12 +393,12 @@ bool AuthSocket::_HandleLogonChallenge()
// If the IP is 'locked', check that the player comes indeed from the correct IP address // If the IP is 'locked', check that the player comes indeed from the correct IP address
bool locked = false; bool locked = false;
if (fields[2].GetUInt8() == 1) // if ip is locked if (fields[1].GetUInt8() == 1) // if ip is locked
{ {
sLog->outDebug(LOG_FILTER_NETWORKIO, "[AuthChallenge] Account '%s' is locked to IP - '%s'", _login.c_str(), fields[3].GetCString()); sLog->outDebug(LOG_FILTER_NETWORKIO, "[AuthChallenge] Account '%s' is locked to IP - '%s'", _login.c_str(), fields[2].GetCString());
sLog->outDebug(LOG_FILTER_NETWORKIO, "[AuthChallenge] Player address is '%s'", ip_address.c_str()); sLog->outDebug(LOG_FILTER_NETWORKIO, "[AuthChallenge] Player address is '%s'", ip_address.c_str());
if (strcmp(fields[4].GetCString(), ip_address.c_str()) != 0) if (strcmp(fields[3].GetCString(), ip_address.c_str()) != 0)
{ {
sLog->outDebug(LOG_FILTER_NETWORKIO, "[AuthChallenge] Account IP differs"); sLog->outDebug(LOG_FILTER_NETWORKIO, "[AuthChallenge] Account IP differs");
pkt << uint8(WOW_FAIL_LOCKED_ENFORCED); pkt << uint8(WOW_FAIL_LOCKED_ENFORCED);
@@ -451,7 +410,7 @@ bool AuthSocket::_HandleLogonChallenge()
else else
{ {
sLog->outDebug(LOG_FILTER_NETWORKIO, "[AuthChallenge] Account '%s' is not locked to ip", _login.c_str()); sLog->outDebug(LOG_FILTER_NETWORKIO, "[AuthChallenge] Account '%s' is not locked to ip", _login.c_str());
std::string accountCountry = fields[3].GetString(); std::string accountCountry = fields[2].GetString();
if (accountCountry.empty() || accountCountry == "00") if (accountCountry.empty() || accountCountry == "00")
sLog->outDebug(LOG_FILTER_NETWORKIO, "[AuthChallenge] Account '%s' is not locked to country", _login.c_str()); sLog->outDebug(LOG_FILTER_NETWORKIO, "[AuthChallenge] Account '%s' is not locked to country", _login.c_str());
else if (!accountCountry.empty()) else if (!accountCountry.empty())
@@ -486,7 +445,7 @@ bool AuthSocket::_HandleLogonChallenge()
// If the account is banned, reject the logon attempt // If the account is banned, reject the logon attempt
stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BANNED); stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BANNED);
stmt->setUInt32(0, fields[1].GetUInt32()); stmt->setUInt32(0, fields[0].GetUInt32());
PreparedQueryResult banresult = LoginDatabase.Query(stmt); PreparedQueryResult banresult = LoginDatabase.Query(stmt);
if (banresult) if (banresult)
{ {
@@ -503,31 +462,7 @@ bool AuthSocket::_HandleLogonChallenge()
} }
else else
{ {
// Get the password from the account table, upper it, and make the SRP6 calculation _srp6.emplace(_login, fields[5].GetBinary<acore::Crypto::SRP6::SALT_LENGTH>(), fields[6].GetBinary<acore::Crypto::SRP6::VERIFIER_LENGTH>());
std::string rI = fields[0].GetString();
// Don't calculate (v, s) if there are already some in the database
std::string databaseV = fields[6].GetString();
std::string databaseS = fields[7].GetString();
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_NETWORKIO, "database authentication values: v='%s' s='%s'", databaseV.c_str(), databaseS.c_str());
#endif
// multiply with 2 since bytes are stored as hexstring
if (databaseV.size() != s_BYTE_SIZE * 2 || databaseS.size() != s_BYTE_SIZE * 2)
_SetVSFields(rI);
else
{
s.SetHexStr(databaseS.c_str());
v.SetHexStr(databaseV.c_str());
}
b.SetRand(19 * 8);
BigNumber gmod = g.ModExp(b, N);
B = ((v * 3) + gmod) % N;
ASSERT(gmod.GetNumBytes() <= 32);
BigNumber unk3; BigNumber unk3;
unk3.SetRand(16 * 8); unk3.SetRand(16 * 8);
@@ -539,17 +474,17 @@ bool AuthSocket::_HandleLogonChallenge()
pkt << uint8(WOW_FAIL_VERSION_INVALID); pkt << uint8(WOW_FAIL_VERSION_INVALID);
// B may be calculated < 32B so we force minimal length to 32B // B may be calculated < 32B so we force minimal length to 32B
pkt.append(B.AsByteArray(32).get(), 32); // 32 bytes pkt.append(_srp6->B);
pkt << uint8(1); pkt << uint8(1);
pkt.append(g.AsByteArray().get(), 1); pkt.append(_srp6->g);
pkt << uint8(32); pkt << uint8(32);
pkt.append(N.AsByteArray(32).get(), 32); pkt.append(_srp6->N);
pkt.append(s.AsByteArray().get(), s.GetNumBytes()); // 32 bytes pkt.append(_srp6->s);
pkt.append(unk3.AsByteArray(16).get(), 16); pkt.append(unk3.ToByteArray<16>());
uint8 securityFlags = 0; uint8 securityFlags = 0;
// Check if token is used // Check if token is used
_tokenKey = fields[8].GetString(); _tokenKey = fields[7].GetString();
if (!_tokenKey.empty()) if (!_tokenKey.empty())
securityFlags = 4; securityFlags = 4;
@@ -573,7 +508,7 @@ bool AuthSocket::_HandleLogonChallenge()
if (securityFlags & 0x04) // Security token input if (securityFlags & 0x04) // Security token input
pkt << uint8(1); pkt << uint8(1);
uint8 secLevel = fields[5].GetUInt8(); uint8 secLevel = fields[4].GetUInt8();
_accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR;
_localizationName.resize(4); _localizationName.resize(4);
@@ -622,107 +557,25 @@ bool AuthSocket::_HandleLogonProof()
return true; return true;
} }
// Continue the SRP6 calculation based on data received from the client if (std::optional<SessionKey> K = _srp6->VerifyChallengeResponse(lp.A, lp.clientM))
BigNumber A;
A.SetBinary(lp.A, 32);
// SRP safeguard: abort if A == 0
if ((A % N).isZero())
{
socket().shutdown();
return true;
}
SHA1Hash sha;
sha.UpdateBigNumbers(&A, &B, nullptr);
sha.Finalize();
BigNumber u;
u.SetBinary(sha.GetDigest(), 20);
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);
for (int i = 0; i < 16; ++i)
t1[i] = t[i * 2];
sha.Initialize();
sha.UpdateData(t1, 16);
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(_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(), 20);
// Check if SRP6 results match (password is correct), else send an error
if (!memcmp(M.AsByteArray().get(), lp.M1, 20))
{ {
_sessionKey = *K;
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_NETWORKIO, "'%s:%d' User '%s' successfully authenticated", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str()); sLog->outDebug(LOG_FILTER_NETWORKIO, "'%s:%d' User '%s' successfully authenticated", socket().getRemoteAddress().c_str(), socket().getRemotePort(), _login.c_str());
#endif #endif
// Update the sessionkey, last_ip, last login time and reset number of failed logins in the account table for this account // 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 // No SQL injection (escaped user name) and IP address as received by socket
const char* K_hex = K.AsHexStr();
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF);
stmt->setString(0, K_hex); stmt->setBinary(0, _sessionKey);
stmt->setString(1, socket().getRemoteAddress().c_str()); stmt->setString(1, socket().getRemoteAddress().c_str());
stmt->setUInt32(2, GetLocaleByName(_localizationName)); stmt->setUInt32(2, GetLocaleByName(_localizationName));
stmt->setString(3, _os); stmt->setString(3, _os);
stmt->setString(4, _login); stmt->setString(4, _login);
LoginDatabase.DirectExecute(stmt); LoginDatabase.DirectExecute(stmt);
OPENSSL_free((void*)K_hex);
// Finish SRP6 and send the final result to the client // Finish SRP6 and send the final result to the client
sha.Initialize(); acore::Crypto::SHA1::Digest M2 = acore::Crypto::SRP6::GetSessionVerifier(lp.A, lp.clientM, _sessionKey);
sha.UpdateBigNumbers(&A, &M, &K, nullptr);
sha.Finalize();
// Check auth token // Check auth token
if ((lp.securityFlags & 0x04) || !_tokenKey.empty()) if ((lp.securityFlags & 0x04) || !_tokenKey.empty())
@@ -746,7 +599,7 @@ bool AuthSocket::_HandleLogonProof()
if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients if (_expversion & POST_BC_EXP_FLAG) // 2.x and 3.x clients
{ {
sAuthLogonProof_S proof; sAuthLogonProof_S proof;
memcpy(proof.M2, sha.GetDigest(), 20); proof.M2 = M2;
proof.cmd = AUTH_LOGON_PROOF; proof.cmd = AUTH_LOGON_PROOF;
proof.error = 0; proof.error = 0;
proof.unk1 = 0x00800000; // Accountflags. 0x01 = GM, 0x08 = Trial, 0x00800000 = Pro pass (arena tournament) proof.unk1 = 0x00800000; // Accountflags. 0x01 = GM, 0x08 = Trial, 0x00800000 = Pro pass (arena tournament)
@@ -757,7 +610,7 @@ bool AuthSocket::_HandleLogonProof()
else else
{ {
sAuthLogonProof_S_Old proof; sAuthLogonProof_S_Old proof;
memcpy(proof.M2, sha.GetDigest(), 20); proof.M2 = M2;
proof.cmd = AUTH_LOGON_PROOF; proof.cmd = AUTH_LOGON_PROOF;
proof.error = 0; proof.error = 0;
proof.unk2 = 0x00; proof.unk2 = 0x00;
@@ -909,7 +762,8 @@ bool AuthSocket::_HandleReconnectChallenge()
uint8 secLevel = fields[2].GetUInt8(); uint8 secLevel = fields[2].GetUInt8();
_accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR; _accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR;
K.SetHexStr ((*result)[0].GetCString()); _sessionKey = fields[0].GetBinary<SESSION_KEY_LENGTH>();
acore::Crypto::GetRandomBytes(_reconnectProof);
///- All good, await client's proof ///- All good, await client's proof
_status = STATUS_RECON_PROOF; _status = STATUS_RECON_PROOF;
@@ -918,8 +772,7 @@ bool AuthSocket::_HandleReconnectChallenge()
ByteBuffer pkt; ByteBuffer pkt;
pkt << uint8(AUTH_RECONNECT_CHALLENGE); pkt << uint8(AUTH_RECONNECT_CHALLENGE);
pkt << uint8(0x00); pkt << uint8(0x00);
_reconnectProof.SetRand(16 * 8); pkt.append(_reconnectProof); // 16 bytes random
pkt.append(_reconnectProof.AsByteArray(16).get(), 16); // 16 bytes random
pkt << uint64(0x00) << uint64(0x00); // 16 bytes zeros pkt << uint64(0x00) << uint64(0x00); // 16 bytes zeros
socket().send((char const*)pkt.contents(), pkt.size()); socket().send((char const*)pkt.contents(), pkt.size());
return true; return true;
@@ -938,19 +791,20 @@ bool AuthSocket::_HandleReconnectProof()
_status = STATUS_CLOSED; _status = STATUS_CLOSED;
if (_login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes()) if (_login.empty())
return false; return false;
BigNumber t1; BigNumber t1;
t1.SetBinary(lp.R1, 16); t1.SetBinary(lp.R1, 16);
SHA1Hash sha; acore::Crypto::SHA1 sha;
sha.Initialize();
sha.UpdateData(_login); sha.UpdateData(_login);
sha.UpdateBigNumbers(&t1, &_reconnectProof, &K, nullptr); sha.UpdateData(t1.ToByteArray<16>());
sha.UpdateData(_reconnectProof);
sha.UpdateData(_sessionKey);
sha.Finalize(); sha.Finalize();
if (!memcmp(sha.GetDigest(), lp.R2, SHA_DIGEST_LENGTH)) if (sha.GetDigest() == lp.R2)
{ {
// Sending response // Sending response
ByteBuffer pkt; ByteBuffer pkt;
+5 -7
View File
@@ -8,8 +8,9 @@
#define _AUTHSOCKET_H #define _AUTHSOCKET_H
#include "Common.h" #include "Common.h"
#include "BigNumber.h" #include "CryptoHash.h"
#include "RealmSocket.h" #include "RealmSocket.h"
#include "SRP6.h"
class ACE_INET_Addr; class ACE_INET_Addr;
struct Realm; struct Realm;
@@ -50,8 +51,6 @@ public:
bool _HandleXferCancel(); bool _HandleXferCancel();
bool _HandleXferAccept(); bool _HandleXferAccept();
void _SetVSFields(const std::string& rI);
FILE* pPatch; FILE* pPatch;
ACE_Thread_Mutex patcherLock; ACE_Thread_Mutex patcherLock;
@@ -59,10 +58,9 @@ private:
RealmSocket& socket_; RealmSocket& socket_;
RealmSocket& socket() { return socket_; } RealmSocket& socket() { return socket_; }
BigNumber N, s, g, v; std::optional<acore::Crypto::SRP6> _srp6;
BigNumber b, B; SessionKey _sessionKey = {};
BigNumber K; std::array<uint8, 16> _reconnectProof = {};
BigNumber _reconnectProof;
eStatus _status; eStatus _status;
+27 -26
View File
@@ -5,11 +5,12 @@
*/ */
#include "AccountMgr.h" #include "AccountMgr.h"
#include "CryptoHash.h"
#include "DatabaseEnv.h" #include "DatabaseEnv.h"
#include "ObjectAccessor.h" #include "ObjectAccessor.h"
#include "Player.h" #include "Player.h"
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include "SHA1.h" #include "SRP6.h"
#include "Util.h" #include "Util.h"
#include "WorldSession.h" #include "WorldSession.h"
@@ -28,13 +29,15 @@ namespace AccountMgr
Utf8ToUpperOnlyLatin(password); Utf8ToUpperOnlyLatin(password);
if (GetId(username)) if (GetId(username))
return AOR_NAME_ALREDY_EXIST; // username does already exist return AOR_NAME_ALREADY_EXIST; // username does already exist
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT);
stmt->setString(0, username); stmt->setString(0, username);
stmt->setString(1, CalculateShaPassHash(username, password)); auto [salt, verifier] = acore::Crypto::SRP6::MakeRegistrationData(username, password);
stmt->setInt8(2, uint8(sWorld->getIntConfig(CONFIG_EXPANSION))); stmt->setBinary(1, salt);
stmt->setBinary(2, verifier);
stmt->setInt8(3, uint8(sWorld->getIntConfig(CONFIG_EXPANSION)));
LoginDatabase.Execute(stmt); LoginDatabase.Execute(stmt);
@@ -141,11 +144,15 @@ namespace AccountMgr
Utf8ToUpperOnlyLatin(newPassword); Utf8ToUpperOnlyLatin(newPassword);
stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_USERNAME); stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_USERNAME);
stmt->setString(0, newUsername); stmt->setString(0, newUsername);
stmt->setString(1, CalculateShaPassHash(newUsername, newPassword)); stmt->setUInt32(1, accountId);
stmt->setUInt32(2, accountId); LoginDatabase.Execute(stmt);
auto [salt, verifier] = acore::Crypto::SRP6::MakeRegistrationData(newUsername, newPassword);
stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGON);
stmt->setBinary(0, salt);
stmt->setBinary(1, verifier);
stmt->setUInt32(2, accountId);
LoginDatabase.Execute(stmt); LoginDatabase.Execute(stmt);
return AOR_OK; return AOR_OK;
@@ -170,11 +177,12 @@ namespace AccountMgr
Utf8ToUpperOnlyLatin(username); Utf8ToUpperOnlyLatin(username);
Utf8ToUpperOnlyLatin(newPassword); Utf8ToUpperOnlyLatin(newPassword);
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_PASSWORD); auto [salt, verifier] = acore::Crypto::SRP6::MakeRegistrationData(username, newPassword);
stmt->setString(0, CalculateShaPassHash(username, newPassword));
stmt->setUInt32(1, accountId);
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGON);
stmt->setBinary(0, salt);
stmt->setBinary(1, verifier);
stmt->setUInt32(2, accountId);;
LoginDatabase.Execute(stmt); LoginDatabase.Execute(stmt);
sScriptMgr->OnPasswordChange(accountId); sScriptMgr->OnPasswordChange(accountId);
@@ -236,10 +244,15 @@ namespace AccountMgr
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD);
stmt->setUInt32(0, accountId); stmt->setUInt32(0, accountId);
stmt->setString(1, CalculateShaPassHash(username, password)); if (PreparedQueryResult result = LoginDatabase.Query(stmt))
PreparedQueryResult result = LoginDatabase.Query(stmt); {
acore::Crypto::SRP6::Salt salt = (*result)[0].GetBinary<acore::Crypto::SRP6::SALT_LENGTH>();
acore::Crypto::SRP6::Verifier verifier = (*result)[1].GetBinary<acore::Crypto::SRP6::VERIFIER_LENGTH>();
if (acore::Crypto::SRP6::CheckLogin(username, password, salt, verifier))
return true;
}
return !!result; return false;
} }
uint32 GetCharactersCount(uint32 accountId) uint32 GetCharactersCount(uint32 accountId)
@@ -252,18 +265,6 @@ namespace AccountMgr
return (result) ? (*result)[0].GetUInt64() : 0; return (result) ? (*result)[0].GetUInt64() : 0;
} }
std::string 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());
}
bool IsPlayerAccount(uint32 gmlevel) bool IsPlayerAccount(uint32 gmlevel)
{ {
return gmlevel == SEC_PLAYER; return gmlevel == SEC_PLAYER;
+1 -2
View File
@@ -15,7 +15,7 @@ enum AccountOpResult
AOR_OK, AOR_OK,
AOR_NAME_TOO_LONG, AOR_NAME_TOO_LONG,
AOR_PASS_TOO_LONG, AOR_PASS_TOO_LONG,
AOR_NAME_ALREDY_EXIST, AOR_NAME_ALREADY_EXIST,
AOR_NAME_NOT_EXIST, AOR_NAME_NOT_EXIST,
AOR_DB_INTERNAL_ERROR AOR_DB_INTERNAL_ERROR
}; };
@@ -36,7 +36,6 @@ namespace AccountMgr
uint32 GetSecurity(uint32 accountId, int32 realmId); uint32 GetSecurity(uint32 accountId, int32 realmId);
bool GetName(uint32 accountId, std::string& name); bool GetName(uint32 accountId, std::string& name);
uint32 GetCharactersCount(uint32 accountId); uint32 GetCharactersCount(uint32 accountId);
std::string CalculateShaPassHash(std::string const& name, std::string const& password);
bool IsPlayerAccount(uint32 gmlevel); bool IsPlayerAccount(uint32 gmlevel);
bool IsGMAccount(uint32 gmlevel); bool IsGMAccount(uint32 gmlevel);
+2 -2
View File
@@ -1740,7 +1740,7 @@ void Guild::HandleMemberDepositMoney(WorldSession* session, uint32 amount)
CharacterDatabase.CommitTransaction(trans); CharacterDatabase.CommitTransaction(trans);
std::string aux = ByteArrayToHexStr(reinterpret_cast<uint8*>(&m_bankMoney), 8, true); std::string aux = acore::Impl::ByteArrayToHexStr(reinterpret_cast<uint8*>(&m_bankMoney), 8, true);
_BroadcastEvent(GE_BANK_MONEY_SET, 0, aux.c_str()); _BroadcastEvent(GE_BANK_MONEY_SET, 0, aux.c_str());
if (amount > 10 * GOLD) if (amount > 10 * GOLD)
@@ -1789,7 +1789,7 @@ bool Guild::HandleMemberWithdrawMoney(WorldSession* session, uint32 amount, bool
if (amount > 10 * GOLD) if (amount > 10 * GOLD)
CharacterDatabase.PExecute("INSERT INTO log_money VALUES(%u, %u, \"%s\", \"%s\", %u, \"%s\", %u, \"<GB WITHDRAW> %s (guild id: %u, members: %u, new amount: %u, leader guid low: %u, char level: %u)\", NOW())", session->GetAccountId(), player->GetGUIDLow(), player->GetName().c_str(), session->GetRemoteAddress().c_str(), 0, "", amount, GetName().c_str(), GetId(), GetMemberCount(), GetTotalBankMoney(), (uint32)(GetLeaderGUID() & 0xFFFFFFFF), player->getLevel()); CharacterDatabase.PExecute("INSERT INTO log_money VALUES(%u, %u, \"%s\", \"%s\", %u, \"%s\", %u, \"<GB WITHDRAW> %s (guild id: %u, members: %u, new amount: %u, leader guid low: %u, char level: %u)\", NOW())", session->GetAccountId(), player->GetGUIDLow(), player->GetName().c_str(), session->GetRemoteAddress().c_str(), 0, "", amount, GetName().c_str(), GetId(), GetMemberCount(), GetTotalBankMoney(), (uint32)(GetLeaderGUID() & 0xFFFFFFFF), player->getLevel());
std::string aux = ByteArrayToHexStr(reinterpret_cast<uint8*>(&m_bankMoney), 8, true); std::string aux = acore::Impl::ByteArrayToHexStr(reinterpret_cast<uint8*>(&m_bankMoney), 8, true);
_BroadcastEvent(GE_BANK_MONEY_SET, 0, aux.c_str()); _BroadcastEvent(GE_BANK_MONEY_SET, 0, aux.c_str());
return true; return true;
} }
-1
View File
@@ -32,7 +32,6 @@
#include "Pet.h" #include "Pet.h"
#include "Player.h" #include "Player.h"
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include "SHA1.h"
#include "SocialMgr.h" #include "SocialMgr.h"
#include "Spell.h" #include "Spell.h"
#include "UpdateData.h" #include "UpdateData.h"
+1 -1
View File
@@ -1331,7 +1331,7 @@ void WorldSession::ProcessQueryCallbackLogin()
} }
} }
void WorldSession::InitWarden(BigNumber* k, std::string const& os) void WorldSession::InitWarden(SessionKey const& k, std::string const& os)
{ {
if (os == "Win") if (os == "Win")
{ {
+2 -2
View File
@@ -12,10 +12,10 @@
#define __WORLDSESSION_H #define __WORLDSESSION_H
#include "AccountMgr.h" #include "AccountMgr.h"
#include "AuthDefines.h"
#include "AddonMgr.h" #include "AddonMgr.h"
#include "BanManager.h" #include "BanManager.h"
#include "Common.h" #include "Common.h"
#include "Cryptography/BigNumber.h"
#include "DatabaseEnv.h" #include "DatabaseEnv.h"
#include "GossipDef.h" #include "GossipDef.h"
#include "Opcodes.h" #include "Opcodes.h"
@@ -239,7 +239,7 @@ public:
void SetTotalTime(uint32 TotalTime) { m_total_time = TotalTime; } void SetTotalTime(uint32 TotalTime) { m_total_time = TotalTime; }
uint32 GetTotalTime() const { return m_total_time; } uint32 GetTotalTime() const { return m_total_time; }
void InitWarden(BigNumber* k, std::string const& os); void InitWarden(SessionKey const&, std::string const& os);
/// Session in auth.queue currently /// Session in auth.queue currently
void SetInQueue(bool state) { m_inQueue = state; } void SetInQueue(bool state) { m_inQueue = state; }
+26 -30
View File
@@ -8,13 +8,14 @@
#include "BigNumber.h" #include "BigNumber.h"
#include "ByteBuffer.h" #include "ByteBuffer.h"
#include "Common.h" #include "Common.h"
#include "CryptoHash.h"
#include "CryptoRandom.h"
#include "DatabaseEnv.h" #include "DatabaseEnv.h"
#include "Log.h" #include "Log.h"
#include "Opcodes.h" #include "Opcodes.h"
#include "PacketLog.h" #include "PacketLog.h"
#include "Player.h" #include "Player.h"
#include "ScriptMgr.h" #include "ScriptMgr.h"
#include "SHA1.h"
#include "SharedDefines.h" #include "SharedDefines.h"
#include "Util.h" #include "Util.h"
#include "World.h" #include "World.h"
@@ -92,9 +93,10 @@ struct ClientPktHeader
WorldSocket::WorldSocket(void): WorldHandler(), WorldSocket::WorldSocket(void): WorldHandler(),
m_LastPingTime(SystemTimePoint::min()), m_OverSpeedPings(0), m_Session(0), m_LastPingTime(SystemTimePoint::min()), m_OverSpeedPings(0), m_Session(0),
m_RecvWPct(0), m_RecvPct(), m_Header(sizeof (ClientPktHeader)), m_RecvWPct(0), m_RecvPct(), m_Header(sizeof (ClientPktHeader)),
m_OutBuffer(0), m_OutBufferSize(65536), m_OutActive(false), m_OutBuffer(0), m_OutBufferSize(65536), m_OutActive(false)
m_Seed(static_cast<uint32> (rand32()))
{ {
acore::Crypto::GetRandomBytes(m_Seed);
reference_counting_policy().value (ACE_Event_Handler::Reference_Counting_Policy::ENABLED); reference_counting_policy().value (ACE_Event_Handler::Reference_Counting_Policy::ENABLED);
msg_queue()->high_water_mark(8 * 1024 * 1024); msg_queue()->high_water_mark(8 * 1024 * 1024);
@@ -157,7 +159,9 @@ int WorldSocket::SendPacket(WorldPacket const& pct)
sPacketLog->LogPacket(pct, SERVER_TO_CLIENT); sPacketLog->LogPacket(pct, SERVER_TO_CLIENT);
ServerPktHeader header(pct.size() + 2, pct.GetOpcode()); ServerPktHeader header(pct.size() + 2, pct.GetOpcode());
m_Crypt.EncryptSend ((uint8*)header.header, header.getHeaderLength());
if (m_Crypt.IsInitialized())
m_Crypt.EncryptSend((uint8*)header.header, header.getHeaderLength());
if (m_OutBuffer->space() >= pct.size() + header.getHeaderLength() && msg_queue()->is_empty()) if (m_OutBuffer->space() >= pct.size() + header.getHeaderLength() && msg_queue()->is_empty())
{ {
@@ -235,15 +239,8 @@ int WorldSocket::open(void* a)
// Send startup packet. // Send startup packet.
WorldPacket packet (SMSG_AUTH_CHALLENGE, 24); WorldPacket packet (SMSG_AUTH_CHALLENGE, 24);
packet << uint32(1); // 1...31 packet << uint32(1); // 1...31
packet << m_Seed; packet.append(m_Seed);
packet.append(acore::Crypto::GetRandomBytes<32>()); // new encryption seeds
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
if (SendPacket(packet) == -1) if (SendPacket(packet) == -1)
return -1; return -1;
@@ -470,7 +467,8 @@ int WorldSocket::handle_input_header(void)
ACE_ASSERT (m_Header.length() == sizeof(ClientPktHeader)); ACE_ASSERT (m_Header.length() == sizeof(ClientPktHeader));
m_Crypt.DecryptRecv ((uint8*) m_Header.rd_ptr(), sizeof(ClientPktHeader)); if (m_Crypt.IsInitialized())
m_Crypt.DecryptRecv((uint8*) m_Header.rd_ptr(), sizeof(ClientPktHeader));
ClientPktHeader& header = *((ClientPktHeader*) m_Header.rd_ptr()); ClientPktHeader& header = *((ClientPktHeader*) m_Header.rd_ptr());
@@ -736,8 +734,6 @@ int WorldSocket::ProcessIncoming(WorldPacket* new_pct)
int WorldSocket::HandleAuthSession(WorldPacket& recvPacket) int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
{ {
// NOTE: ATM the socket is singlethread, have this in mind ... // NOTE: ATM the socket is singlethread, have this in mind ...
uint8 digest[20];
uint32 clientSeed;
uint32 loginServerID, loginServerType, regionID, battlegroupID, realm; uint32 loginServerID, loginServerType, regionID, battlegroupID, realm;
uint64 DosResponse; uint64 DosResponse;
uint32 BuiltNumberClient; uint32 BuiltNumberClient;
@@ -747,10 +743,10 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
//uint8 expansion = 0; //uint8 expansion = 0;
LocaleConstant locale; LocaleConstant locale;
std::string account; std::string account;
SHA1Hash sha;
WorldPacket packet, SendAddonPacked; WorldPacket packet, SendAddonPacked;
std::array<uint8, 4> clientSeed;
acore::Crypto::SHA1::Digest digest;
BigNumber k;
bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED); bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED);
if (sWorld->IsClosed()) if (sWorld->IsClosed())
@@ -768,12 +764,12 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
recvPacket >> loginServerID; recvPacket >> loginServerID;
recvPacket >> account; recvPacket >> account;
recvPacket >> loginServerType; recvPacket >> loginServerType;
recvPacket >> clientSeed; recvPacket.read(clientSeed);
recvPacket >> regionID; recvPacket >> regionID;
recvPacket >> battlegroupID; recvPacket >> battlegroupID;
recvPacket >> realm; recvPacket >> realm;
recvPacket >> DosResponse; recvPacket >> DosResponse;
recvPacket.read(digest, 20); recvPacket.read(digest);
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outStaticDebug ("WorldSocket::HandleAuthSession: client %u, loginServerID %u, account %s, loginServerType %u, clientseed %u", BuiltNumberClient, loginServerID, account.c_str(), loginServerType, clientSeed); sLog->outStaticDebug ("WorldSocket::HandleAuthSession: client %u, loginServerID %u, account %s, loginServerType %u, clientseed %u", BuiltNumberClient, loginServerID, account.c_str(), loginServerType, clientSeed);
@@ -843,7 +839,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
security = SEC_ADMINISTRATOR; security = SEC_ADMINISTRATOR;
*/ */
k.SetHexStr (fields[1].GetCString()); SessionKey sessionKey = fields[1].GetBinary<SESSION_KEY_LENGTH>();
int64 mutetime = fields[6].GetInt64(); int64 mutetime = fields[6].GetInt64();
//! Negative mutetime indicates amount of seconds to be muted effective on next login - which is now. //! Negative mutetime indicates amount of seconds to be muted effective on next login - which is now.
@@ -934,17 +930,17 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
} }
// Check that Key and account name are the same on client and server // Check that Key and account name are the same on client and server
uint32 t = 0; uint8 t[4] = { 0x00, 0x00, 0x00, 0x00 };
uint32 seed = m_Seed;
acore::Crypto::SHA1 sha;
sha.UpdateData (account); sha.UpdateData (account);
sha.UpdateData ((uint8*) & t, 4); sha.UpdateData(t);
sha.UpdateData ((uint8*) & clientSeed, 4); sha.UpdateData(clientSeed);
sha.UpdateData ((uint8*) & seed, 4); sha.UpdateData(m_Seed);
sha.UpdateBigNumbers (&k, nullptr); sha.UpdateData(sessionKey);
sha.Finalize(); sha.Finalize();
if (memcmp (sha.GetDigest(), digest, 20)) if (sha.GetDigest() != digest)
{ {
packet.Initialize (SMSG_AUTH_RESPONSE, 1); packet.Initialize (SMSG_AUTH_RESPONSE, 1);
packet << uint8 (AUTH_FAILED); packet << uint8 (AUTH_FAILED);
@@ -984,7 +980,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
// NOTE ATM the socket is single-threaded, have this in mind ... // NOTE ATM the socket is single-threaded, have this in mind ...
ACE_NEW_RETURN(m_Session, WorldSession(id, this, AccountTypes(security), expansion, mutetime, locale, recruiter, isRecruiter, skipQueue, TotalTime), -1); ACE_NEW_RETURN(m_Session, WorldSession(id, this, AccountTypes(security), expansion, mutetime, locale, recruiter, isRecruiter, skipQueue, TotalTime), -1);
m_Crypt.Init(&k); m_Crypt.Init(sessionKey);
// First reject the connection if packet contains invalid data or realm state doesn't allow logging in // First reject the connection if packet contains invalid data or realm state doesn't allow logging in
if (sWorld->IsClosed()) if (sWorld->IsClosed())
@@ -1019,7 +1015,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
// Initialize Warden system only if it is enabled by config // Initialize Warden system only if it is enabled by config
if (wardenActive) if (wardenActive)
m_Session->InitWarden(&k, os); m_Session->InitWarden(sessionKey, os);
// Sleep this Network thread for // Sleep this Network thread for
uint32 sleepTime = sWorld->getIntConfig(CONFIG_SESSION_ADD_DELAY); uint32 sleepTime = sWorld->getIntConfig(CONFIG_SESSION_ADD_DELAY);
+1 -1
View File
@@ -189,7 +189,7 @@ private:
/// True if the socket is registered with the reactor for output /// True if the socket is registered with the reactor for output
bool m_OutActive; bool m_OutActive;
uint32 m_Seed; std::array<uint8, 4> m_Seed;
}; };
#endif /* _WORLDSOCKET_H */ #endif /* _WORLDSOCKET_H */
+3 -3
View File
@@ -20,7 +20,7 @@
#include <openssl/md5.h> #include <openssl/md5.h>
#include <openssl/sha.h> #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), _module(nullptr), _initialized(false) _dataSent(false), _module(nullptr), _initialized(false)
{ {
memset(_inputKey, 0, sizeof(_inputKey)); memset(_inputKey, 0, sizeof(_inputKey));
@@ -125,12 +125,12 @@ void Warden::Update(uint32 const diff)
void Warden::DecryptData(uint8* buffer, uint32 length) void Warden::DecryptData(uint8* buffer, uint32 length)
{ {
_inputCrypto.UpdateData(length, buffer); _inputCrypto.UpdateData(buffer, length);
} }
void Warden::EncryptData(uint8* buffer, uint32 length) void Warden::EncryptData(uint8* buffer, uint32 length)
{ {
_outputCrypto.UpdateData(length, buffer); _outputCrypto.UpdateData(buffer, length);
} }
bool Warden::IsValidCheckSum(uint32 checksum, const uint8* data, const uint16 length) bool Warden::IsValidCheckSum(uint32 checksum, const uint8* data, const uint16 length)
+6 -6
View File
@@ -7,11 +7,11 @@
#ifndef _WARDEN_BASE_H #ifndef _WARDEN_BASE_H
#define _WARDEN_BASE_H #define _WARDEN_BASE_H
#include "ARC4.h"
#include "AuthDefines.h"
#include "ByteBuffer.h" #include "ByteBuffer.h"
#include "Cryptography/ARC4.h"
#include "Cryptography/BigNumber.h"
#include "WardenCheckMgr.h" #include "WardenCheckMgr.h"
#include <map> #include <array>
enum WardenOpcodes enum WardenOpcodes
{ {
@@ -97,7 +97,7 @@ public:
Warden(); Warden();
virtual ~Warden(); virtual ~Warden();
virtual void Init(WorldSession* session, BigNumber* k) = 0; virtual void Init(WorldSession* session, SessionKey const& k) = 0;
virtual ClientWardenModule* GetModuleForClient() = 0; virtual ClientWardenModule* GetModuleForClient() = 0;
virtual void InitializeModule() = 0; virtual void InitializeModule() = 0;
virtual void RequestHash() = 0; virtual void RequestHash() = 0;
@@ -123,8 +123,8 @@ private:
uint8 _inputKey[16]; uint8 _inputKey[16];
uint8 _outputKey[16]; uint8 _outputKey[16];
uint8 _seed[16]; uint8 _seed[16];
ARC4 _inputCrypto; acore::Crypto::ARC4 _inputCrypto;
ARC4 _outputCrypto; acore::Crypto::ARC4 _outputCrypto;
uint32 _checkTimer; // Timer for sending check requests uint32 _checkTimer; // Timer for sending check requests
uint32 _clientResponseTimer; // Timer for client response delay uint32 _clientResponseTimer; // Timer for client response delay
bool _dataSent; bool _dataSent;
-22
View File
@@ -103,16 +103,6 @@ void WardenCheckMgr::LoadWardenChecks()
{ {
WardenCheckResult wr; WardenCheckResult wr;
wr.Result.SetHexStr(checkResult.c_str()); wr.Result.SetHexStr(checkResult.c_str());
int len = static_cast<int>(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; CheckResultStore[id] = wr;
} }
@@ -148,19 +138,7 @@ void WardenCheckMgr::LoadWardenChecks()
default: default:
{ {
if (checkType == PAGE_CHECK_A || checkType == PAGE_CHECK_B || checkType == DRIVER_CHECK) if (checkType == PAGE_CHECK_A || checkType == PAGE_CHECK_B || checkType == DRIVER_CHECK)
{
wardenCheck.Data.SetHexStr(data.c_str()); wardenCheck.Data.SetHexStr(data.c_str());
int len = static_cast<int>(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);
}
}
CheckIdPool[WARDEN_CHECK_OTHER_TYPE].push_back(id); CheckIdPool[WARDEN_CHECK_OTHER_TYPE].push_back(id);
break; break;
+14 -14
View File
@@ -6,10 +6,10 @@
#include "ByteBuffer.h" #include "ByteBuffer.h"
#include "Common.h" #include "Common.h"
#include "WardenKeyGeneration.h"
#include "Log.h" #include "Log.h"
#include "Opcodes.h" #include "Opcodes.h"
#include "Player.h" #include "Player.h"
#include "SessionKeyGenerator.h"
#include "Util.h" #include "Util.h"
#include "WardenMac.h" #include "WardenMac.h"
#include "WardenModuleMac.h" #include "WardenModuleMac.h"
@@ -26,11 +26,11 @@ WardenMac::~WardenMac()
{ {
} }
void WardenMac::Init(WorldSession* pClient, BigNumber* K) void WardenMac::Init(WorldSession* pClient, SessionKey const& K)
{ {
_session = pClient; _session = pClient;
// Generate Warden Key // Generate Warden Key
SHA1Randx WK(K->AsByteArray().get(), K->GetNumBytes()); SessionKeyGenerator<acore::Crypto::SHA1> WK(K);
WK.Generate(_inputKey, 16); WK.Generate(_inputKey, 16);
WK.Generate(_outputKey, 16); WK.Generate(_outputKey, 16);
/* /*
@@ -48,17 +48,17 @@ void WardenMac::Init(WorldSession* pClient, BigNumber* K)
_outputCrypto.Init(_outputKey); _outputCrypto.Init(_outputKey);
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "Server side warden for client %u initializing...", pClient->GetAccountId()); sLog->outDebug(LOG_FILTER_WARDEN, "Server side warden for client %u initializing...", pClient->GetAccountId());
sLog->outDebug(LOG_FILTER_WARDEN, "C->S Key: %s", ByteArrayToHexStr(_inputKey, 16).c_str()); sLog->outDebug(LOG_FILTER_WARDEN, "C->S Key: %s", acore::Impl::ByteArrayToHexStr(_inputKey).c_str());
sLog->outDebug(LOG_FILTER_WARDEN, "S->C Key: %s", ByteArrayToHexStr(_outputKey, 16).c_str()); sLog->outDebug(LOG_FILTER_WARDEN, "S->C Key: %s", acore::Impl::ByteArrayToHexStr(_outputKey).c_str());
sLog->outDebug(LOG_FILTER_WARDEN, " Seed: %s", ByteArrayToHexStr(_seed, 16).c_str()); sLog->outDebug(LOG_FILTER_WARDEN, " Seed: %s", acore::Impl::ByteArrayToHexStr(_seed).c_str());
sLog->outDebug(LOG_FILTER_WARDEN, "Loading Module..."); sLog->outDebug(LOG_FILTER_WARDEN, "Loading Module...");
#endif #endif
_module = GetModuleForClient(); _module = GetModuleForClient();
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "Module Key: %s", ByteArrayToHexStr(_module->Key, 16).c_str()); sLog->outDebug(LOG_FILTER_WARDEN, "Module Key: %s", acore::Impl::ByteArrayToHexStr(_module->Key).c_str());
sLog->outDebug(LOG_FILTER_WARDEN, "Module ID: %s", ByteArrayToHexStr(_module->Id, 16).c_str()); sLog->outDebug(LOG_FILTER_WARDEN, "Module ID: %s", acore::Impl::ByteArrayToHexStr(_module->Id).c_str());
#endif #endif
RequestModule(); RequestModule();
} }
@@ -154,14 +154,14 @@ void WardenMac::HandleHashResult(ByteBuffer& buff)
buff.rpos(buff.wpos()); buff.rpos(buff.wpos());
SHA1Hash sha1; acore::Crypto::SHA1 sha1;
sha1.UpdateData((uint8*)keyIn, 16); sha1.UpdateData((uint8*)keyIn, 16);
sha1.Finalize(); 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 }; //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 // Verify key
if (memcmp(buff.contents() + 1, sha1.GetDigest(), 20) != 0) if (memcmp(buff.contents() + 1, sha1.GetDigest().data(), 20) != 0)
{ {
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "Request hash reply: failed"); sLog->outDebug(LOG_FILTER_WARDEN, "Request hash reply: failed");
@@ -242,16 +242,16 @@ void WardenMac::HandleData(ByteBuffer& buff)
std::string str = "Test string!"; std::string str = "Test string!";
SHA1Hash sha1; acore::Crypto::SHA1 sha1;
sha1.UpdateData(str); sha1.UpdateData(str);
uint32 magic = 0xFEEDFACE; // unsure uint32 magic = 0xFEEDFACE; // unsure
sha1.UpdateData((uint8*)&magic, 4); sha1.UpdateData((uint8*)&magic, 4);
sha1.Finalize(); sha1.Finalize();
uint8 sha1Hash[20]; std::array<uint8, acore::Crypto::SHA1::DIGEST_LENGTH> sha1Hash;
buff.read(sha1Hash, 20); buff.read(sha1Hash.data(), sha1Hash.size());
if (memcmp(sha1Hash, sha1.GetDigest(), 20)) if (sha1Hash != sha1.GetDigest())
{ {
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "Handle data failed: SHA1 hash is wrong!"); sLog->outDebug(LOG_FILTER_WARDEN, "Handle data failed: SHA1 hash is wrong!");
+1 -2
View File
@@ -9,7 +9,6 @@
#include "ByteBuffer.h" #include "ByteBuffer.h"
#include "ARC4.h" #include "ARC4.h"
#include "BigNumber.h"
#include "Warden.h" #include "Warden.h"
#include <map> #include <map>
@@ -22,7 +21,7 @@ public:
WardenMac(); WardenMac();
~WardenMac() override; ~WardenMac() override;
void Init(WorldSession* session, BigNumber* k) override; void Init(WorldSession* session, SessionKey const& k) override;
ClientWardenModule* GetModuleForClient() override; ClientWardenModule* GetModuleForClient() override;
void InitializeModule() override; void InitializeModule() override;
void RequestHash() override; void RequestHash() override;
+26 -28
View File
@@ -7,12 +7,13 @@
#include "AccountMgr.h" #include "AccountMgr.h"
#include "ByteBuffer.h" #include "ByteBuffer.h"
#include "Common.h" #include "Common.h"
#include "Cryptography/HMACSHA1.h" #include "CryptoRandom.h"
#include "Cryptography/WardenKeyGeneration.h"
#include "Database/DatabaseEnv.h" #include "Database/DatabaseEnv.h"
#include "HMAC.h"
#include "Log.h" #include "Log.h"
#include "Opcodes.h" #include "Opcodes.h"
#include "Player.h" #include "Player.h"
#include "SessionKeyGenerator.h"
#include "Util.h" #include "Util.h"
#include "WardenCheckMgr.h" #include "WardenCheckMgr.h"
#include "WardenModuleWin.h" #include "WardenModuleWin.h"
@@ -38,7 +39,7 @@ static constexpr uint8 GetCheckPacketBaseSize(uint8 type)
case LUA_EVAL_CHECK: return 1 + sizeof(_luaEvalPrefix) - 1 + sizeof(_luaEvalMidfix) - 1 + 4 + sizeof(_luaEvalPostfix) - 1; case LUA_EVAL_CHECK: return 1 + sizeof(_luaEvalPrefix) - 1 + sizeof(_luaEvalMidfix) - 1 + 4 + sizeof(_luaEvalPostfix) - 1;
case PAGE_CHECK_A: return (4 + 1); case PAGE_CHECK_A: return (4 + 1);
case PAGE_CHECK_B: return (4 + 1); case PAGE_CHECK_B: return (4 + 1);
case MODULE_CHECK: return (4 + SHA_DIGEST_LENGTH); case MODULE_CHECK: return (4 + acore::Crypto::Constants::SHA1_DIGEST_LENGTH_BYTES);
case MEM_CHECK: return (1 + 4 + 1); case MEM_CHECK: return (1 + 4 + 1);
default: return 0; default: return 0;
} }
@@ -90,11 +91,11 @@ WardenWin::~WardenWin()
{ {
} }
void WardenWin::Init(WorldSession* session, BigNumber* k) void WardenWin::Init(WorldSession* session, SessionKey const& k)
{ {
_session = session; _session = session;
// Generate Warden Key // Generate Warden Key
SHA1Randx WK(k->AsByteArray().get(), k->GetNumBytes()); SessionKeyGenerator<acore::Crypto::SHA1> WK(k);
WK.Generate(_inputKey, 16); WK.Generate(_inputKey, 16);
WK.Generate(_outputKey, 16); WK.Generate(_outputKey, 16);
@@ -104,17 +105,17 @@ void WardenWin::Init(WorldSession* session, BigNumber* k)
_outputCrypto.Init(_outputKey); _outputCrypto.Init(_outputKey);
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "Server side warden for client %u initializing...", session->GetAccountId()); sLog->outDebug(LOG_FILTER_WARDEN, "Server side warden for client %u initializing...", session->GetAccountId());
sLog->outDebug(LOG_FILTER_WARDEN, "C->S Key: %s", ByteArrayToHexStr(_inputKey, 16).c_str()); sLog->outDebug(LOG_FILTER_WARDEN, "C->S Key: %s", acore::Impl::ByteArrayToHexStr(_inputKey).c_str());
sLog->outDebug(LOG_FILTER_WARDEN, "S->C Key: %s", ByteArrayToHexStr(_outputKey, 16).c_str()); sLog->outDebug(LOG_FILTER_WARDEN, "S->C Key: %s", acore::Impl::ByteArrayToHexStr(_outputKey).c_str());
sLog->outDebug(LOG_FILTER_WARDEN, " Seed: %s", ByteArrayToHexStr(_seed, 16).c_str()); sLog->outDebug(LOG_FILTER_WARDEN, " Seed: %s", acore::Impl::ByteArrayToHexStr(_seed).c_str());
sLog->outDebug(LOG_FILTER_WARDEN, "Loading Module..."); sLog->outDebug(LOG_FILTER_WARDEN, "Loading Module...");
#endif #endif
_module = GetModuleForClient(); _module = GetModuleForClient();
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "Module Key: %s", ByteArrayToHexStr(_module->Key, 16).c_str()); sLog->outDebug(LOG_FILTER_WARDEN, "Module Key: %s", acore::Impl::ByteArrayToHexStr(_module->Key).c_str());
sLog->outDebug(LOG_FILTER_WARDEN, "Module ID: %s", ByteArrayToHexStr(_module->Id, 16).c_str()); sLog->outDebug(LOG_FILTER_WARDEN, "Module ID: %s", acore::Impl::ByteArrayToHexStr(_module->Id).c_str());
#endif #endif
RequestModule(); RequestModule();
} }
@@ -158,7 +159,7 @@ void WardenWin::InitializeModule()
Request.Function1[1] = 0x000218C0; // 0x00400000 + 0x000218C0 SFileGetFileSize Request.Function1[1] = 0x000218C0; // 0x00400000 + 0x000218C0 SFileGetFileSize
Request.Function1[2] = 0x00022530; // 0x00400000 + 0x00022530 SFileReadFile Request.Function1[2] = 0x00022530; // 0x00400000 + 0x00022530 SFileReadFile
Request.Function1[3] = 0x00022910; // 0x00400000 + 0x00022910 SFileCloseFile Request.Function1[3] = 0x00022910; // 0x00400000 + 0x00022910 SFileCloseFile
Request.CheckSumm1 = BuildChecksum(&Request.Unk1, SHA_DIGEST_LENGTH); Request.CheckSumm1 = BuildChecksum(&Request.Unk1, acore::Crypto::Constants::SHA1_DIGEST_LENGTH_BYTES);
Request.Command2 = WARDEN_SMSG_MODULE_INITIALIZE; Request.Command2 = WARDEN_SMSG_MODULE_INITIALIZE;
Request.Size2 = 8; Request.Size2 = 8;
@@ -223,7 +224,7 @@ void WardenWin::HandleHashResult(ByteBuffer& buff)
buff.rpos(buff.wpos()); buff.rpos(buff.wpos());
// Verify key // Verify key
if (memcmp(buff.contents() + 1, Module.ClientKeySeedHash, SHA_DIGEST_LENGTH) != 0) if (memcmp(buff.contents() + 1, Module.ClientKeySeedHash, acore::Crypto::Constants::SHA1_DIGEST_LENGTH_BYTES) != 0)
{ {
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "Request hash reply: failed"); sLog->outDebug(LOG_FILTER_WARDEN, "Request hash reply: failed");
@@ -396,8 +397,8 @@ void WardenWin::RequestChecks()
case PAGE_CHECK_A: case PAGE_CHECK_A:
case PAGE_CHECK_B: case PAGE_CHECK_B:
{ {
BigNumber tempNumber = check->Data; std::vector<uint8> data = check->Data.ToByteVector(0, false);
buff.append(tempNumber.AsByteArray(0, false).get(), tempNumber.GetNumBytes()); buff.append(data.data(), data.size());
buff << uint32(check->Address); buff << uint32(check->Address);
buff << uint8(check->Length); buff << uint8(check->Length);
break; break;
@@ -410,19 +411,16 @@ void WardenWin::RequestChecks()
} }
case DRIVER_CHECK: case DRIVER_CHECK:
{ {
BigNumber tempNumber = check->Data; std::vector<uint8> data = check->Data.ToByteVector(0, false);
buff.append(tempNumber.AsByteArray(0, false).get(), tempNumber.GetNumBytes()); buff.append(data.data(), data.size());
buff << uint8(index++); buff << uint8(index++);
break; break;
} }
case MODULE_CHECK: case MODULE_CHECK:
{ {
uint32 seed = rand32(); std::array<uint8, 4> seed = acore::Crypto::GetRandomBytes<4>();
buff << uint32(seed); buff.append(seed);
HmacHash hmac(4, (uint8*)&seed); buff.append(acore::Crypto::HMAC_SHA1::GetDigestOf(seed, check->Str));
hmac.UpdateData(check->Str);
hmac.Finalize();
buff.append(hmac.GetDigest(), hmac.GetLength());
break; break;
} }
/*case PROC_CHECK: /*case PROC_CHECK:
@@ -542,8 +540,9 @@ void WardenWin::HandleData(ByteBuffer& buff)
} }
WardenCheckResult const* rs = sWardenCheckMgr->GetWardenResultById(checkId); WardenCheckResult const* rs = sWardenCheckMgr->GetWardenResultById(checkId);
BigNumber tempNumber = rs->Result;
if (memcmp(buff.contents() + buff.rpos(), tempNumber.AsByteArray(0, false).get(), rd->Length) != 0) std::vector<uint8> result = rs->Result.ToByteVector(0, false);
if (memcmp(buff.contents() + buff.rpos(), result.data(), rd->Length) != 0)
{ {
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT MEM_CHECK fail CheckId %u account Id %u", checkId, _session->GetAccountId()); sLog->outDebug(LOG_FILTER_WARDEN, "RESULT MEM_CHECK fail CheckId %u account Id %u", checkId, _session->GetAccountId());
@@ -622,18 +621,17 @@ void WardenWin::HandleData(ByteBuffer& buff)
} }
WardenCheckResult const* rs = sWardenCheckMgr->GetWardenResultById(checkId); WardenCheckResult const* rs = sWardenCheckMgr->GetWardenResultById(checkId);
BigNumber tempNumber = rs->Result; if (memcmp(buff.contents() + buff.rpos(), rs->Result.ToByteArray<20>(false).data(), acore::Crypto::Constants::SHA1_DIGEST_LENGTH_BYTES) != 0) // SHA1
if (memcmp(buff.contents() + buff.rpos(), tempNumber.AsByteArray(0, false).get(), SHA_DIGEST_LENGTH) != 0) // SHA1
{ {
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT MPQ_CHECK fail, CheckId %u account Id %u", checkId, _session->GetAccountId()); sLog->outDebug(LOG_FILTER_WARDEN, "RESULT MPQ_CHECK fail, CheckId %u account Id %u", checkId, _session->GetAccountId());
#endif #endif
checkFailed = checkId; checkFailed = checkId;
buff.rpos(buff.rpos() + SHA_DIGEST_LENGTH); // 20 bytes SHA1 buff.rpos(buff.rpos() + acore::Crypto::Constants::SHA1_DIGEST_LENGTH_BYTES); // 20 bytes SHA1
continue; continue;
} }
buff.rpos(buff.rpos() + SHA_DIGEST_LENGTH); // 20 bytes SHA1 buff.rpos(buff.rpos() + acore::Crypto::Constants::SHA1_DIGEST_LENGTH_BYTES); // 20 bytes SHA1
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS) #if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT MPQ_CHECK passed, CheckId %u account Id %u", checkId, _session->GetAccountId()); sLog->outDebug(LOG_FILTER_WARDEN, "RESULT MPQ_CHECK passed, CheckId %u account Id %u", checkId, _session->GetAccountId());
#endif #endif
+1 -1
View File
@@ -64,7 +64,7 @@ public:
WardenWin(); WardenWin();
~WardenWin() override; ~WardenWin() override;
void Init(WorldSession* session, BigNumber* K) override; void Init(WorldSession* session, SessionKey const& K) override;
ClientWardenModule* GetModuleForClient() override; ClientWardenModule* GetModuleForClient() override;
void InitializeModule() override; void InitializeModule() override;
void RequestHash() override; void RequestHash() override;
+1
View File
@@ -164,6 +164,7 @@ enum WorldBoolConfigs
CONFIG_DEBUG_BATTLEGROUND, CONFIG_DEBUG_BATTLEGROUND,
CONFIG_DEBUG_ARENA, CONFIG_DEBUG_ARENA,
CONFIG_REGEN_HP_CANNOT_REACH_TARGET_IN_RAID, CONFIG_REGEN_HP_CANNOT_REACH_TARGET_IN_RAID,
CONFIG_SET_SHAPASSHASH,
BOOL_CONFIG_VALUE_COUNT BOOL_CONFIG_VALUE_COUNT
}; };
+2
View File
@@ -1413,6 +1413,8 @@ void World::LoadConfigSettings(bool reload)
m_int_configs[CONFIG_GM_LEVEL_CHANNEL_MODERATION] = sConfigMgr->GetOption<int32>("Channel.ModerationGMLevel", 1); m_int_configs[CONFIG_GM_LEVEL_CHANNEL_MODERATION] = sConfigMgr->GetOption<int32>("Channel.ModerationGMLevel", 1);
m_bool_configs[CONFIG_SET_SHAPASSHASH] = sConfigMgr->GetBoolDefault("SetDeprecatedExternalPasswords", false);
// call ScriptMgr if we're reloading the configuration // call ScriptMgr if we're reloading the configuration
sScriptMgr->OnAfterConfigLoad(reload); sScriptMgr->OnAfterConfigLoad(reload);
} }
+1 -1
View File
@@ -117,7 +117,7 @@ public:
handler->SendSysMessage(LANG_ACCOUNT_PASS_TOO_LONG); handler->SendSysMessage(LANG_ACCOUNT_PASS_TOO_LONG);
handler->SetSentErrorMessage(true); handler->SetSentErrorMessage(true);
return false; return false;
case AOR_NAME_ALREDY_EXIST: case AOR_NAME_ALREADY_EXIST:
handler->SendSysMessage(LANG_ACCOUNT_ALREADY_EXIST); handler->SendSysMessage(LANG_ACCOUNT_ALREADY_EXIST);
handler->SetSentErrorMessage(true); handler->SetSentErrorMessage(true);
return false; return false;
@@ -16,7 +16,7 @@
#include "Log.h" #include "Log.h"
#include "RASocket.h" #include "RASocket.h"
#include "ServerMotd.h" #include "ServerMotd.h"
#include "SHA1.h" #include "SRP6.h"
#include "Util.h" #include "Util.h"
#include "World.h" #include "World.h"
#include <thread> #include <thread>
@@ -212,22 +212,21 @@ int RASocket::check_password(const std::string& user, const std::string& pass)
std::string safe_pass = pass; std::string safe_pass = pass;
Utf8ToUpperOnlyLatin(safe_pass); Utf8ToUpperOnlyLatin(safe_pass);
std::string hash = AccountMgr::CalculateShaPassHash(safe_user, safe_pass);
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD_BY_NAME); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD_BY_NAME);
stmt->setString(0, safe_user); stmt->setString(0, safe_user);
stmt->setString(1, hash);
PreparedQueryResult result = LoginDatabase.Query(stmt); if (PreparedQueryResult result = LoginDatabase.Query(stmt))
if (!result)
{ {
sLog->outRemote("Wrong password for user: %s", user.c_str()); acore::Crypto::SRP6::Salt salt = (*result)[0].GetBinary<acore::Crypto::SRP6::SALT_LENGTH>();
return -1; acore::Crypto::SRP6::Verifier verifier = (*result)[1].GetBinary<acore::Crypto::SRP6::VERIFIER_LENGTH>();
if (acore::Crypto::SRP6::CheckLogin(safe_user, safe_pass, salt, verifier))
return 0;
} }
return 0; sLog->outRemote("Wrong password for user: %s", user.c_str());
return -1;
} }
int RASocket::authenticate() int RASocket::authenticate()