Asp.net Membership使用哪种哈希算法?

6

我正试图实现一个自定义的密码存储库。在更改密码之前,我需要先检查用户上次 修改密码时是否使用了最后8个密码

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;

我遇到的问题是从表中返回的密码总是与我输入的不同(即使在明文中它们是相同的)。这是由于哈希算法造成的。
我尝试了SHA和SHA1,但没有成功。ASP.NET成员资格使用特定的哈希算法吗?我正在使用System.Web.Security.SqlMembershipProvider版本4.0.0.0
<add key="MembershipProviderHashAlgorithm" value="SHA" />

感谢您的帮助。

编辑

这是来自web.config会员部分配置的一部分。有没有办法知道正在使用哪个算法。

<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>

3
如果您还没有这样做,可以查看SqlMembershipProvider的源代码。 - Tim M.
2
@TimMedora - referencesource 绝对是我在微软库中寻找代码相关问题的首选。这是必须的。 - Travis J
1个回答

8

会员提供程序使用以下算法来哈希密码。

默认哈希将根据会员提供程序的版本而异。

ASP.Net通用提供程序

MVC 4和ASP.NET 4和4.5的默认哈希是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;
}

旧版ASP.Net会员提供程序

默认哈希算法是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); 
}

1
答案是肯定的。EncodePassword 是一个私有方法,因此您无法从外部调用它。 - Win
1
上述方法也没有帮助。使用相同的明文密码和相同的盐值,上述方法生成的哈希值与成员资格提供的不同。我错过了什么吗? - Richard77
1
每个会员的哈希算法都是不同的。关于代码来自最新的Membership Provider,称为ASP.NET Universal ProvidersFYI: 所有的Membership Providers都已被ASP.Net Identity所取代。 - Win
我相信你正在使用旧版的ASP.Net Membership Provider。我已经上传了它的EncodePassword方法。 - Win
1
我使用了Resharper。幸运的是,生成的代码与SqlMembershipProvider相同。 - Win
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接