Merge pull request #2504 from Pryaxis/h/hashing

Remove DIY password hashing crypto
This commit is contained in:
Lucas Nicodemus 2021-11-22 17:17:15 -08:00 committed by GitHub
commit 6cd69324c7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 3 additions and 75 deletions

View file

@ -14,6 +14,7 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin
## Upcoming changes
* 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
* Updated Linux guide. (@NezbednikSK)

View file

@ -368,11 +368,6 @@ namespace TShockAPI.Configuration
[Description("The minimum password length for new user accounts. Can never be lower than 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.
/// 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.")]

View file

@ -438,7 +438,7 @@ namespace TShockAPI.DB
{
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.
UpgradePasswordWorkFactor(password);
@ -447,35 +447,12 @@ namespace TShockAPI.DB
}
catch (SaltParseException)
{
if (String.Equals(HashPassword(password), Password, StringComparison.InvariantCultureIgnoreCase))
{
// The password is not stored using BCrypt; upgrade it to BCrypt immediately
UpgradePasswordToBCrypt(password);
return true;
}
TShock.Log.ConsoleError("Error: Unable to verify the password hash for user {0} ({1})", Name, ID);
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>
/// <param name="password">The raw user account password (unhashed) to upgrade</param>
protected void UpgradePasswordWorkFactor(string password)
@ -536,51 +513,6 @@ namespace TShockAPI.DB
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
/// <summary>Indicates whether the current <see cref="UserAccount"/> is equal to another <see cref="UserAccount"/>.</summary>