I'm trying to implement a custom store for passwords. Before changing a password, I need to check first whether the password has been used last 8 times the user changed the password.
var hashingAlgorithm = ConfigurationManager.AppSettings("MembershipProviderHashAlgorithm");
var hashedPasswordDetails = pwdHistory.GetRecentPasswordDetails(userName);
foreach (var passwordDetails_loopVariable in hashedPasswordDetails)
{
passwordDetails = passwordDetails_loopVariable;
var encodedPassword = pwdEncr
.EncodePassword(proposedNewPassword, passwordDetails.Salt, hashingAlgorithm);
var hashedPassword = passwordDetails.HashedPassword;
if (hashedPassword.Equals(encodedPassword)) //This line always return FALSE.
{
return true;
}
}
return false;
The problem I'm having is that the passwords returned from the tables are always different from what I type (event when in clear there are the same). That's because of the Hashing Algorithm.
I've tried SHA and SHA1 with no luck. Is there a particular hashing algorithm that ASP.NEt membership uses? I'm using System.Web.Security.SqlMembershipProvider version 4.0.0.0
<add key="MembershipProviderHashAlgorithm" value="SHA" />
Thanks for helping.
Here's part of configuration from the membership section in the web.config. Is there a way to tell which algorithm's being used.
<membership defaultProvider="SqlProvider" userIsOnlineTimeWindow="15">
<providers>
<clear />
<add name="SqlProvider" type="System.Web.Security.SqlMembershipProvider,
System.Web, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a"
connectionStringName="myConnectionString"
../..
requiresUniqueEmail="false"
passwordFormat="Hashed"
maxInvalidPasswordAttempts="5"
minRequiredPasswordLength="7"
passwordAttemptWindow="10"/>
</providers>
</membership>
The default password hasher for ASP.NET Core Identity uses PBKDF2 for password hashing. While PBKDF2 is not the worst choice, there are certainly better password hashing algorithms available to you, such as bcrypt, scrypt, and Argon2.
Some common hashing algorithms include MD5, SHA-1, SHA-2, NTLM, and LANMAN. MD5: This is the fifth version of the Message Digest algorithm. MD5 creates 128-bit outputs. MD5 was a very commonly used hashing algorithm.
There are many hashing algorithms that people have used to hash passwords. Two of the most common hashing algorithms you may have come across are MD5 and the SHA-* family of algorithms (SHA-1, SHA-2, SHA-3), but there are several reasons not to use these. For starters, they are extremely fast.
What is the most commonly used Hash today? SHA-256 or SHA 512 Both have the same bit size as there name implies.
Membership Provider uses the following Algorithms to hash password.
Default hash will vary based on the version of Membership Provider.
MVC 4 and ASP.NET 4 and 4.5 default hash is SHA256 (HMACSHA256).
public string EncodePassword(string pass,
MembershipPasswordFormat passwordFormat, string salt)
{
byte[] numArray;
byte[] numArray1;
string base64String;
if (passwordFormat == MembershipPasswordFormat.Hashed)
{
byte[] bytes = Encoding.Unicode.GetBytes(pass);
byte[] numArray2 = Convert.FromBase64String(salt);
byte[] numArray3;
// Hash password
HashAlgorithm hashAlgorithm = HashAlgorithm.Create(Membership.HashAlgorithmType);
if (hashAlgorithm as KeyedHashAlgorithm == null)
{
numArray1 = new byte[numArray2.Length + bytes.Length];
Buffer.BlockCopy(numArray2, 0, numArray1, 0, numArray2.Length);
Buffer.BlockCopy(bytes, 0, numArray1, numArray2.Length, bytes.Length);
numArray3 = hashAlgorithm.ComputeHash(numArray1);
}
else
{
KeyedHashAlgorithm keyedHashAlgorithm = (KeyedHashAlgorithm)hashAlgorithm;
if (keyedHashAlgorithm.Key.Length != numArray2.Length)
{
if (keyedHashAlgorithm.Key.Length >= numArray2.Length)
{
numArray = new byte[keyedHashAlgorithm.Key.Length];
int num = 0;
while (true)
{
if (!(num < numArray.Length))
{
break;
}
int num1 = Math.Min(numArray2.Length, numArray.Length - num);
Buffer.BlockCopy(numArray2, 0, numArray, num, num1);
num = num + num1;
}
keyedHashAlgorithm.Key = numArray;
}
else
{
numArray = new byte[keyedHashAlgorithm.Key.Length];
Buffer.BlockCopy(numArray2, 0, numArray, 0, numArray.Length);
keyedHashAlgorithm.Key = numArray;
}
}
else
{
keyedHashAlgorithm.Key = numArray2;
}
numArray3 = keyedHashAlgorithm.ComputeHash(bytes);
}
base64String = Convert.ToBase64String(numArray3);
}
else if (passwordFormat == MembershipPasswordFormat.Encrypted)
{
throw new NotImplementedException("Encrypted password method is not supported.");
}
else
{
base64String = pass;
}
return base64String;
}
Default hash algorithm is SHA-1.
private string EncodePassword(string pass, int passwordFormat, string salt)
{
if (passwordFormat == 0) // MembershipPasswordFormat.Clear
return pass;
byte[] bIn = Encoding.Unicode.GetBytes(pass);
byte[] bSalt = Convert.FromBase64String(salt);
byte[] bRet = null;
if (passwordFormat == 1)
{ // MembershipPasswordFormat.Hashed
HashAlgorithm hm = GetHashAlgorithm();
if (hm is KeyedHashAlgorithm) {
KeyedHashAlgorithm kha = (KeyedHashAlgorithm) hm;
if (kha.Key.Length == bSalt.Length) {
kha.Key = bSalt;
} else if (kha.Key.Length < bSalt.Length) {
byte[] bKey = new byte[kha.Key.Length];
Buffer.BlockCopy(bSalt, 0, bKey, 0, bKey.Length);
kha.Key = bKey;
} else {
byte[] bKey = new byte[kha.Key.Length];
for (int iter = 0; iter < bKey.Length; ) {
int len = Math.Min(bSalt.Length, bKey.Length - iter);
Buffer.BlockCopy(bSalt, 0, bKey, iter, len);
iter += len;
}
kha.Key = bKey;
}
bRet = kha.ComputeHash(bIn);
}
else {
byte[] bAll = new byte[bSalt.Length + bIn.Length];
Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);
bRet = hm.ComputeHash(bAll);
}
} else {
byte[] bAll = new byte[bSalt.Length + bIn.Length];
Buffer.BlockCopy(bSalt, 0, bAll, 0, bSalt.Length);
Buffer.BlockCopy(bIn, 0, bAll, bSalt.Length, bIn.Length);
bRet = EncryptPassword(bAll, _LegacyPasswordCompatibilityMode);
}
return Convert.ToBase64String(bRet);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With