Is there a bug in the hashfunction of the ASP.NET DefaultMembershipProvider?

扶醉桌前 提交于 2020-04-11 12:09:12

问题


I am migrating my legacy ASP.NET webforms application to start using the ASP.NET build-in DefaultMembershipProvider. My old homebrewn authenticationmodule used to store SHA256 hashes of passwords. I figured that 'upgrading' to the DefaultMembershipProvider, which also stores hashes in the SQL DB, would mean that I could migrate these hashes as well and therefore offer painless upgrade for current users (so they wouldn't have to reset their password).

Now, this didn't quite work as planned (obviously!) and I started to look into the source of the DefaultMembershipProvider (to be more specific, right here: https://github.com/wyxy2005/bluceNet/tree/master/System.Web.Providers) and I came accross the following function:

private string EncodePassword(string pass, int passwordFormat, string salt)
    {
        if (passwordFormat == 0)
        {
            return pass;
        }
        byte[] bytes = Encoding.Unicode.GetBytes(pass);
        byte[] src = Convert.FromBase64String(salt);
        byte[] inArray = null;
        if (passwordFormat == 1)
        {
            HashAlgorithm hashAlgorithm = this.GetHashAlgorithm();
            KeyedHashAlgorithm algorithm2 = hashAlgorithm as KeyedHashAlgorithm;
            if (algorithm2 != null)
            {
                if (algorithm2.Key.Length == src.Length)
                {
                    algorithm2.Key = src;
                }
                else if (algorithm2.Key.Length < src.Length)
                {
                    byte[] dst = new byte[algorithm2.Key.Length];
                    Buffer.BlockCopy(src, 0, dst, 0, dst.Length);
                    algorithm2.Key = dst;
                }
                else
                {
                    int num2;
                    byte[] buffer5 = new byte[algorithm2.Key.Length];
                    for (int i = 0; i < buffer5.Length; i += num2)
                    {
                        num2 = Math.Min(src.Length, buffer5.Length - i);
                        Buffer.BlockCopy(src, 0, buffer5, i, num2);
                    }
                    algorithm2.Key = buffer5;
                }
                inArray = algorithm2.ComputeHash(bytes);
            }
            else
            {
                byte[] buffer6 = new byte[src.Length + bytes.Length];
                Buffer.BlockCopy(src, 0, buffer6, 0, src.Length);
                Buffer.BlockCopy(bytes, 0, buffer6, src.Length, bytes.Length);
                inArray = hashAlgorithm.ComputeHash(buffer6);
            }
        }
        else
        {
            byte[] buffer7 = new byte[src.Length + bytes.Length];
            Buffer.BlockCopy(src, 0, buffer7, 0, src.Length);
            Buffer.BlockCopy(bytes, 0, buffer7, src.Length, bytes.Length);
            inArray = this.EncryptPassword(buffer7, this.LegacyPasswordCompatibilityMode);
        }
        return Convert.ToBase64String(inArray);
    }

Now, in my particular scenario I didn't have any password-salt as my old authentication module didn't use it so string salt is empty, as is byte [] src. The hashing algorithm that is used by default is HMACSHA256, which is a keyed hashfunction. So we get into this for-loop where num2 is always 0. As num2 is also used as the incrementer, we enter an infinite loop.

Shouldn't the algorithm test for this particular condition? Shouldn't this have been an easy error, caught by simply UnitTesting the code? Or am I overlooking something?


回答1:


I'm not a security expert, so I cannot answer your question.

Here is the EncodePassword method used by new ASP.Net Universal Provider.

It is a little bit different from old MembershipProvider. You might want to give a try.

private string EncodePassword(string pass, int passwordFormat, string salt)
{
    byte[] numArray;
    byte[] numArray1;
    string base64String;
    bool length = passwordFormat != 0;
    if (length)
    {
        byte[] bytes = Encoding.Unicode.GetBytes(pass);
        byte[] numArray2 = Convert.FromBase64String(salt);
        byte[] numArray3 = null;
        length = passwordFormat != 1;
        if (length)
        {
            numArray1 = new byte[(int)numArray2.Length + (int)bytes.Length];
            Buffer.BlockCopy(numArray2, 0, numArray1, 0, (int)numArray2.Length);
            Buffer.BlockCopy(bytes, 0, numArray1, (int)numArray2.Length, (int)bytes.Length);
            numArray3 = this.EncryptPassword(numArray1);
        }
        else
        {
            HashAlgorithm hashAlgorithm = this.GetHashAlgorithm();
            length = hashAlgorithm as KeyedHashAlgorithm <= null;
            if (length)
            {
                numArray1 = new byte[(int)numArray2.Length + (int)bytes.Length];
                Buffer.BlockCopy(numArray2, 0, numArray1, 0, (int)numArray2.Length);
                Buffer.BlockCopy(bytes, 0, numArray1, (int)numArray2.Length, (int)bytes.Length);
                numArray3 = hashAlgorithm.ComputeHash(numArray1);
            }
            else
            {
                KeyedHashAlgorithm keyedHashAlgorithm = (KeyedHashAlgorithm)hashAlgorithm;
                length = (int)keyedHashAlgorithm.Key.Length != (int)numArray2.Length;
                if (length)
                {
                    length = (int)keyedHashAlgorithm.Key.Length >= (int)numArray2.Length;
                    if (length)
                    {
                        numArray = new byte[(int)keyedHashAlgorithm.Key.Length];
                        int num = 0;
                        while (true)
                        {
                            length = num < (int)numArray.Length;
                            if (!length)
                            {
                                break;
                            }
                            int num1 = Math.Min((int)numArray2.Length, (int)numArray.Length - num);
                            Buffer.BlockCopy(numArray2, 0, numArray, num, num1);
                            num = num + num1;
                        }
                        keyedHashAlgorithm.Key = numArray;
                    }
                    else
                    {
                        numArray = new byte[(int)keyedHashAlgorithm.Key.Length];
                        Buffer.BlockCopy(numArray2, 0, numArray, 0, (int)numArray.Length);
                        keyedHashAlgorithm.Key = numArray;
                    }
                }
                else
                {
                    keyedHashAlgorithm.Key = numArray2;
                }
                numArray3 = keyedHashAlgorithm.ComputeHash(bytes);
            }
        }
        base64String = Convert.ToBase64String(numArray3);
    }
    else
    {
        base64String = pass;
    }
    return base64String;
}


来源:https://stackoverflow.com/questions/19162971/is-there-a-bug-in-the-hashfunction-of-the-asp-net-defaultmembershipprovider

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!