哈希在Unicode密码上

时间:2010-11-16 15:52:04

标签: .net unicode hash passwords

我正在为我的.NET应用程序编写密码salt / hash过程,主要遵循本文的指南: http://www.aspheute.com/english/20040105.asp

基本上,计算盐渍哈希的代码是:

public string ComputeSaltedHash(string password, byte[] salt) {

    // Get password ASCII text as bytes:
    byte[] passwordBytes = System.Text.Encoding.ASCII.GetBytes(password);

    // Append the two arrays
    byte[] toHash = new byte[passwordBytes.Length + salt.Length];
    Array.Copy(passwordBytes, 0, toHash, 0, passwordBytes.Length);
    Array.Copy(salt, 0, toHash, passwordBytes.Length, salt.Length);

    byte[] computedHash = SHA1.Create().ComputeHash(toHash);

    // Return as an ASCII string
    return System.Text.Encoding.ASCII.GetString(computedHash);
}

但是,如果他们愿意,我想允许允许用户在他们的密码中使用Unicode字符。 (这似乎是一个好主意;任何人都可以想到它不是的原因吗?)

但是,我不知道Unicode如何工作,我担心如果我只是将System.Text.Encoding.ASCII的引用更改为System.Text.Encoding.Unicode,哈希算法可能会生成一些字节组合,不要形成有效的Unicode字符,并且GetString调用会吓坏。

这是一个有效的问题,还是可以?

3 个答案:

答案 0 :(得分:12)

您不应该使用任何普通编码将任意二进制数据转换回字符串。它不是编码文本 - 它只是一个字节序列。不要试图将其解释为“正常”文本。原始密码是否包含任何非ASCII字符与此无关 - 您当前的代码已损坏。 (我会在此基础上对相关文章进行大量怀疑处理。)

我建议:

  • 使用Encoding.UTF8从密码中获取字节。这将允许密码包含任何unicode字符。 Encoding.Unicode在这里也没关系。
  • 使用Convert.ToBase64String将计算出的哈希值转换回文本。 Base64专门用于表示ASCII字符集中文本中的不透明二进制数据。

答案 1 :(得分:2)

将第一个引用更改为UnicodeUTF-8就足够了。但是,您可能需要对输入进行标准化,以考虑输入重音等的各种方式。

答案 2 :(得分:0)

我更喜欢Jon解决方案,但另一种选择是将原始十六进制存储为字符串。将最后一行替换为:

return BitConverter.ToString(computedHash)

您可能需要考虑的一件事是加强密码。
SHA1非常快,有时太快。一个系统每秒可以计算几百万个哈希值。速度允许攻击者尝试常见的单词字典攻击(包括大小写中的变体)和数字扩展。 SHA1的速度允许在合理的时间内完成宽字典空间,从而破坏大多数用户的密码。

加强密码的方法是多次哈希,这会增加哈希的CPU需求。获取SHA1哈希的输出并将其作为第二轮的输入传递。这样做至少1000次。这会减慢您和攻击者的哈希计算速度。对于您的用户来说,它会在很短的时间内延迟访问;例程将在0.01秒内返回,而不是0.0001秒。但是对于暴力攻击,你的执行时间增加了1000倍。

您可以自己滚动但.net框架会公开一个类来执行此操作:  System.Security.Cryptography.Rfc2898DeriveBytes

RFC2898使用SHA1算法并接受纯文本,salt和迭代次数。它可以输出一个可变长度的密钥。

http://msdn.microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.aspx