ace/Source/ACE.Database/Models/Auth/AccountExtensions.cs
Ty Conner d311df7e0c
Change BCrypt WorkFactor to configurable Option in Config.js (#1506)
* Change WorkFactor to 8

* Add configuration option for password workfactor, and migration option to support [up/down]grade at runtime

* Fix a default

* Do not pass in values less 4 and greater than 31 to prevent server crash

* Update defaults
2019-03-09 19:52:04 -06:00

105 lines
3.8 KiB
C#

using ACE.Common.Cryptography;
using log4net;
using System;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
namespace ACE.Database.Models.Auth
{
public static class AccountExtensions
{
private static readonly ILog log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public static bool PasswordMatches(this Account account, string password)
{
if (account.PasswordSalt == "use bcrypt") // Account password is using bcrypt
{
if (Common.ConfigManager.Config.Server.Accounts.ForceWorkFactorMigration &&
(BCryptProvider.GetPasswordWorkFactor(account.PasswordHash) != Common.ConfigManager.Config.Server.Accounts.PasswordHashWorkFactor))
// Upgrade (or downgrade) Password workfactor if not the same as config specifies, ForceWorkFactorMigration is TRUE and Password Matches
{
if (BCryptProvider.Verify(password, account.PasswordHash))
{
account.SetPassword(password);
account.SetSaltForBCrypt();
DatabaseManager.Authentication.UpdateAccount(account);
return true;
}
else
return false;
}
else
return BCryptProvider.Verify(password, account.PasswordHash);
}
else // Account password is using SHA512 salt
{
log.Debug($"{account.AccountName} password verified using SHA512 hash/salt, migrating to bcrypt.");
var input = GetPasswordHash(account, password);
if (input == account.PasswordHash) // If password matches, migrate to bcrypt
{
account.SetPassword(password);
account.SetSaltForBCrypt();
DatabaseManager.Authentication.UpdateAccount(account);
return true;
}
else
return false;
}
}
public static void SetPassword(this Account account, string value)
{
account.PasswordHash = GetPasswordHash(value);
}
public static void SetSalt(this Account account, string value)
{
account.PasswordSalt = value;
}
public static void SetSaltForBCrypt(this Account account)
{
SetSalt(account, "use bcrypt"); // this is used just to indicate that the password is using bcrypt. For migration purposes only.
}
private static string GetPasswordHash(string password)
{
var workFactor = Common.ConfigManager.Config.Server.Accounts.PasswordHashWorkFactor;
if (workFactor < 4)
{
log.Warn("PasswordHashWorkFactor in config less than minimum value of 4, using 4 and continuing.");
workFactor = 4;
}
else if (workFactor > 31)
{
log.Warn("PasswordHashWorkFactor in config greater than minimum value of 31, using 31 and continuing.");
workFactor = 31;
}
return BCryptProvider.HashPassword(password, workFactor);
}
private static string GetPasswordHash(Account account, string password)
{
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
byte[] saltBytes = Convert.FromBase64String(account.PasswordSalt);
byte[] buffer = passwordBytes.Concat(saltBytes).ToArray();
byte[] hash;
using (SHA512Managed hasher = new SHA512Managed())
hash = hasher.ComputeHash(buffer);
return Convert.ToBase64String(hash);
}
}
}