我正在为我的.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调用会吓坏。
这是一个有效的问题,还是可以?
答案 0 :(得分:12)
您不应该使用任何普通编码将任意二进制数据转换回字符串。它不是编码文本 - 它只是一个字节序列。不要试图将其解释为“正常”文本。原始密码是否包含任何非ASCII字符与此无关 - 您当前的代码已损坏。 (我会在此基础上对相关文章进行大量怀疑处理。)
我建议:
Encoding.UTF8
从密码中获取字节。这将允许密码包含任何unicode字符。 Encoding.Unicode
在这里也没关系。Convert.ToBase64String
将计算出的哈希值转换回文本。 Base64专门用于表示ASCII字符集中文本中的不透明二进制数据。答案 1 :(得分:2)
将第一个引用更改为Unicode
或UTF-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