Add password verification for BCrypt
This commit is contained in:
parent
782b59f2b3
commit
a5aa31376a
2 changed files with 82 additions and 9 deletions
|
|
@ -398,6 +398,9 @@ namespace TShockAPI
|
||||||
[Description("Determines if the server should save the world if the last player exits.")]
|
[Description("Determines if the server should save the world if the last player exits.")]
|
||||||
public bool SaveWorldOnLastPlayerExit = true;
|
public bool SaveWorldOnLastPlayerExit = true;
|
||||||
|
|
||||||
|
[Description("Determines the BCrypt work factor to use. If increased, all passwords will be upgraded to new work-factor on verify. Range: 5-31.")]
|
||||||
|
public int WorkFactor = 10;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Reads a configuration file from a given path
|
/// Reads a configuration file from a given path
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using MySql.Data.MySqlClient;
|
using MySql.Data.MySqlClient;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using BCrypt.Net;
|
||||||
|
|
||||||
namespace TShockAPI.DB
|
namespace TShockAPI.DB
|
||||||
{
|
{
|
||||||
|
|
@ -309,32 +310,101 @@ namespace TShockAPI.DB
|
||||||
public int ID { get; set; }
|
public int ID { get; set; }
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
public string UUID { get; set; }
|
public string UUID { get; set; }
|
||||||
public string Group { get; set; }
|
public string Group { get; set; }
|
||||||
public string Registered { get; set; }
|
public string Registered { get; set; }
|
||||||
public string LastAccessed { get; set; }
|
public string LastAccessed { get; set; }
|
||||||
public string KnownIps { get; set; }
|
public string KnownIps { get; set; }
|
||||||
|
|
||||||
public User(string name, string pass, string uuid, string group, string registered, string last, string known)
|
public User(string name, string pass, string uuid, string group, string registered, string last, string known)
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
Password = pass;
|
Password = pass;
|
||||||
UUID = uuid;
|
UUID = uuid;
|
||||||
Group = group;
|
Group = group;
|
||||||
Registered = registered;
|
Registered = registered;
|
||||||
LastAccessed = last;
|
LastAccessed = last;
|
||||||
KnownIps = known;
|
KnownIps = known;
|
||||||
}
|
}
|
||||||
|
|
||||||
public User()
|
public User()
|
||||||
{
|
{
|
||||||
Name = "";
|
Name = "";
|
||||||
Password = "";
|
Password = "";
|
||||||
UUID = "";
|
UUID = "";
|
||||||
Group = "";
|
Group = "";
|
||||||
Registered = "";
|
Registered = "";
|
||||||
LastAccessed = "";
|
LastAccessed = "";
|
||||||
KnownIps = "";
|
KnownIps = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verifies if a password matches the one stored in the database.
|
||||||
|
/// If the password is stored in an unsafe hashing algorithm, it will be converted to BCrypt.
|
||||||
|
/// If the password is stored using BCrypt, it will be re-saved if the work factor in the config
|
||||||
|
/// is greater than the existing work factor with the new work factor.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="password">string password - The password to check against the user object.</param>
|
||||||
|
/// <returns>bool true, if the password matched, or false, if it didn't.</returns>
|
||||||
|
public bool VerifyPassword(string password) {
|
||||||
|
try {
|
||||||
|
if (BCrypt.Net.BCrypt.Verify(password, this.Password)) {
|
||||||
|
// If necessary, perform an upgrade to the highest work factor.
|
||||||
|
upgradePasswordWorkFactor(password);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (SaltParseException) {
|
||||||
|
if (TShock.Utils.HashPassword(password).ToUpper() == this.Password.ToUpper()) {
|
||||||
|
// The password is not stored using BCrypt; upgrade it to BCrypt immediately
|
||||||
|
upgradePasswordToBCrypt(password);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Upgrades a password to BCrypt, from an insecure hashing algorithm.</summary>
|
||||||
|
/// <param name="password">string password - the raw user password (unhashed) to upgrade</param>
|
||||||
|
internal void upgradePasswordToBCrypt(string password) {
|
||||||
|
// Save the old password, in the event that we have to revert changes.
|
||||||
|
string oldpassword = this.Password;
|
||||||
|
|
||||||
|
// Convert the password to BCrypt, and save it.
|
||||||
|
try {
|
||||||
|
this.Password = BCrypt.Net.BCrypt.HashPassword(password, TShock.Config.WorkFactor);
|
||||||
|
} catch (ArgumentOutOfRangeException) {
|
||||||
|
TShock.Log.ConsoleError("Invalid BCrypt work factor! Upgrading user password to BCrypt using default work factor.");
|
||||||
|
this.Password = BCrypt.Net.BCrypt.HashPassword(password);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
TShock.Users.SetUserPassword(this, this.Password);
|
||||||
|
} catch (UserManagerException e) {
|
||||||
|
TShock.Log.ConsoleError(e.ToString());
|
||||||
|
this.Password = oldpassword; // Revert changes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Upgrades a password to the highest work factor available in the config.</summary>
|
||||||
|
/// <param name="password">string password - the raw user password (unhashed) to upgrade</param>
|
||||||
|
internal void upgradePasswordWorkFactor(string password) {
|
||||||
|
// If the destination work factor is not greater, we won't upgrade it or re-hash it
|
||||||
|
int currentWorkFactor = Convert.ToInt32(this.Password.Split(new Char[] {'$'})[1]);
|
||||||
|
|
||||||
|
if (currentWorkFactor < TShock.Config.WorkFactor) {
|
||||||
|
try {
|
||||||
|
this.Password = BCrypt.Net.BCrypt.HashPassword(password, TShock.Config.WorkFactor);
|
||||||
|
} catch (ArgumentOutOfRangeException) {
|
||||||
|
TShock.Log.ConsoleError("Invalid BCrypt work factor! Refusing to change work-factor on exsting password.");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
TShock.Users.SetUserPassword(this, this.Password);
|
||||||
|
} catch (UserManagerException e) {
|
||||||
|
TShock.Log.ConsoleError(e.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue