2012-06-12 50 views
0

zetetic有一个非常好的加密库,它包含对bcrypt2的支持。它看起来应该足够简单,可以合并到ASP.NET成员资格提供程序中(实际上,可以找到有关默认提供程序的说明here)。我正在使用NHibernate成员资格提供程序(发现here)似乎在其EncodePassword函数中硬编码SHA1哈希格式。我的问题是,这应该如何适应与BCrypt2(特别是Zetetic的包装)。这是我非常害怕出错的原因,我不愿意自己刺伤它,以免它“应用”,但却有一些我没有资格找到的隐藏缺陷。ASP.NET MVC - 将zetetic安全性与NHibernate成员提供者集成

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

回答

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)) 
     } 
    } 
} 
+0

我修改基于NHibernate的提供商,所以很自由地进行修改。这听起来(纠正我,如果我错了)就像我需要拔出EncodePassword实现并插入一个调用HashAlgorithm.Create? –

+0

还有一个想法 - 如果您要滚动MembershipProvider,您可能需要为散列alg名称和参数以及散列输出分配单独的列,以防您想从(例如)BCrypt更改为SCrypt或更改工作因素,与BCrypt哈希的人仍然可以登录。 – SKradel

+0

谢谢@SKradel - 你的回答非常有见地。我不想使用zetetics解决方案,因为直接从EncodePassword函数的switch语句中的MembershipPasswordFormat.Hashed情况调用bcrypt(如果我没有使用自定义提供程序,我肯定会使用zetetic解决方案。 ..)。我非常喜欢在每条记录中存储算法和工作因子的想法,并且当用户的工作因素与网站使用的当前工作因素不匹配时,我计划再进一步并在登录时重新密码。 –

相关问题