SRP6 testing
This commit is contained in:
75
Account.cs
75
Account.cs
@ -1,6 +1,12 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Text;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Security.Cryptography;
|
||||||
using MySql.Data.MySqlClient;
|
using MySql.Data.MySqlClient;
|
||||||
|
using System.Globalization;
|
||||||
|
using MiscUtil.Conversion;
|
||||||
|
|
||||||
namespace NightmareCoreWeb2
|
namespace NightmareCoreWeb2
|
||||||
{
|
{
|
||||||
@ -11,6 +17,7 @@ namespace NightmareCoreWeb2
|
|||||||
public string Username { get; set; }
|
public string Username { get; set; }
|
||||||
public string Email { get; set; }
|
public string Email { get; set; }
|
||||||
public string LastIP { get; set; }
|
public string LastIP { get; set; }
|
||||||
|
public string Verifier {get; set;}
|
||||||
public DateTime LastLogin { get; set; }
|
public DateTime LastLogin { get; set; }
|
||||||
public List<Character> Characters { get; set; }
|
public List<Character> Characters { get; set; }
|
||||||
public List<AccountAccess> Access { get; set; }
|
public List<AccountAccess> Access { get; set; }
|
||||||
@ -46,7 +53,7 @@ namespace NightmareCoreWeb2
|
|||||||
MySqlConnection conn = new MySqlConnection(Program.connStr);
|
MySqlConnection conn = new MySqlConnection(Program.connStr);
|
||||||
conn.Open();
|
conn.Open();
|
||||||
|
|
||||||
string sql = "select id,username,email,last_ip,last_login from account where username=@username";
|
string sql = "select id,username,email,last_ip,last_login,verifier from account where username=@username";
|
||||||
MySqlCommand cmd = new MySqlCommand(sql, conn);
|
MySqlCommand cmd = new MySqlCommand(sql, conn);
|
||||||
cmd.Parameters.AddWithValue("username", username);
|
cmd.Parameters.AddWithValue("username", username);
|
||||||
MySqlDataReader rdr = cmd.ExecuteReader();
|
MySqlDataReader rdr = cmd.ExecuteReader();
|
||||||
@ -60,6 +67,7 @@ namespace NightmareCoreWeb2
|
|||||||
this.Email = rdr.GetString(2);
|
this.Email = rdr.GetString(2);
|
||||||
this.LastIP = rdr.GetString(3);
|
this.LastIP = rdr.GetString(3);
|
||||||
this.LastLogin = rdr.GetDateTime(4);
|
this.LastLogin = rdr.GetDateTime(4);
|
||||||
|
this.Verifier = rdr.GetString(5);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@ -116,10 +124,75 @@ namespace NightmareCoreWeb2
|
|||||||
conn.Close();
|
conn.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool AuthenticateAccount(string password)
|
||||||
|
{
|
||||||
|
MySqlConnection conn = new MySqlConnection(Program.connStr);
|
||||||
|
conn.Open();
|
||||||
|
string sql = "select salt,verifier from account where username=@username";
|
||||||
|
MySqlCommand cmd = new MySqlCommand(sql, conn);
|
||||||
|
cmd.Parameters.AddWithValue("username", this.Username);
|
||||||
|
MySqlDataReader rdr = cmd.ExecuteReader();
|
||||||
|
string salt = "", verifier = "";
|
||||||
|
while (rdr.Read())
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
salt = rdr.GetString(0);
|
||||||
|
verifier = rdr.GetString(1);
|
||||||
}
|
}
|
||||||
|
catch (Exception) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
return VerifySRP6Login(this.Username, password, Encoding.ASCII.GetBytes(salt), Encoding.ASCII.GetBytes(verifier));
|
||||||
|
}
|
||||||
|
// https://gist.github.com/Rochet2/3bb0adaf6f3e9a9fbc78ba5ce9a43e09
|
||||||
|
public static byte[] CalculateSRP6Verifier(string username, string password, byte[] salt_bytes)
|
||||||
|
{
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// done!
|
||||||
|
return verifier_bytes_padded;
|
||||||
|
}
|
||||||
|
public static bool VerifySRP6Login(string username, string password, byte[] salt, byte[] verifier)
|
||||||
|
{
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public class AccountAccess
|
public class AccountAccess
|
||||||
{
|
{
|
||||||
public int SecurityLevel { get; set; }
|
public int SecurityLevel { get; set; }
|
||||||
public int RealmID { get; set; }
|
public int RealmID { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -6,6 +6,12 @@
|
|||||||
@if (string.IsNullOrEmpty(Model.AuthToken))
|
@if (string.IsNullOrEmpty(Model.AuthToken))
|
||||||
{
|
{
|
||||||
<div id="LoginForm">
|
<div id="LoginForm">
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-header">
|
||||||
|
<h6>Login</h6>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
<form action="?handler=Login" method="post" enctype="multipart/form-data">
|
<form action="?handler=Login" method="post" enctype="multipart/form-data">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="UserEmail">E-mail:</label>
|
<label for="UserEmail">E-mail:</label>
|
||||||
@ -15,8 +21,17 @@
|
|||||||
<label for="UserPassword">Password:</label>
|
<label for="UserPassword">Password:</label>
|
||||||
<input asp-for="UserPassword" type="password" id="UserPassword">
|
<input asp-for="UserPassword" type="password" id="UserPassword">
|
||||||
</div>
|
</div>
|
||||||
|
<input type="submit">
|
||||||
|
@Html.AntiForgeryToken()
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -55,10 +70,14 @@
|
|||||||
<p class="card-text">@ticket.Description</p>
|
<p class="card-text">@ticket.Description</p>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<a class="btn active" href="/Account?handler=CharacterAction&guid=@ticket.Id&action=1">Rename Character</a>
|
<a class="btn active" href="/Account?handler=CharacterAction&guid=@ticket.Id&action=1">Rename
|
||||||
<a class="btn active" href="/Account?handler=CharacterAction&guid=@ticket.Id&action=8">Recustomize Character</a>
|
Character</a>
|
||||||
<a class="btn active" href="/Account?handler=CharacterAction&guid=@ticket.Id&action=64">Change Faction</a>
|
<a class="btn active"
|
||||||
<a class="btn active" href="/Account?handler=CharacterAction&guid=@ticket.Id&action=128">Change Race</a>
|
href="/Account?handler=CharacterAction&guid=@ticket.Id&action=8">Recustomize Character</a>
|
||||||
|
<a class="btn active" href="/Account?handler=CharacterAction&guid=@ticket.Id&action=64">Change
|
||||||
|
Faction</a>
|
||||||
|
<a class="btn active" href="/Account?handler=CharacterAction&guid=@ticket.Id&action=128">Change
|
||||||
|
Race</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer text-muted">
|
<div class="card-footer text-muted">
|
||||||
<p>Opened @ticket.CreateTime.ToLocalTime()</p>
|
<p>Opened @ticket.CreateTime.ToLocalTime()</p>
|
||||||
@ -79,10 +98,15 @@
|
|||||||
<h6>@character.Name</h6>
|
<h6>@character.Name</h6>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<a class="btn active" href="/Account?handler=CharacterAction&guid=@character.guid&action=1">Rename Character</a>
|
<a class="btn active"
|
||||||
<a class="btn active" href="/Account?handler=CharacterAction&guid=@character.guid&action=8">Recustomize Character</a>
|
href="/Account?handler=CharacterAction&guid=@character.guid&action=1">Rename Character</a>
|
||||||
<a class="btn active" href="/Account?handler=CharacterAction&guid=@character.guid&action=64">Change Faction</a>
|
<a class="btn active"
|
||||||
<a class="btn active" href="/Account?handler=CharacterAction&guid=@character.guid&action=128">Change Race</a>
|
href="/Account?handler=CharacterAction&guid=@character.guid&action=8">Recustomize
|
||||||
|
Character</a>
|
||||||
|
<a class="btn active"
|
||||||
|
href="/Account?handler=CharacterAction&guid=@character.guid&action=64">Change Faction</a>
|
||||||
|
<a class="btn active"
|
||||||
|
href="/Account?handler=CharacterAction&guid=@character.guid&action=128">Change Race</a>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-footer text-muted">
|
<div class="card-footer text-muted">
|
||||||
<p>Level @character.Level @character.GetRace() @character.GetClass()</p>
|
<p>Level @character.Level @character.GetRace() @character.GetClass()</p>
|
||||||
|
|||||||
@ -88,13 +88,17 @@ namespace NightmareCoreWeb2.Pages
|
|||||||
|
|
||||||
public void OnPostLogin()
|
public void OnPostLogin()
|
||||||
{
|
{
|
||||||
|
Console.WriteLine("Logging in!");
|
||||||
UserEmail = Request.Form["UserEmail"];
|
UserEmail = Request.Form["UserEmail"];
|
||||||
UserPassword = Request.Form["UserPassword"];
|
UserPassword = Request.Form["UserPassword"];
|
||||||
Username = UserEmail.Substring(0, UserEmail.IndexOf("@"));
|
Username = UserEmail.Substring(0, UserEmail.IndexOf("@"));
|
||||||
AuthToken = Hash($"{Username.ToUpper()}:{UserPassword.ToUpper()}");
|
Account a = new Account(Username);
|
||||||
|
if (a.AuthenticateAccount(UserPassword))
|
||||||
|
{
|
||||||
Response.Cookies.Append("Username", Username);
|
Response.Cookies.Append("Username", Username);
|
||||||
Response.Cookies.Append("AuthToken", AuthToken);
|
Response.Cookies.Append("AuthToken", a.Verifier);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static string Hash(string input)
|
static string Hash(string input)
|
||||||
|
|||||||
Reference in New Issue
Block a user