std::string LoginRESTService::CalculateShaPassHash(std::string const& name, std::string const& password) { SHA256Hash email; email.UpdateData(name); email.Finalize(); SHA256Hash sha; sha.UpdateData(ByteArrayToHexStr(email.GetDigest(), email.GetLength())); sha.UpdateData(":"); sha.UpdateData(password); sha.Finalize(); return ByteArrayToHexStr(sha.GetDigest(), sha.GetLength(), true); }
bool Battlenet::Session::HandlePasswordModule(BitStream* dataStream, ServerPacket** response) { if (dataStream->GetSize() != 1 + 128 + 32 + 128) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE); ReplaceResponse(response, logonResponse); return false; } if (dataStream->Read<uint8>(8) != 2) // State { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE); ReplaceResponse(response, logonResponse); return false; } BigNumber A, clientM1, clientChallenge; A.SetBinary(dataStream->ReadBytes(128).get(), 128); clientM1.SetBinary(dataStream->ReadBytes(32).get(), 32); clientChallenge.SetBinary(dataStream->ReadBytes(128).get(), 128); if (A.isZero()) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_CORRUPTED_MODULE); ReplaceResponse(response, logonResponse); return false; } SHA256Hash sha; sha.UpdateBigNumbers(&A, &B, NULL); sha.Finalize(); BigNumber u; u.SetBinary(sha.GetDigest(), sha.GetLength()); BigNumber S = ((A * v.ModExp(u, N)) % N).ModExp(b, N); uint8 S_bytes[128]; memcpy(S_bytes, S.AsByteArray(128).get(), 128); uint8 part1[64]; uint8 part2[64]; for (int i = 0; i < 64; ++i) { part1[i] = S_bytes[i * 2]; part2[i] = S_bytes[i * 2 + 1]; } SHA256Hash part1sha, part2sha; part1sha.UpdateData(part1, 64); part1sha.Finalize(); part2sha.UpdateData(part2, 64); part2sha.Finalize(); uint8 sessionKey[SHA256_DIGEST_LENGTH * 2]; for (int i = 0; i < SHA256_DIGEST_LENGTH; ++i) { sessionKey[i * 2] = part1sha.GetDigest()[i]; sessionKey[i * 2 + 1] = part2sha.GetDigest()[i]; } K.SetBinary(sessionKey, SHA256_DIGEST_LENGTH * 2); BigNumber M1; uint8 hash[SHA256_DIGEST_LENGTH]; sha.Initialize(); sha.UpdateBigNumbers(&N, NULL); sha.Finalize(); memcpy(hash, sha.GetDigest(), sha.GetLength()); sha.Initialize(); sha.UpdateBigNumbers(&g, NULL); sha.Finalize(); for (int i = 0; i < sha.GetLength(); ++i) hash[i] ^= sha.GetDigest()[i]; SHA256Hash shaI; shaI.UpdateData(ByteArrayToHexStr(I.AsByteArray().get(), 32)); shaI.Finalize(); // Concat all variables for M1 hash sha.Initialize(); sha.UpdateData(hash, SHA256_DIGEST_LENGTH); sha.UpdateData(shaI.GetDigest(), shaI.GetLength()); sha.UpdateBigNumbers(&s, &A, &B, &K, NULL); sha.Finalize(); M1.SetBinary(sha.GetDigest(), sha.GetLength()); if (memcmp(M1.AsByteArray().get(), clientM1.AsByteArray().get(), 32)) { PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_FAILED_LOGINS); stmt->setString(0, _accountInfo->Login); LoginDatabase.Execute(stmt); Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); ReplaceResponse(response, logonResponse); TC_LOG_DEBUG("session", "[Battlenet::Password] %s attempted to log in with invalid password!", GetClientInfo().c_str()); return false; } if (_gameAccounts.empty()) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(LOGIN_NO_GAME_ACCOUNT); ReplaceResponse(response, logonResponse); TC_LOG_DEBUG("session", "[Battlenet::Password] %s does not have any linked game accounts!", GetClientInfo().c_str()); return false; } BigNumber M; sha.Initialize(); sha.UpdateBigNumbers(&A, &M1, &K, NULL); sha.Finalize(); M.SetBinary(sha.GetDigest(), sha.GetLength()); BigNumber serverProof; serverProof.SetRand(128 * 8); // just send garbage, server signature check is patched out in client BitStream stream; ModuleInfo* password = sModuleMgr->CreateModule(_os, "Password"); uint8 state = 3; stream.WriteBytes(&state, 1); stream.WriteBytes(M.AsByteArray(32).get(), 32); stream.WriteBytes(serverProof.AsByteArray(128).get(), 128); password->DataSize = stream.GetSize(); password->Data = new uint8[password->DataSize]; memcpy(password->Data, stream.GetBuffer(), password->DataSize); Authentication::ProofRequest* proofRequest = new Authentication::ProofRequest(); proofRequest->Modules.push_back(password); if (_gameAccounts.size() > 1) { BitStream accounts; state = 0; accounts.WriteBytes(&state, 1); accounts.Write(_gameAccounts.size(), 8); for (GameAccountInfo const& gameAccount : _gameAccounts) { accounts.Write(2, 8); accounts.WriteString(gameAccount.DisplayName, 8); } ModuleInfo* selectGameAccount = sModuleMgr->CreateModule(_os, "SelectGameAccount"); selectGameAccount->DataSize = accounts.GetSize(); selectGameAccount->Data = new uint8[selectGameAccount->DataSize]; memcpy(selectGameAccount->Data, accounts.GetBuffer(), selectGameAccount->DataSize); proofRequest->Modules.push_back(selectGameAccount); _modulesWaitingForData.push(MODULE_SELECT_GAME_ACCOUNT); } else { _gameAccountInfo = &_gameAccounts[0]; if (_gameAccountInfo->IsBanned) { delete proofRequest; Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); if (_gameAccountInfo->IsPermanentlyBanned) { logonResponse->SetAuthResult(LOGIN_BANNED); TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::Password] Banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo->Login.c_str()); } else { logonResponse->SetAuthResult(LOGIN_SUSPENDED); TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::Password] Temporarily banned account %s tried to login!", GetRemoteIpAddress().to_string().c_str(), GetRemotePort(), _accountInfo->Login.c_str()); } ReplaceResponse(response, logonResponse); return false; } proofRequest->Modules.push_back(sModuleMgr->CreateModule(_os, "RiskFingerprint")); _modulesWaitingForData.push(MODULE_RISK_FINGERPRINT); } ReplaceResponse(response, proofRequest); return true; }
void Battlenet::Session::HandleLogonRequestCallback(PreparedQueryResult result) { if (!result) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); AsyncWrite(logonResponse); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s is trying to log in from unknown account!", GetClientInfo().c_str()); return; } Field* fields = result->Fetch(); _accountInfo->LoadResult(fields); std::string pStr = fields[8].GetString(); std::string databaseV = fields[9].GetString(); std::string databaseS = fields[10].GetString(); _gameAccounts.resize(result->GetRowCount()); uint32 i = 0; do { _gameAccounts[i++].LoadResult(result->Fetch() + 11); } while (result->NextRow()); std::string ip_address = GetRemoteIpAddress().to_string(); // If the IP is 'locked', check that the player comes indeed from the correct IP address if (_accountInfo->IsLockedToIP) { TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is locked to IP - '%s' is logging in from '%s'", _accountInfo->Login.c_str(), _accountInfo->LastIP.c_str(), ip_address.c_str()); if (_accountInfo->LastIP != ip_address) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_ACCOUNT_LOCKED); AsyncWrite(logonResponse); return; } } else { TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is not locked to ip", _accountInfo->Login.c_str()); if (_accountInfo->LockCountry.empty() || _accountInfo->LockCountry == "00") TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is not locked to country", _accountInfo->Login.c_str()); else if (!_accountInfo->LockCountry.empty() && !_ipCountry.empty()) { TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is locked to country: '%s' Player country is '%s'", _accountInfo->Login.c_str(), _accountInfo->LockCountry.c_str(), _ipCountry.c_str()); if (_ipCountry != _accountInfo->LockCountry) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_ACCOUNT_LOCKED); AsyncWrite(logonResponse); return; } } } // If the account is banned, reject the logon attempt if (_accountInfo->IsBanned) { if (_accountInfo->IsPermanentlyBanned) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(LOGIN_BANNED); AsyncWrite(logonResponse); TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::LogonRequest] Banned account %s tried to login!", ip_address.c_str(), GetRemotePort(), _accountInfo->Login.c_str()); return; } else { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(LOGIN_SUSPENDED); AsyncWrite(logonResponse); TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::LogonRequest] Temporarily banned account %s tried to login!", ip_address.c_str(), GetRemotePort(), _accountInfo->Login.c_str()); return; } } SHA256Hash sha; sha.UpdateData(_accountInfo->Login); sha.Finalize(); I.SetBinary(sha.GetDigest(), sha.GetLength()); ModuleInfo* password = sModuleMgr->CreateModule(_os, "Password"); ModuleInfo* thumbprint = sModuleMgr->CreateModule(_os, "Thumbprint"); if (databaseV.size() != size_t(BufferSizes::SRP_6_V) * 2 || databaseS.size() != size_t(BufferSizes::SRP_6_S) * 2) _SetVSFields(pStr); else { s.SetHexStr(databaseS.c_str()); v.SetHexStr(databaseV.c_str()); } b.SetRand(128 * 8); B = ((v * k) + g.ModExp(b, N)) % N; BigNumber unk; unk.SetRand(128 * 8); BitStream passwordData; uint8 state = 0; passwordData.WriteBytes(&state, 1); passwordData.WriteBytes(I.AsByteArray(32).get(), 32); passwordData.WriteBytes(s.AsByteArray(32).get(), 32); passwordData.WriteBytes(B.AsByteArray(128).get(), 128); passwordData.WriteBytes(unk.AsByteArray(128).get(), 128); password->DataSize = passwordData.GetSize(); password->Data = new uint8[password->DataSize]; memcpy(password->Data, passwordData.GetBuffer(), password->DataSize); _modulesWaitingForData.push(MODULE_PASSWORD); Authentication::ProofRequest* proofRequest = new Authentication::ProofRequest(); proofRequest->Modules.push_back(password); // if has authenticator, send Token module proofRequest->Modules.push_back(thumbprint); AsyncWrite(proofRequest); }
void Battlenet::Session::HandleLogonRequest(Authentication::LogonRequest3 const& logonRequest) { // Verify that this IP is not in the ip_banned table LoginDatabase.Execute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_EXPIRED_IP_BANS)); std::string ip_address = GetRemoteIpAddress().to_string(); PreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_IP_BANNED); stmt->setString(0, ip_address); if (PreparedQueryResult result = LoginDatabase.Query(stmt)) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(LOGIN_BANNED); AsyncWrite(logonResponse); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Banned ip '%s:%d' tries to login!", ip_address.c_str(), GetRemotePort()); return; } if (logonRequest.Program != "WoW") { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_INVALID_PROGRAM); AsyncWrite(logonResponse); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s attempted to log in with game other than WoW (using %s)!", GetClientInfo().c_str(), logonRequest.Program.c_str()); return; } if (!sComponentMgr->HasPlatform(logonRequest.Platform)) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_INVALID_OS); AsyncWrite(logonResponse); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s attempted to log in from an unsupported platform (using %s)!", GetClientInfo().c_str(), logonRequest.Platform.c_str()); return; } if (!sComponentMgr->HasPlatform(logonRequest.Locale)) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_UNSUPPORTED_LANGUAGE); AsyncWrite(logonResponse); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s attempted to log in with unsupported locale (using %s)!", GetClientInfo().c_str(), logonRequest.Locale.c_str()); return; } for (Component const& component : logonRequest.Components) { if (!sComponentMgr->HasComponent(&component)) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); if (!sComponentMgr->HasProgram(component.Program)) { logonResponse->SetAuthResult(AUTH_INVALID_PROGRAM); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s is using unsupported component program %s!", GetClientInfo().c_str(), component.Program.c_str()); } else if (!sComponentMgr->HasPlatform(component.Platform)) { logonResponse->SetAuthResult(AUTH_INVALID_OS); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s is using unsupported component platform %s!", GetClientInfo().c_str(), component.Platform.c_str()); } else { if (component.Program != "WoW" || AuthHelper::IsBuildSupportingBattlenet(component.Build)) logonResponse->SetAuthResult(AUTH_REGION_BAD_VERSION); else logonResponse->SetAuthResult(AUTH_USE_GRUNT_LOGON); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s is using unsupported component version %u!", GetClientInfo().c_str(), component.Build); } AsyncWrite(logonResponse); return; } if (component.Platform == "base") _build = component.Build; } _accountName = logonRequest.Login; _locale = logonRequest.Locale; _os = logonRequest.Platform; Utf8ToUpperOnlyLatin(_accountName); stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACCOUNT_INFO); stmt->setString(0, _accountName); PreparedQueryResult result = LoginDatabase.Query(stmt); if (!result) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_UNKNOWN_ACCOUNT); AsyncWrite(logonResponse); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] %s is trying to log in from unknown account!", GetClientInfo().c_str()); return; } Field* fields = result->Fetch(); _accountId = fields[1].GetUInt32(); // If the IP is 'locked', check that the player comes indeed from the correct IP address if (fields[2].GetUInt8() == 1) // if ip is locked { TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is locked to IP - '%s' is logging in from '%s'", _accountName.c_str(), fields[4].GetCString(), ip_address.c_str()); if (strcmp(fields[4].GetCString(), ip_address.c_str()) != 0) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_ACCOUNT_LOCKED); AsyncWrite(logonResponse); return; } } else { TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is not locked to ip", _accountName.c_str()); std::string accountCountry = fields[3].GetString(); if (accountCountry.empty() || accountCountry == "00") TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is not locked to country", _accountName.c_str()); else if (!accountCountry.empty()) { uint32 ip = inet_addr(ip_address.c_str()); EndianConvertReverse(ip); stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGON_COUNTRY); stmt->setUInt32(0, ip); if (PreparedQueryResult sessionCountryQuery = LoginDatabase.Query(stmt)) { std::string loginCountry = (*sessionCountryQuery)[0].GetString(); TC_LOG_DEBUG("session", "[Battlenet::LogonRequest] Account '%s' is locked to country: '%s' Player country is '%s'", _accountName.c_str(), accountCountry.c_str(), loginCountry.c_str()); if (loginCountry != accountCountry) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(AUTH_ACCOUNT_LOCKED); AsyncWrite(logonResponse); return; } } } } //set expired bans to inactive LoginDatabase.DirectExecute(LoginDatabase.GetPreparedStatement(LOGIN_DEL_BNET_EXPIRED_BANS)); // If the account is banned, reject the logon attempt stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_ACTIVE_ACCOUNT_BAN); stmt->setUInt32(0, _accountId); PreparedQueryResult banresult = LoginDatabase.Query(stmt); if (banresult) { Field* fields = banresult->Fetch(); if (fields[0].GetUInt32() == fields[1].GetUInt32()) { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(LOGIN_BANNED); AsyncWrite(logonResponse); TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::LogonRequest] Banned account %s tried to login!", ip_address.c_str(), GetRemotePort(), _accountName.c_str()); return; } else { Authentication::LogonResponse* logonResponse = new Authentication::LogonResponse(); logonResponse->SetAuthResult(LOGIN_SUSPENDED); AsyncWrite(logonResponse); TC_LOG_DEBUG("session", "'%s:%d' [Battlenet::LogonRequest] Temporarily banned account %s tried to login!", ip_address.c_str(), GetRemotePort(), _accountName.c_str()); return; } } SHA256Hash sha; sha.UpdateData(_accountName); sha.Finalize(); I.SetBinary(sha.GetDigest(), sha.GetLength()); ModuleInfo* password = sModuleMgr->CreateModule(_os, "Password"); ModuleInfo* thumbprint = sModuleMgr->CreateModule(_os, "Thumbprint"); std::string pStr = fields[0].GetString(); std::string databaseV = fields[5].GetString(); std::string databaseS = fields[6].GetString(); if (databaseV.size() != size_t(BufferSizes::SRP_6_V) * 2 || databaseS.size() != size_t(BufferSizes::SRP_6_S) * 2) _SetVSFields(pStr); else { s.SetHexStr(databaseS.c_str()); v.SetHexStr(databaseV.c_str()); } b.SetRand(128 * 8); B = ((v * k) + g.ModExp(b, N)) % N; BigNumber unk; unk.SetRand(128 * 8); BitStream passwordData; uint8 state = 0; passwordData.WriteBytes(&state, 1); passwordData.WriteBytes(I.AsByteArray(32).get(), 32); passwordData.WriteBytes(s.AsByteArray(32).get(), 32); passwordData.WriteBytes(B.AsByteArray(128).get(), 128); passwordData.WriteBytes(unk.AsByteArray(128).get(), 128); password->DataSize = passwordData.GetSize(); password->Data = new uint8[password->DataSize]; memcpy(password->Data, passwordData.GetBuffer(), password->DataSize); _modulesWaitingForData.push(MODULE_PASSWORD); Authentication::ProofRequest* proofRequest = new Authentication::ProofRequest(); proofRequest->Modules.push_back(password); // if has authenticator, send Token module proofRequest->Modules.push_back(thumbprint); AsyncWrite(proofRequest); }