Migrate some manual password creation to BCrypt

Note that several times, user.Password was set to a plain text password,
but then later changed to a hashed password, creating data inconsistency.

This also changes User.Password to private set to prevent further accidents.
This commit is contained in:
Lucas Nicodemus 2015-04-13 10:44:45 -06:00
parent a5aa31376a
commit ed34a87c3f
3 changed files with 78 additions and 14 deletions

View file

@ -919,16 +919,18 @@ namespace TShockAPI
try
{
var user = new User();
string echoPassword = "";
if (args.Parameters.Count == 1)
{
user.Name = args.Player.Name;
user.Password = args.Parameters[0];
echoPassword = args.Parameters[0];
user.CreateBCryptHash(args.Parameters[0]);
}
else if (args.Parameters.Count == 2 && TShock.Config.AllowRegisterAnyUsername)
{
user.Name = args.Parameters[0];
user.Password = args.Parameters[1];
echoPassword = args.Parameters[1];
user.CreateBCryptHash(args.Parameters[1]);
}
else
{
@ -942,7 +944,7 @@ namespace TShockAPI
if (TShock.Users.GetUserByName(user.Name) == null && user.Name != TSServerPlayer.AccountName) // Cheap way of checking for existance of a user
{
args.Player.SendSuccessMessage("Account \"{0}\" has been registered.", user.Name);
args.Player.SendSuccessMessage("Your password is {0}.", user.Password);
args.Player.SendSuccessMessage("Your password is {0}.", echoPassword);
TShock.Users.AddUser(user);
TShock.Log.ConsoleInfo("{0} registered an account: \"{1}\".", args.Player.Name, user.Name);
}
@ -976,7 +978,7 @@ namespace TShockAPI
var user = new User();
user.Name = args.Parameters[1];
user.Password = args.Parameters[2];
user.CreateBCryptHash(args.Parameters[2]);
user.Group = args.Parameters[3];
try

View file

@ -21,9 +21,11 @@ using System.CodeDom.Compiler;
using System.Data;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MySql.Data.MySqlClient;
using System.Text.RegularExpressions;
using BCrypt.Net;
using System.Security.Cryptography;
namespace TShockAPI.DB
{
@ -309,7 +311,7 @@ namespace TShockAPI.DB
{
public int ID { get; set; }
public string Name { get; set; }
public string Password { get; set; }
public string Password { get; internal set; }
public string UUID { get; set; }
public string Group { get; set; }
public string Registered { get; set; }
@ -354,7 +356,7 @@ namespace TShockAPI.DB
return true;
}
} catch (SaltParseException) {
if (TShock.Utils.HashPassword(password).ToUpper() == this.Password.ToUpper()) {
if (hashPassword(password).ToUpper() == this.Password.ToUpper()) {
// The password is not stored using BCrypt; upgrade it to BCrypt immediately
upgradePasswordToBCrypt(password);
return true;
@ -406,6 +408,61 @@ namespace TShockAPI.DB
}
}
}
public void CreateBCryptHash(string password) {
try {
this.Password = BCrypt.Net.BCrypt.HashPassword(password, TShock.Config.WorkFactor);
} catch (ArgumentOutOfRangeException) {
TShock.Log.ConsoleError("Invalid BCrypt work factor! Creating new hash using default work factor.");
this.Password = BCrypt.Net.BCrypt.HashPassword(password);
}
}
/// <summary>
/// A dictionary of hashing algortihms and an implementation object.
/// </summary>
internal readonly Dictionary<string, Func<HashAlgorithm>> HashTypes = new Dictionary<string, Func<HashAlgorithm>>
{
{"sha512", () => new SHA512Managed()},
{"sha256", () => new SHA256Managed()},
{"md5", () => new MD5Cng()},
{"sha512-xp", () => SHA512.Create()},
{"sha256-xp", () => SHA256.Create()},
{"md5-xp", () => MD5.Create()},
};
/// <summary>
/// Returns a Sha256 string for a given string
/// </summary>
/// <param name="bytes">bytes to hash</param>
/// <returns>string sha256</returns>
internal string hashPassword(byte[] bytes)
{
if (bytes == null)
throw new NullReferenceException("bytes");
Func<HashAlgorithm> func;
if (!HashTypes.TryGetValue(TShock.Config.HashAlgorithm.ToLower(), out func))
throw new NotSupportedException("Hashing algorithm {0} is not supported".SFormat(TShock.Config.HashAlgorithm.ToLower()));
using (var hash = func())
{
var ret = hash.ComputeHash(bytes);
return ret.Aggregate("", (s, b) => s + b.ToString("X2"));
}
}
/// <summary>
/// Returns a hashed password string for a given string
/// </summary>
/// <param name="password">string to hash</param>
/// <returns>string sha256</returns>
internal string hashPassword(string password)
{
if (string.IsNullOrEmpty(password) || password == "non-existant password")
return null;
return hashPassword(Encoding.UTF8.GetBytes(password));
}
}
[Serializable]

View file

@ -27,6 +27,7 @@ using System.Text;
using System.Text.RegularExpressions;
using Terraria;
using TShockAPI.DB;
using BCrypt.Net;
namespace TShockAPI
{
@ -719,14 +720,16 @@ namespace TShockAPI
ply.SendErrorMessage("Use \"my query\" for items with spaces");
}
/// <summary>
/// Default hashing algorithm.
/// </summary>
public string HashAlgo = "sha512";
/// <summary>
/// Default hashing algorithm.
/// </summary>
[Obsolete("This is no longer necessary, please use TShock.Config.HashAlgorithm instead.")]
public string HashAlgo = "sha512";
/// <summary>
/// A dictionary of hashing algortihms and an implementation object.
/// </summary>
/// <summary>
/// A dictionary of hashing algortihms and an implementation object.
/// </summary>
[Obsolete("This is no longer necessary, after switching to User.VerifyPassword(password) instead.")]
public readonly Dictionary<string, Func<HashAlgorithm>> HashTypes = new Dictionary<string, Func<HashAlgorithm>>
{
{"sha512", () => new SHA512Managed()},
@ -742,6 +745,7 @@ namespace TShockAPI
/// </summary>
/// <param name="bytes">bytes to hash</param>
/// <returns>string sha256</returns>
[Obsolete("Please use User.VerifyPassword(password) instead. Warning: This will upgrade passwords to BCrypt. Already converted passwords will not hash correctly using this method.")]
public string HashPassword(byte[] bytes)
{
if (bytes == null)
@ -762,6 +766,7 @@ namespace TShockAPI
/// </summary>
/// <param name="password">string to hash</param>
/// <returns>string sha256</returns>
[Obsolete("Please use User.VerifyPassword(password) instead. Warning: This will upgrade passwords to BCrypt. Already converted passwords will not hash correctly using this method.")]
public string HashPassword(string password)
{
if (string.IsNullOrEmpty(password) || password == "non-existant password")