aboutsummaryrefslogtreecommitdiff
path: root/src/server/game
diff options
context:
space:
mode:
authorShauren <shauren.trinity@gmail.com>2023-12-26 14:55:15 +0100
committerShauren <shauren.trinity@gmail.com>2023-12-26 14:55:15 +0100
commit623202d68e862b346b22ac65f9dcbb498d2fa2ac (patch)
treefd882ea858e1668d2f79c1232ea5c0bf50001488 /src/server/game
parent4a61675191c91c7d09def0e612f2e11a646845b0 (diff)
Core/Bnet: Implemented new SRP6 variants, and migrate old sha_pass_hash in battlenet_accounts to separate salt and verifier columns
* passwords can now be case sensitive and up to 128 characters long
Diffstat (limited to 'src/server/game')
-rw-r--r--src/server/game/Accounts/AccountMgr.cpp32
-rw-r--r--src/server/game/Accounts/BattlenetAccountMgr.cpp76
-rw-r--r--src/server/game/Accounts/BattlenetAccountMgr.h3
3 files changed, 67 insertions, 44 deletions
diff --git a/src/server/game/Accounts/AccountMgr.cpp b/src/server/game/Accounts/AccountMgr.cpp
index 0229dd686b4..113e81153ba 100644
--- a/src/server/game/Accounts/AccountMgr.cpp
+++ b/src/server/game/Accounts/AccountMgr.cpp
@@ -29,6 +29,8 @@
#include "World.h"
#include "WorldSession.h"
+using AccountSRP6 = Trinity::Crypto::SRP::GruntSRP6;
+
AccountMgr::AccountMgr() { }
AccountMgr::~AccountMgr()
@@ -60,9 +62,9 @@ AccountOpResult AccountMgr::CreateAccount(std::string username, std::string pass
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_ACCOUNT);
stmt->setString(0, username);
- std::pair<Trinity::Crypto::SRP6::Salt, Trinity::Crypto::SRP6::Verifier> registrationData = Trinity::Crypto::SRP6::MakeRegistrationData(username, password);
- stmt->setBinary(1, registrationData.first);
- stmt->setBinary(2, registrationData.second);
+ auto [salt, verifier] = Trinity::Crypto::SRP6::MakeRegistrationData<AccountSRP6>(username, password);
+ stmt->setBinary(1, salt);
+ stmt->setBinary(2, verifier);
stmt->setString(3, email);
stmt->setString(4, email);
@@ -184,10 +186,10 @@ AccountOpResult AccountMgr::ChangeUsername(uint32 accountId, std::string newUser
stmt->setUInt32(1, accountId);
LoginDatabase.Execute(stmt);
- std::pair<Trinity::Crypto::SRP6::Salt, Trinity::Crypto::SRP6::Verifier> registrationData = Trinity::Crypto::SRP6::MakeRegistrationData(newUsername, newPassword);
+ auto [salt, verifier] = Trinity::Crypto::SRP6::MakeRegistrationData<AccountSRP6>(newUsername, newPassword);
stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGON);
- stmt->setBinary(0, registrationData.first);
- stmt->setBinary(1, registrationData.second);
+ stmt->setBinary(0, salt);
+ stmt->setBinary(1, verifier);
stmt->setUInt32(2, accountId);
LoginDatabase.Execute(stmt);
@@ -212,11 +214,11 @@ AccountOpResult AccountMgr::ChangePassword(uint32 accountId, std::string newPass
Utf8ToUpperOnlyLatin(username);
Utf8ToUpperOnlyLatin(newPassword);
- std::pair<Trinity::Crypto::SRP6::Salt, Trinity::Crypto::SRP6::Verifier> registrationData = Trinity::Crypto::SRP6::MakeRegistrationData(username, newPassword);
+ auto [salt, verifier] = Trinity::Crypto::SRP6::MakeRegistrationData<AccountSRP6>(username, newPassword);
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_LOGON);
- stmt->setBinary(0, registrationData.first);
- stmt->setBinary(1, registrationData.second);
+ stmt->setBinary(0, salt);
+ stmt->setBinary(1, verifier);
stmt->setUInt32(2, accountId);
LoginDatabase.Execute(stmt);
@@ -354,9 +356,9 @@ bool AccountMgr::CheckPassword(std::string username, std::string password)
if (PreparedQueryResult result = LoginDatabase.Query(stmt))
{
- Trinity::Crypto::SRP6::Salt salt = (*result)[0].GetBinary<Trinity::Crypto::SRP6::SALT_LENGTH>();
- Trinity::Crypto::SRP6::Verifier verifier = (*result)[1].GetBinary<Trinity::Crypto::SRP6::VERIFIER_LENGTH>();
- if (Trinity::Crypto::SRP6::CheckLogin(username, password, salt, verifier))
+ Trinity::Crypto::SRP::Salt salt = (*result)[0].GetBinary<Trinity::Crypto::SRP::SALT_LENGTH>();
+ Trinity::Crypto::SRP::Verifier verifier = (*result)[1].GetBinary();
+ if (AccountSRP6(username, salt, verifier).CheckCredentials(username, password))
return true;
}
@@ -378,9 +380,9 @@ bool AccountMgr::CheckPassword(uint32 accountId, std::string password)
if (PreparedQueryResult result = LoginDatabase.Query(stmt))
{
- Trinity::Crypto::SRP6::Salt salt = (*result)[0].GetBinary<Trinity::Crypto::SRP6::SALT_LENGTH>();
- Trinity::Crypto::SRP6::Verifier verifier = (*result)[1].GetBinary<Trinity::Crypto::SRP6::VERIFIER_LENGTH>();
- if (Trinity::Crypto::SRP6::CheckLogin(username, password, salt, verifier))
+ Trinity::Crypto::SRP::Salt salt = (*result)[0].GetBinary<Trinity::Crypto::SRP::SALT_LENGTH>();
+ Trinity::Crypto::SRP::Verifier verifier = (*result)[1].GetBinary();
+ if (AccountSRP6(username, salt, verifier).CheckCredentials(username, password))
return true;
}
diff --git a/src/server/game/Accounts/BattlenetAccountMgr.cpp b/src/server/game/Accounts/BattlenetAccountMgr.cpp
index 08a807b8db6..8b57ac71093 100644
--- a/src/server/game/Accounts/BattlenetAccountMgr.cpp
+++ b/src/server/game/Accounts/BattlenetAccountMgr.cpp
@@ -17,29 +17,41 @@
#include "BattlenetAccountMgr.h"
#include "AccountMgr.h"
-#include "CryptoHash.h"
#include "DatabaseEnv.h"
+#include "SRP6.h"
#include "Util.h"
using GameAccountMgr = AccountMgr;
+using BnetSRP6_OLD = Trinity::Crypto::SRP::BnetSRP6v1<Trinity::Crypto::SHA256>;
+using BnetSRP6 = Trinity::Crypto::SRP::BnetSRP6v2<Trinity::Crypto::SHA256>;
+
+enum class SrpVersion : int8
+{
+ v1 = 1, // password length limit 16 characters, case-insensitive, uses SHA256 to generate verifier
+ v2 = 2 // password length limit 128 characters, case-sensitive, uses PBKDF2 with SHA512 to generate verifier
+};
AccountOpResult Battlenet::AccountMgr::CreateBattlenetAccount(std::string email, std::string password, bool withGameAccount, std::string* gameAccountName)
{
if (utf8length(email) > MAX_BNET_EMAIL_STR)
return AccountOpResult::AOR_NAME_TOO_LONG;
- if (utf8length(password) > MAX_PASS_STR)
+ if (utf8length(password) > MAX_BNET_PASS_STR)
return AccountOpResult::AOR_PASS_TOO_LONG;
Utf8ToUpperOnlyLatin(email);
- Utf8ToUpperOnlyLatin(password);
if (GetId(email))
return AccountOpResult::AOR_NAME_ALREADY_EXIST;
+ std::string srpUsername = GetSrpUsername(email);
+ auto [salt, verifier] = Trinity::Crypto::SRP6::MakeRegistrationData<BnetSRP6>(srpUsername, password);
+
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_INS_BNET_ACCOUNT);
stmt->setString(0, email);
- stmt->setString(1, CalculateShaPassHash(email, password));
+ stmt->setInt8(1, AsUnderlyingType(SrpVersion::v2));
+ stmt->setBinary(2, salt);
+ stmt->setBinary(3, verifier);
LoginDatabase.DirectExecute(stmt);
uint32 newAccountId = GetId(email);
@@ -48,7 +60,9 @@ AccountOpResult Battlenet::AccountMgr::CreateBattlenetAccount(std::string email,
if (withGameAccount)
{
*gameAccountName = std::to_string(newAccountId) + "#1";
- GameAccountMgr::instance()->CreateAccount(*gameAccountName, password, email, newAccountId, 1);
+ std::string gameAccountPassword = password.substr(0, MAX_PASS_STR);
+ Utf8ToUpperOnlyLatin(gameAccountPassword);
+ GameAccountMgr::instance()->CreateAccount(*gameAccountName, gameAccountPassword, email, newAccountId, 1);
}
return AccountOpResult::AOR_OK;
@@ -60,14 +74,17 @@ AccountOpResult Battlenet::AccountMgr::ChangePassword(uint32 accountId, std::str
if (!GetName(accountId, username))
return AccountOpResult::AOR_NAME_NOT_EXIST; // account doesn't exist
- Utf8ToUpperOnlyLatin(username);
- Utf8ToUpperOnlyLatin(newPassword);
- if (utf8length(newPassword) > MAX_PASS_STR)
+ if (utf8length(newPassword) > MAX_BNET_PASS_STR)
return AccountOpResult::AOR_PASS_TOO_LONG;
- LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_PASSWORD);
- stmt->setString(0, CalculateShaPassHash(username, newPassword));
- stmt->setUInt32(1, accountId);
+ std::string srpUsername = GetSrpUsername(username);
+ auto [salt, verifier] = Trinity::Crypto::SRP6::MakeRegistrationData<BnetSRP6>(srpUsername, newPassword);
+
+ LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_LOGON);
+ stmt->setInt8(0, AsUnderlyingType(SrpVersion::v2));
+ stmt->setBinary(1, salt);
+ stmt->setBinary(2, verifier);
+ stmt->setUInt32(3, accountId);
LoginDatabase.Execute(stmt);
return AccountOpResult::AOR_OK;
@@ -80,14 +97,26 @@ bool Battlenet::AccountMgr::CheckPassword(uint32 accountId, std::string password
if (!GetName(accountId, username))
return false;
- Utf8ToUpperOnlyLatin(username);
- Utf8ToUpperOnlyLatin(password);
-
LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_BNET_CHECK_PASSWORD);
stmt->setUInt32(0, accountId);
- stmt->setString(1, CalculateShaPassHash(username, password));
- return LoginDatabase.Query(stmt) != nullptr;
+ if (PreparedQueryResult result = LoginDatabase.Query(stmt))
+ {
+ Trinity::Crypto::SRP::Salt salt = (*result)[1].GetBinary<Trinity::Crypto::SRP::SALT_LENGTH>();
+ Trinity::Crypto::SRP::Verifier verifier = (*result)[2].GetBinary();
+ switch (SrpVersion((*result)[0].GetInt8()))
+ {
+ case SrpVersion::v1:
+ Utf8ToUpperOnlyLatin(password);
+ return BnetSRP6_OLD(username, salt, verifier).CheckCredentials(username, password);
+ case SrpVersion::v2:
+ return BnetSRP6(username, salt, verifier).CheckCredentials(username, password);
+ default:
+ break;
+ }
+ }
+
+ return false;
}
AccountOpResult Battlenet::AccountMgr::LinkWithGameAccount(std::string_view email, std::string_view gameAccountName)
@@ -179,17 +208,8 @@ uint8 Battlenet::AccountMgr::GetMaxIndex(uint32 accountId)
return 0;
}
-std::string Battlenet::AccountMgr::CalculateShaPassHash(std::string_view name, std::string_view password)
+std::string Battlenet::AccountMgr::GetSrpUsername(std::string name)
{
- Trinity::Crypto::SHA256 email;
- email.UpdateData(name);
- email.Finalize();
-
- Trinity::Crypto::SHA256 sha;
- sha.UpdateData(ByteArrayToHexStr(email.GetDigest()));
- sha.UpdateData(":");
- sha.UpdateData(password);
- sha.Finalize();
-
- return ByteArrayToHexStr(sha.GetDigest(), true);
+ Utf8ToUpperOnlyLatin(name);
+ return ByteArrayToHexStr(Trinity::Crypto::SHA256::GetDigestOf(name));
}
diff --git a/src/server/game/Accounts/BattlenetAccountMgr.h b/src/server/game/Accounts/BattlenetAccountMgr.h
index bfeb02302f7..b4fe7626b42 100644
--- a/src/server/game/Accounts/BattlenetAccountMgr.h
+++ b/src/server/game/Accounts/BattlenetAccountMgr.h
@@ -25,6 +25,7 @@ class QueryCallback;
enum class AccountOpResult : uint8;
#define MAX_BNET_EMAIL_STR 320
+#define MAX_BNET_PASS_STR 128
namespace Battlenet
{
@@ -42,7 +43,7 @@ namespace Battlenet
[[nodiscard]] TC_GAME_API QueryCallback GetIdByGameAccountAsync(uint32 gameAccountId);
TC_GAME_API uint8 GetMaxIndex(uint32 accountId);
- TC_GAME_API std::string CalculateShaPassHash(std::string_view name, std::string_view password);
+ TC_GAME_API std::string GetSrpUsername(std::string name);
}
}