What Hash Algorithm used by the Asp.net Membership?
Asked Answered
F

1

6

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.

EDIT

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>
Furred answered 29/4, 2016 at 19:13 Comment(2)
If you haven't already, you can look at the source of SqlMembershipProviderHent
@TimMedora - referencesource is definitely the first place I look for code related issues in MSFT libraries also. It is a must.Glyn
M
8

Membership Provider uses the following Algorithms to hash password.

Default hash will vary based on the version of Membership Provider.

ASP.Net Universal 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;
}

Old ASP.Net Membership Provider

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); 
}
Mendy answered 29/4, 2016 at 19:19 Comment(10)
What you are suggesting is to replace the method used in this line var encodedPassword = pwdEncr .EncodePassword(proposedNewPassword, passwordDetails.Salt, hashingAlgorithm); with the above method? Is there a way to call an existing class/method that contains the above code?Furred
Answer is yes. EncodePassword is a private method, so you cannot call it from outside.Mendy
The above method didn't help either. With the same clear password and the same salt, the above method is producing a hashed that is different from what membership is providing. I'm missing something?Furred
Each membership's hashing algorithm is different. About code is from latest Membership Provider called ASP.NET Universal Providers. FYI: all Membership Providers has been replaced by ASP.Net Identity.Mendy
Can u tell which is algorithm is being used in my application, only by looking to the membership portion of the web.config file that I've added in the question? Thanks.Furred
I believe you are using old ASP.Net Membership Provider. I uploaded EncodePassword method for it.Mendy
GetHashAlgorithm and EncryptPassword are missing from the code you provided. Is there a way to paste them or to point me to where I can find them?Furred
I used Resharper. Fortunately, the generated code is same as SqlMembershipProviderMendy
Let us continue this discussion in chat.Furred
It's a shame this moved to chat, which is now no longer available. Loss of knowledge and breaking what StackOverflow is great for — historical knowledge sharing.Mittiemittimus

© 2022 - 2024 — McMap. All rights reserved.