Remove DIY password hashing crypto
The old system for hashing passwords and permitting users to select
their algorithm has been deprecated and phased out since 2015. This
removes the remaining functions for hashing passwords to clear the way
for .NET5/6 and for OTAPI 3.
In 211b70ca37, I allowed blank passwords
to upgrade to bcrypt hashes. However, the minimum password length has
been 4 historically for a long time. So I don't actually assume a lot of
users have blank passwords, so I think there are very few, if any of the
old hashes laying around.
So therefore, I think this is pretty much safe to merge.
This commit is contained in:
parent
614211d7a1
commit
9416e8f1e2
3 changed files with 3 additions and 75 deletions
|
|
@ -14,6 +14,7 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin
|
||||||
|
|
||||||
## Upcoming changes
|
## Upcoming changes
|
||||||
* Fixed the `/respawn` command to permit respawning players from the console. (@hakusaro, @Kojirremer)
|
* Fixed the `/respawn` command to permit respawning players from the console. (@hakusaro, @Kojirremer)
|
||||||
|
* Removed the old password hashing system, which predated `bcrypt` hashes and allowed specifying the hash algorithm in the config file. This also removes the config option for setting the hash algorithm (`HashAlgorithm`). This is because it helps clear the way for .NET5/6 and OTAPI 3, and because `bcrypt` has been the default since TShock 4.3 in 2015. (@hakusaro)
|
||||||
|
|
||||||
## TShock 4.5.6
|
## TShock 4.5.6
|
||||||
* Updated Linux guide. (@NezbednikSK)
|
* Updated Linux guide. (@NezbednikSK)
|
||||||
|
|
|
||||||
|
|
@ -368,11 +368,6 @@ namespace TShockAPI.Configuration
|
||||||
[Description("The minimum password length for new user accounts. Can never be lower than 4.")]
|
[Description("The minimum password length for new user accounts. Can never be lower than 4.")]
|
||||||
public int MinimumPasswordLength = 4;
|
public int MinimumPasswordLength = 4;
|
||||||
|
|
||||||
/// <summary>The hash algorithm used to encrypt user passwords.
|
|
||||||
/// Valid types: "sha512", "sha256" and "md5". Append with "-xp" for the xp supported algorithms.</summary>
|
|
||||||
[Description("The hash algorithm used to encrypt user passwords. Valid types: \"sha512\", \"sha256\" and \"md5\". Append with \"-xp\" for the xp supported algorithms.")]
|
|
||||||
public string HashAlgorithm = "sha512";
|
|
||||||
|
|
||||||
/// <summary>Determines the BCrypt work factor to use. If increased, all passwords will be upgraded to new work-factor on verify.
|
/// <summary>Determines the BCrypt work factor to use. If increased, all passwords will be upgraded to new work-factor on verify.
|
||||||
/// The number of computational rounds is 2^n. Increase with caution. Range: 5-31.</summary>
|
/// The number of computational rounds is 2^n. Increase with caution. Range: 5-31.</summary>
|
||||||
[Description("Determines the BCrypt work factor to use. If increased, all passwords will be upgraded to new work-factor on verify. The number of computational rounds is 2^n. Increase with caution. Range: 5-31.")]
|
[Description("Determines the BCrypt work factor to use. If increased, all passwords will be upgraded to new work-factor on verify. The number of computational rounds is 2^n. Increase with caution. Range: 5-31.")]
|
||||||
|
|
|
||||||
|
|
@ -438,7 +438,7 @@ namespace TShockAPI.DB
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (BCrypt.Net.BCrypt.Verify(password, Password))
|
if (BCrypt.Net.BCrypt.Verify(password, Password))
|
||||||
{
|
{
|
||||||
// If necessary, perform an upgrade to the highest work factor.
|
// If necessary, perform an upgrade to the highest work factor.
|
||||||
UpgradePasswordWorkFactor(password);
|
UpgradePasswordWorkFactor(password);
|
||||||
|
|
@ -447,35 +447,12 @@ namespace TShockAPI.DB
|
||||||
}
|
}
|
||||||
catch (SaltParseException)
|
catch (SaltParseException)
|
||||||
{
|
{
|
||||||
if (String.Equals(HashPassword(password), Password, StringComparison.InvariantCultureIgnoreCase))
|
TShock.Log.ConsoleError("Error: Unable to verify the password hash for user {0} ({1})", Name, ID);
|
||||||
{
|
|
||||||
// The password is not stored using BCrypt; upgrade it to BCrypt immediately
|
|
||||||
UpgradePasswordToBCrypt(password);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Upgrades a password to BCrypt, from an insecure hashing algorithm.</summary>
|
|
||||||
/// <param name="password">The raw user account password (unhashed) to upgrade</param>
|
|
||||||
protected void UpgradePasswordToBCrypt(string password)
|
|
||||||
{
|
|
||||||
// Save the old password, in the event that we have to revert changes.
|
|
||||||
string oldpassword = Password;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
TShock.UserAccounts.SetUserAccountPassword(this, password);
|
|
||||||
}
|
|
||||||
catch (UserAccountManagerException e)
|
|
||||||
{
|
|
||||||
TShock.Log.ConsoleError(e.ToString());
|
|
||||||
Password = oldpassword; // Revert changes
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Upgrades a password to the highest work factor available in the config.</summary>
|
/// <summary>Upgrades a password to the highest work factor available in the config.</summary>
|
||||||
/// <param name="password">The raw user account password (unhashed) to upgrade</param>
|
/// <param name="password">The raw user account password (unhashed) to upgrade</param>
|
||||||
protected void UpgradePasswordWorkFactor(string password)
|
protected void UpgradePasswordWorkFactor(string password)
|
||||||
|
|
@ -536,51 +513,6 @@ namespace TShockAPI.DB
|
||||||
Password = BCrypt.Net.BCrypt.HashPassword(password.Trim(), workFactor);
|
Password = BCrypt.Net.BCrypt.HashPassword(password.Trim(), workFactor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A dictionary of hashing algorithms and an implementation object.
|
|
||||||
/// </summary>
|
|
||||||
protected 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 hashed string for a given string based on the config file's hash algo
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="bytes">bytes to hash</param>
|
|
||||||
/// <returns>string hash</returns>
|
|
||||||
protected string HashPassword(byte[] bytes)
|
|
||||||
{
|
|
||||||
if (bytes == null)
|
|
||||||
throw new NullReferenceException("bytes");
|
|
||||||
Func<HashAlgorithm> func;
|
|
||||||
if (!HashTypes.TryGetValue(TShock.Config.Settings.HashAlgorithm.ToLower(), out func))
|
|
||||||
throw new NotSupportedException("Hashing algorithm {0} is not supported".SFormat(TShock.Config.Settings.HashAlgorithm.ToLower()));
|
|
||||||
|
|
||||||
using (var hash = func())
|
|
||||||
{
|
|
||||||
var ret = hash.ComputeHash(bytes);
|
|
||||||
return ret.Aggregate("", (s, b) => s + b.ToString("X2"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a hashed string for a given string based on the config file's hash algo
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="password">string to hash</param>
|
|
||||||
/// <returns>string hash</returns>
|
|
||||||
protected string HashPassword(string password)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(password) && Password == "non-existant password")
|
|
||||||
return "non-existant password";
|
|
||||||
return HashPassword(Encoding.UTF8.GetBytes(password));
|
|
||||||
}
|
|
||||||
|
|
||||||
#region IEquatable
|
#region IEquatable
|
||||||
|
|
||||||
/// <summary>Indicates whether the current <see cref="UserAccount"/> is equal to another <see cref="UserAccount"/>.</summary>
|
/// <summary>Indicates whether the current <see cref="UserAccount"/> is equal to another <see cref="UserAccount"/>.</summary>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue