mirror of
https://github.com/mod-playerbots/azerothcore-wotlk.git
synced 2026-01-25 22:56:24 +00:00
feat(Core/DB/Authserver): remove sha_pass_hash (#4827)
This commit is contained in:
@@ -8,6 +8,8 @@
|
||||
#include <openssl/md5.h>
|
||||
|
||||
#include "Common.h"
|
||||
#include "CryptoRandom.h"
|
||||
#include "CryptoHash.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "Configuration/Config.h"
|
||||
@@ -16,7 +18,6 @@
|
||||
#include "AuthSocket.h"
|
||||
#include "AuthCodes.h"
|
||||
#include "TOTP.h"
|
||||
#include "SHA1.h"
|
||||
#include "openssl/crypto.h"
|
||||
|
||||
#define ChunkSize 2048
|
||||
@@ -64,9 +65,9 @@ typedef struct AUTH_LOGON_CHALLENGE_C
|
||||
typedef struct AUTH_LOGON_PROOF_C
|
||||
{
|
||||
uint8 cmd;
|
||||
uint8 A[32];
|
||||
uint8 M1[20];
|
||||
uint8 crc_hash[20];
|
||||
acore::Crypto::SRP6::EphemeralKey A;
|
||||
acore::Crypto::SHA1::Digest clientM;
|
||||
acore::Crypto::SHA1::Digest crc_hash;
|
||||
uint8 number_of_keys;
|
||||
uint8 securityFlags; // 0x00-0x04
|
||||
} sAuthLogonProof_C;
|
||||
@@ -75,7 +76,7 @@ typedef struct AUTH_LOGON_PROOF_S
|
||||
{
|
||||
uint8 cmd;
|
||||
uint8 error;
|
||||
uint8 M2[20];
|
||||
acore::Crypto::SHA1::Digest M2;
|
||||
uint32 unk1;
|
||||
uint32 unk2;
|
||||
uint16 unk3;
|
||||
@@ -85,7 +86,7 @@ typedef struct AUTH_LOGON_PROOF_S_OLD
|
||||
{
|
||||
uint8 cmd;
|
||||
uint8 error;
|
||||
uint8 M2[20];
|
||||
acore::Crypto::SHA1::Digest M2;
|
||||
uint32 unk2;
|
||||
} sAuthLogonProof_S_Old;
|
||||
|
||||
@@ -93,8 +94,7 @@ typedef struct AUTH_RECONNECT_PROOF_C
|
||||
{
|
||||
uint8 cmd;
|
||||
uint8 R1[16];
|
||||
uint8 R2[20];
|
||||
uint8 R3[20];
|
||||
acore::Crypto::SHA1::Digest R2, R3;
|
||||
uint8 number_of_keys;
|
||||
} sAuthReconnectProof_C;
|
||||
|
||||
@@ -183,8 +183,6 @@ AuthSocket::AuthSocket(RealmSocket& socket) :
|
||||
pPatch(nullptr), socket_(socket), _status(STATUS_CHALLENGE), _build(0),
|
||||
_expversion(0), _accountSecurityLevel(SEC_PLAYER)
|
||||
{
|
||||
N.SetHexStr("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7");
|
||||
g.SetDword(7);
|
||||
}
|
||||
|
||||
// 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;
|
||||
uint32 LastLoginAttemptCleanTime = 0;
|
||||
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
|
||||
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());
|
||||
|
||||
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");
|
||||
pkt << uint8(WOW_FAIL_LOCKED_ENFORCED);
|
||||
@@ -451,7 +410,7 @@ bool AuthSocket::_HandleLogonChallenge()
|
||||
else
|
||||
{
|
||||
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")
|
||||
sLog->outDebug(LOG_FILTER_NETWORKIO, "[AuthChallenge] Account '%s' is not locked to country", _login.c_str());
|
||||
else if (!accountCountry.empty())
|
||||
@@ -486,7 +445,7 @@ bool AuthSocket::_HandleLogonChallenge()
|
||||
|
||||
// If the account is banned, reject the logon attempt
|
||||
stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_ACCOUNT_BANNED);
|
||||
stmt->setUInt32(0, fields[1].GetUInt32());
|
||||
stmt->setUInt32(0, fields[0].GetUInt32());
|
||||
PreparedQueryResult banresult = LoginDatabase.Query(stmt);
|
||||
if (banresult)
|
||||
{
|
||||
@@ -503,31 +462,7 @@ bool AuthSocket::_HandleLogonChallenge()
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get the password from the account table, upper it, and make the SRP6 calculation
|
||||
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);
|
||||
_srp6.emplace(_login, fields[5].GetBinary<acore::Crypto::SRP6::SALT_LENGTH>(), fields[6].GetBinary<acore::Crypto::SRP6::VERIFIER_LENGTH>());
|
||||
|
||||
BigNumber unk3;
|
||||
unk3.SetRand(16 * 8);
|
||||
@@ -539,17 +474,17 @@ bool AuthSocket::_HandleLogonChallenge()
|
||||
pkt << uint8(WOW_FAIL_VERSION_INVALID);
|
||||
|
||||
// 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.append(g.AsByteArray().get(), 1);
|
||||
pkt.append(_srp6->g);
|
||||
pkt << uint8(32);
|
||||
pkt.append(N.AsByteArray(32).get(), 32);
|
||||
pkt.append(s.AsByteArray().get(), s.GetNumBytes()); // 32 bytes
|
||||
pkt.append(unk3.AsByteArray(16).get(), 16);
|
||||
pkt.append(_srp6->N);
|
||||
pkt.append(_srp6->s);
|
||||
pkt.append(unk3.ToByteArray<16>());
|
||||
uint8 securityFlags = 0;
|
||||
|
||||
// Check if token is used
|
||||
_tokenKey = fields[8].GetString();
|
||||
_tokenKey = fields[7].GetString();
|
||||
if (!_tokenKey.empty())
|
||||
securityFlags = 4;
|
||||
|
||||
@@ -573,7 +508,7 @@ bool AuthSocket::_HandleLogonChallenge()
|
||||
if (securityFlags & 0x04) // Security token input
|
||||
pkt << uint8(1);
|
||||
|
||||
uint8 secLevel = fields[5].GetUInt8();
|
||||
uint8 secLevel = fields[4].GetUInt8();
|
||||
_accountSecurityLevel = secLevel <= SEC_ADMINISTRATOR ? AccountTypes(secLevel) : SEC_ADMINISTRATOR;
|
||||
|
||||
_localizationName.resize(4);
|
||||
@@ -622,107 +557,25 @@ bool AuthSocket::_HandleLogonProof()
|
||||
return true;
|
||||
}
|
||||
|
||||
// Continue the SRP6 calculation based on data received from the client
|
||||
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))
|
||||
if (std::optional<SessionKey> K = _srp6->VerifyChallengeResponse(lp.A, lp.clientM))
|
||||
{
|
||||
_sessionKey = *K;
|
||||
#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());
|
||||
#endif
|
||||
|
||||
// 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
|
||||
const char* K_hex = K.AsHexStr();
|
||||
|
||||
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGONPROOF);
|
||||
stmt->setString(0, K_hex);
|
||||
stmt->setBinary(0, _sessionKey);
|
||||
stmt->setString(1, socket().getRemoteAddress().c_str());
|
||||
stmt->setUInt32(2, GetLocaleByName(_localizationName));
|
||||
stmt->setString(3, _os);
|
||||
stmt->setString(4, _login);
|
||||
LoginDatabase.DirectExecute(stmt);
|
||||
|
||||
OPENSSL_free((void*)K_hex);
|
||||
|
||||
// Finish SRP6 and send the final result to the client
|
||||
sha.Initialize();
|
||||
sha.UpdateBigNumbers(&A, &M, &K, nullptr);
|
||||
sha.Finalize();
|
||||
acore::Crypto::SHA1::Digest M2 = acore::Crypto::SRP6::GetSessionVerifier(lp.A, lp.clientM, _sessionKey);
|
||||
|
||||
// Check auth token
|
||||
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
|
||||
{
|
||||
sAuthLogonProof_S proof;
|
||||
memcpy(proof.M2, sha.GetDigest(), 20);
|
||||
proof.M2 = M2;
|
||||
proof.cmd = AUTH_LOGON_PROOF;
|
||||
proof.error = 0;
|
||||
proof.unk1 = 0x00800000; // Accountflags. 0x01 = GM, 0x08 = Trial, 0x00800000 = Pro pass (arena tournament)
|
||||
@@ -757,7 +610,7 @@ bool AuthSocket::_HandleLogonProof()
|
||||
else
|
||||
{
|
||||
sAuthLogonProof_S_Old proof;
|
||||
memcpy(proof.M2, sha.GetDigest(), 20);
|
||||
proof.M2 = M2;
|
||||
proof.cmd = AUTH_LOGON_PROOF;
|
||||
proof.error = 0;
|
||||
proof.unk2 = 0x00;
|
||||
@@ -909,7 +762,8 @@ bool AuthSocket::_HandleReconnectChallenge()
|
||||
uint8 secLevel = fields[2].GetUInt8();
|
||||
_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
|
||||
_status = STATUS_RECON_PROOF;
|
||||
@@ -918,8 +772,7 @@ bool AuthSocket::_HandleReconnectChallenge()
|
||||
ByteBuffer pkt;
|
||||
pkt << uint8(AUTH_RECONNECT_CHALLENGE);
|
||||
pkt << uint8(0x00);
|
||||
_reconnectProof.SetRand(16 * 8);
|
||||
pkt.append(_reconnectProof.AsByteArray(16).get(), 16); // 16 bytes random
|
||||
pkt.append(_reconnectProof); // 16 bytes random
|
||||
pkt << uint64(0x00) << uint64(0x00); // 16 bytes zeros
|
||||
socket().send((char const*)pkt.contents(), pkt.size());
|
||||
return true;
|
||||
@@ -938,19 +791,20 @@ bool AuthSocket::_HandleReconnectProof()
|
||||
|
||||
_status = STATUS_CLOSED;
|
||||
|
||||
if (_login.empty() || !_reconnectProof.GetNumBytes() || !K.GetNumBytes())
|
||||
if (_login.empty())
|
||||
return false;
|
||||
|
||||
BigNumber t1;
|
||||
t1.SetBinary(lp.R1, 16);
|
||||
|
||||
SHA1Hash sha;
|
||||
sha.Initialize();
|
||||
acore::Crypto::SHA1 sha;
|
||||
sha.UpdateData(_login);
|
||||
sha.UpdateBigNumbers(&t1, &_reconnectProof, &K, nullptr);
|
||||
sha.UpdateData(t1.ToByteArray<16>());
|
||||
sha.UpdateData(_reconnectProof);
|
||||
sha.UpdateData(_sessionKey);
|
||||
sha.Finalize();
|
||||
|
||||
if (!memcmp(sha.GetDigest(), lp.R2, SHA_DIGEST_LENGTH))
|
||||
if (sha.GetDigest() == lp.R2)
|
||||
{
|
||||
// Sending response
|
||||
ByteBuffer pkt;
|
||||
|
||||
@@ -8,8 +8,9 @@
|
||||
#define _AUTHSOCKET_H
|
||||
|
||||
#include "Common.h"
|
||||
#include "BigNumber.h"
|
||||
#include "CryptoHash.h"
|
||||
#include "RealmSocket.h"
|
||||
#include "SRP6.h"
|
||||
|
||||
class ACE_INET_Addr;
|
||||
struct Realm;
|
||||
@@ -50,8 +51,6 @@ public:
|
||||
bool _HandleXferCancel();
|
||||
bool _HandleXferAccept();
|
||||
|
||||
void _SetVSFields(const std::string& rI);
|
||||
|
||||
FILE* pPatch;
|
||||
ACE_Thread_Mutex patcherLock;
|
||||
|
||||
@@ -59,10 +58,9 @@ private:
|
||||
RealmSocket& socket_;
|
||||
RealmSocket& socket() { return socket_; }
|
||||
|
||||
BigNumber N, s, g, v;
|
||||
BigNumber b, B;
|
||||
BigNumber K;
|
||||
BigNumber _reconnectProof;
|
||||
std::optional<acore::Crypto::SRP6> _srp6;
|
||||
SessionKey _sessionKey = {};
|
||||
std::array<uint8, 16> _reconnectProof = {};
|
||||
|
||||
eStatus _status;
|
||||
|
||||
|
||||
@@ -5,11 +5,12 @@
|
||||
*/
|
||||
|
||||
#include "AccountMgr.h"
|
||||
#include "CryptoHash.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "ObjectAccessor.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "SHA1.h"
|
||||
#include "SRP6.h"
|
||||
#include "Util.h"
|
||||
#include "WorldSession.h"
|
||||
|
||||
@@ -28,13 +29,15 @@ namespace AccountMgr
|
||||
Utf8ToUpperOnlyLatin(password);
|
||||
|
||||
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);
|
||||
|
||||
stmt->setString(0, username);
|
||||
stmt->setString(1, CalculateShaPassHash(username, password));
|
||||
stmt->setInt8(2, uint8(sWorld->getIntConfig(CONFIG_EXPANSION)));
|
||||
auto [salt, verifier] = acore::Crypto::SRP6::MakeRegistrationData(username, password);
|
||||
stmt->setBinary(1, salt);
|
||||
stmt->setBinary(2, verifier);
|
||||
stmt->setInt8(3, uint8(sWorld->getIntConfig(CONFIG_EXPANSION)));
|
||||
|
||||
LoginDatabase.Execute(stmt);
|
||||
|
||||
@@ -141,11 +144,15 @@ namespace AccountMgr
|
||||
Utf8ToUpperOnlyLatin(newPassword);
|
||||
|
||||
stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_USERNAME);
|
||||
|
||||
stmt->setString(0, newUsername);
|
||||
stmt->setString(1, CalculateShaPassHash(newUsername, newPassword));
|
||||
stmt->setUInt32(2, accountId);
|
||||
stmt->setUInt32(1, 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);
|
||||
|
||||
return AOR_OK;
|
||||
@@ -170,11 +177,12 @@ namespace AccountMgr
|
||||
Utf8ToUpperOnlyLatin(username);
|
||||
Utf8ToUpperOnlyLatin(newPassword);
|
||||
|
||||
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_PASSWORD);
|
||||
|
||||
stmt->setString(0, CalculateShaPassHash(username, newPassword));
|
||||
stmt->setUInt32(1, accountId);
|
||||
auto [salt, verifier] = acore::Crypto::SRP6::MakeRegistrationData(username, newPassword);
|
||||
|
||||
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGON);
|
||||
stmt->setBinary(0, salt);
|
||||
stmt->setBinary(1, verifier);
|
||||
stmt->setUInt32(2, accountId);;
|
||||
LoginDatabase.Execute(stmt);
|
||||
|
||||
sScriptMgr->OnPasswordChange(accountId);
|
||||
@@ -236,10 +244,15 @@ namespace AccountMgr
|
||||
|
||||
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD);
|
||||
stmt->setUInt32(0, accountId);
|
||||
stmt->setString(1, CalculateShaPassHash(username, password));
|
||||
PreparedQueryResult result = LoginDatabase.Query(stmt);
|
||||
if (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)
|
||||
@@ -252,18 +265,6 @@ namespace AccountMgr
|
||||
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)
|
||||
{
|
||||
return gmlevel == SEC_PLAYER;
|
||||
|
||||
@@ -15,7 +15,7 @@ enum AccountOpResult
|
||||
AOR_OK,
|
||||
AOR_NAME_TOO_LONG,
|
||||
AOR_PASS_TOO_LONG,
|
||||
AOR_NAME_ALREDY_EXIST,
|
||||
AOR_NAME_ALREADY_EXIST,
|
||||
AOR_NAME_NOT_EXIST,
|
||||
AOR_DB_INTERNAL_ERROR
|
||||
};
|
||||
@@ -36,7 +36,6 @@ namespace AccountMgr
|
||||
uint32 GetSecurity(uint32 accountId, int32 realmId);
|
||||
bool GetName(uint32 accountId, std::string& name);
|
||||
uint32 GetCharactersCount(uint32 accountId);
|
||||
std::string CalculateShaPassHash(std::string const& name, std::string const& password);
|
||||
|
||||
bool IsPlayerAccount(uint32 gmlevel);
|
||||
bool IsGMAccount(uint32 gmlevel);
|
||||
|
||||
@@ -1740,7 +1740,7 @@ void Guild::HandleMemberDepositMoney(WorldSession* session, uint32 amount)
|
||||
|
||||
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());
|
||||
|
||||
if (amount > 10 * GOLD)
|
||||
@@ -1789,7 +1789,7 @@ bool Guild::HandleMemberWithdrawMoney(WorldSession* session, uint32 amount, bool
|
||||
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());
|
||||
|
||||
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());
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@
|
||||
#include "Pet.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "SHA1.h"
|
||||
#include "SocialMgr.h"
|
||||
#include "Spell.h"
|
||||
#include "UpdateData.h"
|
||||
|
||||
@@ -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")
|
||||
{
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
#define __WORLDSESSION_H
|
||||
|
||||
#include "AccountMgr.h"
|
||||
#include "AuthDefines.h"
|
||||
#include "AddonMgr.h"
|
||||
#include "BanManager.h"
|
||||
#include "Common.h"
|
||||
#include "Cryptography/BigNumber.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "GossipDef.h"
|
||||
#include "Opcodes.h"
|
||||
@@ -239,7 +239,7 @@ public:
|
||||
void SetTotalTime(uint32 TotalTime) { m_total_time = TotalTime; }
|
||||
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
|
||||
void SetInQueue(bool state) { m_inQueue = state; }
|
||||
|
||||
@@ -8,13 +8,14 @@
|
||||
#include "BigNumber.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "Common.h"
|
||||
#include "CryptoHash.h"
|
||||
#include "CryptoRandom.h"
|
||||
#include "DatabaseEnv.h"
|
||||
#include "Log.h"
|
||||
#include "Opcodes.h"
|
||||
#include "PacketLog.h"
|
||||
#include "Player.h"
|
||||
#include "ScriptMgr.h"
|
||||
#include "SHA1.h"
|
||||
#include "SharedDefines.h"
|
||||
#include "Util.h"
|
||||
#include "World.h"
|
||||
@@ -92,9 +93,10 @@ struct ClientPktHeader
|
||||
WorldSocket::WorldSocket(void): WorldHandler(),
|
||||
m_LastPingTime(SystemTimePoint::min()), m_OverSpeedPings(0), m_Session(0),
|
||||
m_RecvWPct(0), m_RecvPct(), m_Header(sizeof (ClientPktHeader)),
|
||||
m_OutBuffer(0), m_OutBufferSize(65536), m_OutActive(false),
|
||||
m_Seed(static_cast<uint32> (rand32()))
|
||||
m_OutBuffer(0), m_OutBufferSize(65536), m_OutActive(false)
|
||||
{
|
||||
acore::Crypto::GetRandomBytes(m_Seed);
|
||||
|
||||
reference_counting_policy().value (ACE_Event_Handler::Reference_Counting_Policy::ENABLED);
|
||||
|
||||
msg_queue()->high_water_mark(8 * 1024 * 1024);
|
||||
@@ -157,7 +159,9 @@ int WorldSocket::SendPacket(WorldPacket const& pct)
|
||||
sPacketLog->LogPacket(pct, SERVER_TO_CLIENT);
|
||||
|
||||
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())
|
||||
{
|
||||
@@ -235,15 +239,8 @@ int WorldSocket::open(void* a)
|
||||
// Send startup packet.
|
||||
WorldPacket packet (SMSG_AUTH_CHALLENGE, 24);
|
||||
packet << uint32(1); // 1...31
|
||||
packet << m_Seed;
|
||||
|
||||
BigNumber seed1;
|
||||
seed1.SetRand(16 * 8);
|
||||
packet.append(seed1.AsByteArray(16).get(), 16); // new encryption seeds
|
||||
|
||||
BigNumber seed2;
|
||||
seed2.SetRand(16 * 8);
|
||||
packet.append(seed2.AsByteArray(16).get(), 16); // new encryption seeds
|
||||
packet.append(m_Seed);
|
||||
packet.append(acore::Crypto::GetRandomBytes<32>()); // new encryption seeds
|
||||
|
||||
if (SendPacket(packet) == -1)
|
||||
return -1;
|
||||
@@ -470,7 +467,8 @@ int WorldSocket::handle_input_header(void)
|
||||
|
||||
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());
|
||||
|
||||
@@ -736,8 +734,6 @@ int WorldSocket::ProcessIncoming(WorldPacket* new_pct)
|
||||
int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
|
||||
{
|
||||
// NOTE: ATM the socket is singlethread, have this in mind ...
|
||||
uint8 digest[20];
|
||||
uint32 clientSeed;
|
||||
uint32 loginServerID, loginServerType, regionID, battlegroupID, realm;
|
||||
uint64 DosResponse;
|
||||
uint32 BuiltNumberClient;
|
||||
@@ -747,10 +743,10 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
|
||||
//uint8 expansion = 0;
|
||||
LocaleConstant locale;
|
||||
std::string account;
|
||||
SHA1Hash sha;
|
||||
WorldPacket packet, SendAddonPacked;
|
||||
std::array<uint8, 4> clientSeed;
|
||||
acore::Crypto::SHA1::Digest digest;
|
||||
|
||||
BigNumber k;
|
||||
bool wardenActive = sWorld->getBoolConfig(CONFIG_WARDEN_ENABLED);
|
||||
|
||||
if (sWorld->IsClosed())
|
||||
@@ -768,12 +764,12 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
|
||||
recvPacket >> loginServerID;
|
||||
recvPacket >> account;
|
||||
recvPacket >> loginServerType;
|
||||
recvPacket >> clientSeed;
|
||||
recvPacket.read(clientSeed);
|
||||
recvPacket >> regionID;
|
||||
recvPacket >> battlegroupID;
|
||||
recvPacket >> realm;
|
||||
recvPacket >> DosResponse;
|
||||
recvPacket.read(digest, 20);
|
||||
recvPacket.read(digest);
|
||||
|
||||
#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);
|
||||
@@ -843,7 +839,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
|
||||
security = SEC_ADMINISTRATOR;
|
||||
*/
|
||||
|
||||
k.SetHexStr (fields[1].GetCString());
|
||||
SessionKey sessionKey = fields[1].GetBinary<SESSION_KEY_LENGTH>();
|
||||
|
||||
int64 mutetime = fields[6].GetInt64();
|
||||
//! 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
|
||||
uint32 t = 0;
|
||||
uint32 seed = m_Seed;
|
||||
uint8 t[4] = { 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
acore::Crypto::SHA1 sha;
|
||||
sha.UpdateData (account);
|
||||
sha.UpdateData ((uint8*) & t, 4);
|
||||
sha.UpdateData ((uint8*) & clientSeed, 4);
|
||||
sha.UpdateData ((uint8*) & seed, 4);
|
||||
sha.UpdateBigNumbers (&k, nullptr);
|
||||
sha.UpdateData(t);
|
||||
sha.UpdateData(clientSeed);
|
||||
sha.UpdateData(m_Seed);
|
||||
sha.UpdateData(sessionKey);
|
||||
sha.Finalize();
|
||||
|
||||
if (memcmp (sha.GetDigest(), digest, 20))
|
||||
if (sha.GetDigest() != digest)
|
||||
{
|
||||
packet.Initialize (SMSG_AUTH_RESPONSE, 1);
|
||||
packet << uint8 (AUTH_FAILED);
|
||||
@@ -984,7 +980,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
|
||||
// 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);
|
||||
|
||||
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
|
||||
if (sWorld->IsClosed())
|
||||
@@ -1019,7 +1015,7 @@ int WorldSocket::HandleAuthSession(WorldPacket& recvPacket)
|
||||
|
||||
// Initialize Warden system only if it is enabled by config
|
||||
if (wardenActive)
|
||||
m_Session->InitWarden(&k, os);
|
||||
m_Session->InitWarden(sessionKey, os);
|
||||
|
||||
// Sleep this Network thread for
|
||||
uint32 sleepTime = sWorld->getIntConfig(CONFIG_SESSION_ADD_DELAY);
|
||||
|
||||
@@ -189,7 +189,7 @@ private:
|
||||
/// True if the socket is registered with the reactor for output
|
||||
bool m_OutActive;
|
||||
|
||||
uint32 m_Seed;
|
||||
std::array<uint8, 4> m_Seed;
|
||||
};
|
||||
|
||||
#endif /* _WORLDSOCKET_H */
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <openssl/md5.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)
|
||||
{
|
||||
memset(_inputKey, 0, sizeof(_inputKey));
|
||||
@@ -125,12 +125,12 @@ void Warden::Update(uint32 const diff)
|
||||
|
||||
void Warden::DecryptData(uint8* buffer, uint32 length)
|
||||
{
|
||||
_inputCrypto.UpdateData(length, buffer);
|
||||
_inputCrypto.UpdateData(buffer, length);
|
||||
}
|
||||
|
||||
void Warden::EncryptData(uint8* buffer, uint32 length)
|
||||
{
|
||||
_outputCrypto.UpdateData(length, buffer);
|
||||
_outputCrypto.UpdateData(buffer, length);
|
||||
}
|
||||
|
||||
bool Warden::IsValidCheckSum(uint32 checksum, const uint8* data, const uint16 length)
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
#ifndef _WARDEN_BASE_H
|
||||
#define _WARDEN_BASE_H
|
||||
|
||||
#include "ARC4.h"
|
||||
#include "AuthDefines.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "Cryptography/ARC4.h"
|
||||
#include "Cryptography/BigNumber.h"
|
||||
#include "WardenCheckMgr.h"
|
||||
#include <map>
|
||||
#include <array>
|
||||
|
||||
enum WardenOpcodes
|
||||
{
|
||||
@@ -97,7 +97,7 @@ public:
|
||||
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 void InitializeModule() = 0;
|
||||
virtual void RequestHash() = 0;
|
||||
@@ -123,8 +123,8 @@ private:
|
||||
uint8 _inputKey[16];
|
||||
uint8 _outputKey[16];
|
||||
uint8 _seed[16];
|
||||
ARC4 _inputCrypto;
|
||||
ARC4 _outputCrypto;
|
||||
acore::Crypto::ARC4 _inputCrypto;
|
||||
acore::Crypto::ARC4 _outputCrypto;
|
||||
uint32 _checkTimer; // Timer for sending check requests
|
||||
uint32 _clientResponseTimer; // Timer for client response delay
|
||||
bool _dataSent;
|
||||
|
||||
@@ -103,16 +103,6 @@ void WardenCheckMgr::LoadWardenChecks()
|
||||
{
|
||||
WardenCheckResult wr;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -148,19 +138,7 @@ void WardenCheckMgr::LoadWardenChecks()
|
||||
default:
|
||||
{
|
||||
if (checkType == PAGE_CHECK_A || checkType == PAGE_CHECK_B || checkType == DRIVER_CHECK)
|
||||
{
|
||||
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);
|
||||
break;
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
|
||||
#include "ByteBuffer.h"
|
||||
#include "Common.h"
|
||||
#include "WardenKeyGeneration.h"
|
||||
#include "Log.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Player.h"
|
||||
#include "SessionKeyGenerator.h"
|
||||
#include "Util.h"
|
||||
#include "WardenMac.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;
|
||||
// Generate Warden Key
|
||||
SHA1Randx WK(K->AsByteArray().get(), K->GetNumBytes());
|
||||
SessionKeyGenerator<acore::Crypto::SHA1> WK(K);
|
||||
WK.Generate(_inputKey, 16);
|
||||
WK.Generate(_outputKey, 16);
|
||||
/*
|
||||
@@ -48,17 +48,17 @@ void WardenMac::Init(WorldSession* pClient, BigNumber* K)
|
||||
_outputCrypto.Init(_outputKey);
|
||||
#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, "C->S Key: %s", ByteArrayToHexStr(_inputKey, 16).c_str());
|
||||
sLog->outDebug(LOG_FILTER_WARDEN, "S->C Key: %s", ByteArrayToHexStr(_outputKey, 16).c_str());
|
||||
sLog->outDebug(LOG_FILTER_WARDEN, " Seed: %s", ByteArrayToHexStr(_seed, 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", acore::Impl::ByteArrayToHexStr(_outputKey).c_str());
|
||||
sLog->outDebug(LOG_FILTER_WARDEN, " Seed: %s", acore::Impl::ByteArrayToHexStr(_seed).c_str());
|
||||
sLog->outDebug(LOG_FILTER_WARDEN, "Loading Module...");
|
||||
#endif
|
||||
|
||||
_module = GetModuleForClient();
|
||||
|
||||
#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 ID: %s", ByteArrayToHexStr(_module->Id, 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", acore::Impl::ByteArrayToHexStr(_module->Id).c_str());
|
||||
#endif
|
||||
RequestModule();
|
||||
}
|
||||
@@ -154,14 +154,14 @@ void WardenMac::HandleHashResult(ByteBuffer& buff)
|
||||
|
||||
buff.rpos(buff.wpos());
|
||||
|
||||
SHA1Hash sha1;
|
||||
acore::Crypto::SHA1 sha1;
|
||||
sha1.UpdateData((uint8*)keyIn, 16);
|
||||
sha1.Finalize();
|
||||
|
||||
//const uint8 validHash[20] = { 0x56, 0x8C, 0x05, 0x4C, 0x78, 0x1A, 0x97, 0x2A, 0x60, 0x37, 0xA2, 0x29, 0x0C, 0x22, 0xB5, 0x25, 0x71, 0xA0, 0x6F, 0x4E };
|
||||
|
||||
// Verify key
|
||||
if (memcmp(buff.contents() + 1, sha1.GetDigest(), 20) != 0)
|
||||
if (memcmp(buff.contents() + 1, sha1.GetDigest().data(), 20) != 0)
|
||||
{
|
||||
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
|
||||
sLog->outDebug(LOG_FILTER_WARDEN, "Request hash reply: failed");
|
||||
@@ -242,16 +242,16 @@ void WardenMac::HandleData(ByteBuffer& buff)
|
||||
|
||||
std::string str = "Test string!";
|
||||
|
||||
SHA1Hash sha1;
|
||||
acore::Crypto::SHA1 sha1;
|
||||
sha1.UpdateData(str);
|
||||
uint32 magic = 0xFEEDFACE; // unsure
|
||||
sha1.UpdateData((uint8*)&magic, 4);
|
||||
sha1.Finalize();
|
||||
|
||||
uint8 sha1Hash[20];
|
||||
buff.read(sha1Hash, 20);
|
||||
std::array<uint8, acore::Crypto::SHA1::DIGEST_LENGTH> sha1Hash;
|
||||
buff.read(sha1Hash.data(), sha1Hash.size());
|
||||
|
||||
if (memcmp(sha1Hash, sha1.GetDigest(), 20))
|
||||
if (sha1Hash != sha1.GetDigest())
|
||||
{
|
||||
#if defined(ENABLE_EXTRAS) && defined(ENABLE_EXTRA_LOGS)
|
||||
sLog->outDebug(LOG_FILTER_WARDEN, "Handle data failed: SHA1 hash is wrong!");
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
#include "ByteBuffer.h"
|
||||
#include "ARC4.h"
|
||||
#include "BigNumber.h"
|
||||
#include "Warden.h"
|
||||
#include <map>
|
||||
|
||||
@@ -22,7 +21,7 @@ public:
|
||||
WardenMac();
|
||||
~WardenMac() override;
|
||||
|
||||
void Init(WorldSession* session, BigNumber* k) override;
|
||||
void Init(WorldSession* session, SessionKey const& k) override;
|
||||
ClientWardenModule* GetModuleForClient() override;
|
||||
void InitializeModule() override;
|
||||
void RequestHash() override;
|
||||
|
||||
@@ -7,12 +7,13 @@
|
||||
#include "AccountMgr.h"
|
||||
#include "ByteBuffer.h"
|
||||
#include "Common.h"
|
||||
#include "Cryptography/HMACSHA1.h"
|
||||
#include "Cryptography/WardenKeyGeneration.h"
|
||||
#include "CryptoRandom.h"
|
||||
#include "Database/DatabaseEnv.h"
|
||||
#include "HMAC.h"
|
||||
#include "Log.h"
|
||||
#include "Opcodes.h"
|
||||
#include "Player.h"
|
||||
#include "SessionKeyGenerator.h"
|
||||
#include "Util.h"
|
||||
#include "WardenCheckMgr.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 PAGE_CHECK_A: 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);
|
||||
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;
|
||||
// Generate Warden Key
|
||||
SHA1Randx WK(k->AsByteArray().get(), k->GetNumBytes());
|
||||
SessionKeyGenerator<acore::Crypto::SHA1> WK(k);
|
||||
WK.Generate(_inputKey, 16);
|
||||
WK.Generate(_outputKey, 16);
|
||||
|
||||
@@ -104,17 +105,17 @@ void WardenWin::Init(WorldSession* session, BigNumber* k)
|
||||
_outputCrypto.Init(_outputKey);
|
||||
#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, "C->S Key: %s", ByteArrayToHexStr(_inputKey, 16).c_str());
|
||||
sLog->outDebug(LOG_FILTER_WARDEN, "S->C Key: %s", ByteArrayToHexStr(_outputKey, 16).c_str());
|
||||
sLog->outDebug(LOG_FILTER_WARDEN, " Seed: %s", ByteArrayToHexStr(_seed, 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", acore::Impl::ByteArrayToHexStr(_outputKey).c_str());
|
||||
sLog->outDebug(LOG_FILTER_WARDEN, " Seed: %s", acore::Impl::ByteArrayToHexStr(_seed).c_str());
|
||||
sLog->outDebug(LOG_FILTER_WARDEN, "Loading Module...");
|
||||
#endif
|
||||
|
||||
_module = GetModuleForClient();
|
||||
|
||||
#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 ID: %s", ByteArrayToHexStr(_module->Id, 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", acore::Impl::ByteArrayToHexStr(_module->Id).c_str());
|
||||
#endif
|
||||
RequestModule();
|
||||
}
|
||||
@@ -158,7 +159,7 @@ void WardenWin::InitializeModule()
|
||||
Request.Function1[1] = 0x000218C0; // 0x00400000 + 0x000218C0 SFileGetFileSize
|
||||
Request.Function1[2] = 0x00022530; // 0x00400000 + 0x00022530 SFileReadFile
|
||||
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.Size2 = 8;
|
||||
@@ -223,7 +224,7 @@ void WardenWin::HandleHashResult(ByteBuffer& buff)
|
||||
buff.rpos(buff.wpos());
|
||||
|
||||
// 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)
|
||||
sLog->outDebug(LOG_FILTER_WARDEN, "Request hash reply: failed");
|
||||
@@ -396,8 +397,8 @@ void WardenWin::RequestChecks()
|
||||
case PAGE_CHECK_A:
|
||||
case PAGE_CHECK_B:
|
||||
{
|
||||
BigNumber tempNumber = check->Data;
|
||||
buff.append(tempNumber.AsByteArray(0, false).get(), tempNumber.GetNumBytes());
|
||||
std::vector<uint8> data = check->Data.ToByteVector(0, false);
|
||||
buff.append(data.data(), data.size());
|
||||
buff << uint32(check->Address);
|
||||
buff << uint8(check->Length);
|
||||
break;
|
||||
@@ -410,19 +411,16 @@ void WardenWin::RequestChecks()
|
||||
}
|
||||
case DRIVER_CHECK:
|
||||
{
|
||||
BigNumber tempNumber = check->Data;
|
||||
buff.append(tempNumber.AsByteArray(0, false).get(), tempNumber.GetNumBytes());
|
||||
std::vector<uint8> data = check->Data.ToByteVector(0, false);
|
||||
buff.append(data.data(), data.size());
|
||||
buff << uint8(index++);
|
||||
break;
|
||||
}
|
||||
case MODULE_CHECK:
|
||||
{
|
||||
uint32 seed = rand32();
|
||||
buff << uint32(seed);
|
||||
HmacHash hmac(4, (uint8*)&seed);
|
||||
hmac.UpdateData(check->Str);
|
||||
hmac.Finalize();
|
||||
buff.append(hmac.GetDigest(), hmac.GetLength());
|
||||
std::array<uint8, 4> seed = acore::Crypto::GetRandomBytes<4>();
|
||||
buff.append(seed);
|
||||
buff.append(acore::Crypto::HMAC_SHA1::GetDigestOf(seed, check->Str));
|
||||
break;
|
||||
}
|
||||
/*case PROC_CHECK:
|
||||
@@ -542,8 +540,9 @@ void WardenWin::HandleData(ByteBuffer& buff)
|
||||
}
|
||||
|
||||
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)
|
||||
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);
|
||||
BigNumber tempNumber = rs->Result;
|
||||
if (memcmp(buff.contents() + buff.rpos(), tempNumber.AsByteArray(0, false).get(), SHA_DIGEST_LENGTH) != 0) // SHA1
|
||||
if (memcmp(buff.contents() + buff.rpos(), rs->Result.ToByteArray<20>(false).data(), acore::Crypto::Constants::SHA1_DIGEST_LENGTH_BYTES) != 0) // SHA1
|
||||
{
|
||||
#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());
|
||||
#endif
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
sLog->outDebug(LOG_FILTER_WARDEN, "RESULT MPQ_CHECK passed, CheckId %u account Id %u", checkId, _session->GetAccountId());
|
||||
#endif
|
||||
|
||||
@@ -64,7 +64,7 @@ public:
|
||||
WardenWin();
|
||||
~WardenWin() override;
|
||||
|
||||
void Init(WorldSession* session, BigNumber* K) override;
|
||||
void Init(WorldSession* session, SessionKey const& K) override;
|
||||
ClientWardenModule* GetModuleForClient() override;
|
||||
void InitializeModule() override;
|
||||
void RequestHash() override;
|
||||
|
||||
@@ -164,6 +164,7 @@ enum WorldBoolConfigs
|
||||
CONFIG_DEBUG_BATTLEGROUND,
|
||||
CONFIG_DEBUG_ARENA,
|
||||
CONFIG_REGEN_HP_CANNOT_REACH_TARGET_IN_RAID,
|
||||
CONFIG_SET_SHAPASSHASH,
|
||||
BOOL_CONFIG_VALUE_COUNT
|
||||
};
|
||||
|
||||
|
||||
@@ -1413,6 +1413,8 @@ void World::LoadConfigSettings(bool reload)
|
||||
|
||||
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
|
||||
sScriptMgr->OnAfterConfigLoad(reload);
|
||||
}
|
||||
|
||||
@@ -117,7 +117,7 @@ public:
|
||||
handler->SendSysMessage(LANG_ACCOUNT_PASS_TOO_LONG);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
case AOR_NAME_ALREDY_EXIST:
|
||||
case AOR_NAME_ALREADY_EXIST:
|
||||
handler->SendSysMessage(LANG_ACCOUNT_ALREADY_EXIST);
|
||||
handler->SetSentErrorMessage(true);
|
||||
return false;
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "Log.h"
|
||||
#include "RASocket.h"
|
||||
#include "ServerMotd.h"
|
||||
#include "SHA1.h"
|
||||
#include "SRP6.h"
|
||||
#include "Util.h"
|
||||
#include "World.h"
|
||||
#include <thread>
|
||||
@@ -212,22 +212,21 @@ int RASocket::check_password(const std::string& user, const std::string& pass)
|
||||
std::string safe_pass = pass;
|
||||
Utf8ToUpperOnlyLatin(safe_pass);
|
||||
|
||||
std::string hash = AccountMgr::CalculateShaPassHash(safe_user, safe_pass);
|
||||
|
||||
PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_CHECK_PASSWORD_BY_NAME);
|
||||
|
||||
stmt->setString(0, safe_user);
|
||||
stmt->setString(1, hash);
|
||||
|
||||
PreparedQueryResult result = LoginDatabase.Query(stmt);
|
||||
|
||||
if (!result)
|
||||
if (PreparedQueryResult result = LoginDatabase.Query(stmt))
|
||||
{
|
||||
sLog->outRemote("Wrong password for user: %s", user.c_str());
|
||||
return -1;
|
||||
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(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()
|
||||
|
||||
Reference in New Issue
Block a user