0

zetetic 有一个非常好的加密库,其中包括对 bcrypt2 的支持。看起来它应该足够简单,可以合并到 ASP.NET 成员资格提供程序中(事实上,可以在此处找到默认提供程序的说明)。我正在使用 NHibernate Membership Provider(在此处找到),它似乎在其 EncodePassword 函数中硬编码 SHA1 哈希格式。我的问题是,这应该如何适应 BCrypt2(特别是 Zetetic 的包装器)。这是我非常害怕出错的事情,我不愿意自己尝试一下,以免它应该“起作用”但有一些我没有资格发现的隐藏缺陷。

 private string EncodePassword(string password)
        {
            string encodedPassword = password;

            switch (PasswordFormat)
            {
                case MembershipPasswordFormat.Clear:
                    break;
                case MembershipPasswordFormat.Encrypted:
                    encodedPassword =
                        Convert.ToBase64String(EncryptPassword(Encoding.Unicode.GetBytes(password)));
                    break;
                case MembershipPasswordFormat.Hashed:
                    HMACSHA1 hash = new HMACSHA1();
                    hash.Key = HexToByte(_machineKey.ValidationKey);
                    encodedPassword =
                        Convert.ToBase64String(hash.ComputeHash(Encoding.Unicode.GetBytes(password)));
                    break;
                default:
                    throw new ProviderException("Unsupported password format.");
            }

            return encodedPassword;
        }
4

1 回答 1

1

您是在修改基于 NHibernate 的会员提供程序,还是开箱即用地使用它?如果是后者,它看起来没有任何可扩展性。

ASP.NET SqlMembershipProvider 通过接受哈希算法的名称来工作,通过HashAlgorithm.Create(name)调用一个实例,然后如果算法类型是 KeyedHashAlgorithm 或常规(非键控)HashAlgorithm,则其行为会有所不同。Zetetic.Security 包只是提供了一点胶水来使 BCrypt 和 PBKDF2 与该模型兼容。

NHMembershipProvider 的示例代码无法利用这一点,因为它非常直接地依赖于 HMACSHA1。我注意到 HMACSHA1 不是用于此目的的安全算法,也不是所有用户都可以使用静态盐(它几乎不比没有盐好)。应用 ValidationKey 和 HMACSHA1 仅用于消息完整性。

这是一个示例:

public class HashDemo
{
    private static readonly RNGCryptoServiceProvider s_rng = new RNGCryptoServiceProvider();

    public string HashPassword(string pwd, string hashName)
    {
        var alg = HashAlgorithm.Create(hashName);

        if (alg == null)
            throw new ArgumentException("Invalid hash name", "hashName");

        byte[] tohash = System.Text.Encoding.UTF8.GetBytes(pwd);

        var ka = alg as KeyedHashAlgorithm;

        if (ka != null)
        {
            if (ka.Key == null || ka.Key.Length == 0)
            {
                byte[] key = new byte[20];

                s_rng.GetBytes(key);

                ka.Key = key;
            }
            else
            {
                s_rng.GetBytes(ka.Key);
            }
            // TODO: return base64(ka.Key || alg.ComputeHash(tohash))
        }
        else
        {
            var salt = new byte[20];

            s_rng.GetBytes(salt);

            using (var ms = new System.IO.MemoryStream(salt))
            {
                ms.Write(tohash, 0, tohash.Length);

                tohash = ms.ToArray();
            }
            // TODO: return base64(salt || alg.ComputeHash(tohash))
        }
    }
}
于 2012-06-13T17:11:14.803 回答