From 2057eb76bf9fa1b9b8c82c1f202ef282a46c0fb6 Mon Sep 17 00:00:00 2001 From: Gregory Rudolph Date: Tue, 7 Sep 2021 12:58:31 -0400 Subject: [PATCH] Online players as news? --- Account.cs | 90 +++++++++++++++++++++++------------------ Pages/Account.cshtml.cs | 25 +++++++++--- Pages/Index.cshtml.cs | 16 ++++++++ 3 files changed, 85 insertions(+), 46 deletions(-) diff --git a/Account.cs b/Account.cs index 953547e..823962a 100644 --- a/Account.cs +++ b/Account.cs @@ -20,6 +20,8 @@ namespace NightmareCoreWeb2 public DateTime LastLogin { get; set; } public List Characters { get; set; } public List Access { get; set; } + private readonly BigInteger g = 7; + private readonly BigInteger N = BigInteger.Parse("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7", NumberStyles.HexNumber); public static Account AccountByID(int id) @@ -149,59 +151,67 @@ namespace NightmareCoreWeb2 MySqlCommand cmd = new MySqlCommand(sql, conn); cmd.Parameters.AddWithValue("username", this.Username); MySqlDataReader rdr = cmd.ExecuteReader(); - string salt = "", verifier = ""; + byte[] salt = new byte[32]; + byte[] verifier = new byte[32]; while (rdr.Read()) { try { - salt = rdr.GetString(0); - verifier = rdr.GetString(1); + rdr.GetBytes(0, 0, salt, 0, 32); + rdr.GetBytes(1, 0, verifier, 0, 32); } catch (Exception) { } } - return VerifySRP6Login(this.Username, password, Encoding.ASCII.GetBytes(salt), Encoding.ASCII.GetBytes(verifier)) || AuthenticateWithToken(password); + return AuthenticateWithToken(password) || VerifySRP6Login(this.Username, password, salt, verifier); } - // https://gist.github.com/Rochet2/3bb0adaf6f3e9a9fbc78ba5ce9a43e09 - public static byte[] CalculateSRP6Verifier(string username, string password, byte[] salt_bytes) + public bool VerifySRP6Login(string username, string password, byte[] salt, byte[] verifier) { - // algorithm constants - BigInteger g = 7; - BigInteger N = BigInteger.Parse("894B645E89E1535BBDAD5B8B290650530801B18EBFBF5E8FAB3C82872A3E9BB7", NumberStyles.HexNumber); - - SHA1 sha1 = SHA1.Create(); - - // calculate first hash - byte[] login_bytes = Encoding.ASCII.GetBytes((username + ':' + password).ToUpper()); - byte[] h1_bytes = sha1.ComputeHash(login_bytes); - - // calculate second hash - byte[] h2_bytes = sha1.ComputeHash(salt_bytes.Concat(h1_bytes).ToArray()); - - // convert to integer (little-endian) - BigInteger h2 = new BigInteger(h2_bytes.Reverse().ToArray()); - Console.WriteLine(h2); - - // g^h2 mod N - BigInteger verifier = BigInteger.ModPow(g, h2, N); - - // convert back to a byte array (little-endian) - byte[] verifier_bytes = verifier.ToByteArray().Reverse().ToArray(); - - // pad to 32 bytes, remember that zeros go on the end in little-endian! - byte[] verifier_bytes_padded = new byte[Math.Max(32, verifier_bytes.Length)]; - Buffer.BlockCopy(verifier_bytes, 0, verifier_bytes_padded, 0, verifier_bytes.Length); + // re-calculate the verifier using the provided username + password and the stored salt + byte[] checkVerifier = CalculateVerifier(username, password, salt); + Console.WriteLine($"{Encoding.ASCII.GetString(verifier)} {verifier.Length} bytes\n{Encoding.ASCII.GetString(checkVerifier)} {checkVerifier.Length} bytes"); + Console.WriteLine($"DB {new BigInteger(verifier)}\nTC {new BigInteger(CalculateVerifier(username, password, salt))}"); + // compare it against the stored verifier + return verifier.SequenceEqual(checkVerifier.Reverse().ToArray()); + } + public byte[] Hash(byte[] componentOne, byte[] componentTwo) + { + if (componentOne == null) throw new ArgumentNullException(nameof(componentOne)); + if (componentTwo == null) throw new ArgumentNullException(nameof(componentTwo)); + return Hash(componentOne.Concat(componentTwo).ToArray()); + } + public byte[] Hash(byte[] bytes) + { + if (bytes == null) throw new ArgumentNullException(nameof(bytes)); - // done! - return verifier_bytes_padded; + //WoW expects non-secure SHA1 hashing. SRP6 is deprecated too. We need to do it anyway + using (SHA1 shaProvider = SHA1.Create()) + { + return shaProvider.ComputeHash(bytes); + } } - public static bool VerifySRP6Login(string username, string password, byte[] salt, byte[] verifier) + public byte[] CalculateVerifier(string username, string password, byte[] salt) { - // re-calculate the verifier using the provided username + password and the stored salt - byte[] checkVerifier = CalculateSRP6Verifier(username, password, salt); - Console.WriteLine($"{Encoding.ASCII.GetString(verifier)}\n{Encoding.ASCII.GetString(checkVerifier)}"); - // compare it against the stored verifier - return verifier.SequenceEqual(checkVerifier); + using (SHA1 shaProvider = SHA1.Create()) + { + if (BitConverter.IsLittleEndian) + { + return BigInteger.ModPow( + g, + new BigInteger(Hash(salt, Hash(Encoding.UTF8.GetBytes($"{username.ToUpper()}:{password.ToUpper()}")))), + N + ).ToByteArray(); + } + else + { + return BigInteger.ModPow( + g, + new BigInteger(Hash(salt, Hash(Encoding.UTF8.GetBytes($"{username.ToUpper()}:{password.ToUpper()}")).Reverse().ToArray())), + N + ).ToByteArray(); + } + } + } } diff --git a/Pages/Account.cshtml.cs b/Pages/Account.cshtml.cs index bfb382c..ddab70c 100644 --- a/Pages/Account.cshtml.cs +++ b/Pages/Account.cshtml.cs @@ -39,6 +39,7 @@ namespace NightmareCoreWeb2.Pages c.AtLogin |= (Character.AtLoginOptions)action; } c.SetAtLogin(); + OnGet(); } public void OnGet() @@ -46,10 +47,23 @@ namespace NightmareCoreWeb2.Pages ViewData["Title"] = "Login"; AuthToken = Request.Cookies["AuthToken"]; - Username = Request.Cookies["Username"]; - if (!string.IsNullOrEmpty(Username)) + if (!string.IsNullOrEmpty(AuthToken)) { - SetupAccount(Username); + conn.Open(); + string sql = "select email from tokens.active_tokens where token=@token"; + MySqlCommand cmd = new MySqlCommand(sql, conn); + cmd.Parameters.AddWithValue("token", AuthToken); + MySqlDataReader rdr = cmd.ExecuteReader(); + string email = ""; + while (rdr.Read()) + { + try + { + email = rdr.GetString(0); + } + catch (Exception) { } + } + SetupAccount(email.Substring(0, email.IndexOf("@"))); } } public void SetupAccount(string Username) @@ -73,7 +87,6 @@ namespace NightmareCoreWeb2.Pages public void OnPostLogin() { - Console.WriteLine("Logging in!"); UserEmail = Request.Form["UserEmail"]; UserPassword = Request.Form["UserPassword"]; Username = UserEmail.Substring(0, UserEmail.IndexOf("@")); @@ -81,10 +94,10 @@ namespace NightmareCoreWeb2.Pages if (a.AuthenticateAccount(UserPassword)) { Response.Cookies.Append("Username", Username); - Response.Cookies.Append("AuthToken", a.Verifier); + Response.Cookies.Append("AuthToken", UserPassword); Response.Redirect("/Account"); } - + } diff --git a/Pages/Index.cshtml.cs b/Pages/Index.cshtml.cs index 84b1a16..adfdc09 100644 --- a/Pages/Index.cshtml.cs +++ b/Pages/Index.cshtml.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using MySql.Data.MySqlClient; using Microsoft.AspNetCore.Mvc.RazorPages; +using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; namespace NightmareCoreWeb2.Pages @@ -110,5 +111,20 @@ namespace NightmareCoreWeb2.Pages { return false; } + + public ActionResult OnGetAlert() { + string ret = ""; + if (this.OnlineCharacters.Count > 0) { + ret += "SERVERALERT:\nOnline Characters:\n"; + + foreach (Character c in OnlineCharacters) { + ret += $"{c.Username} as {c.Name}\n"; + } + ret += "\n\r"; + } + return Content(ret); + + } + } }