我问了一个问题,我确实得到了很多很好的反馈,并得到了很好的答案。我假设我对2个哈希的验证检查有问题。也许循环中的代码很好,但我的代码了解字节和base64等问题?
这是原始问题。 Password Hashing - Why salt 60,000 times
问题是这些哈希与if (resultHash.Equals(hashPassword))
代码
public string BuildVerify()
{
string password = "";
string salt = "";
byte[] result;
using (var sha256 = SHA256.Create())
{
password = "hovercraft";
// step 1: you can use RNGCryptoServiceProvider for something worth using
var passwordHashing = new PasswordHashing();
salt = passwordHashing.CreateRandomSalt();
// step 2
string hash =
Convert.ToBase64String(sha256.ComputeHash(Encoding.UTF8.GetBytes(salt + password)));
// step 3
result = sha256.ComputeHash(Encoding.UTF8.GetBytes(salt + hash));
// step 4
for (int i = 0; i < 60000; i++)
{
result =
sha256.ComputeHash(Encoding.UTF8.GetBytes(salt + Convert.ToBase64String(result)));
}
}
// TESTING VERIFY this works ..
string SaltAndPwd = string.Concat(password, salt);
SHA256 sha2 = SHA256Managed.Create();
byte[] buff = sha2.ComputeHash(Encoding.Unicode.GetBytes(SaltAndPwd));
string resultHash = Convert.ToBase64String(buff);
string hashPassword = Convert.ToBase64String(result);
if (resultHash.Equals(hashPassword))
{
// perfect
}
return "";
}
public class PasswordHashing
{
public string CreateRandomSalt()
{
string password = "";
password = HashPassword.CreateSalt(8) + "=";
password = password.Replace("/", "c");
return password;
}
}
public static string CreateSalt(int size)
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] buff = new byte[size];
rng.GetBytes(buff);
return Convert.ToBase64String(buff);
}
更新 - 问题
好的,我正在使用答案中的代码,但显然我的假设不正确,因为我无法使用我的代码进行验证
// This should be stored in your DB for example along with the hash result
var newsalt = SOPasswordHasher.GetSalt();
// We calculate the hash then store the result. Next time you want to authenticate someone
// You'll have to reuse the same salt and recalculate the hash then compare
// the stored hash with the new one
var result = Convert.ToBase64String(SOPasswordHasher.Hash("hovercraft", newsalt));
string SaltAndPwd = string.Concat("hovercraft", newsalt);
SHA256 sha2 = SHA256Managed.Create();
byte[] buff = sha2.ComputeHash(Encoding.Unicode.GetBytes(SaltAndPwd));
string resultHash = Convert.ToBase64String(buff);
if (result.Equals(resultHash))
{
// perfect
}
答案 0 :(得分:2)
这是一个可以使用的可重用类(更少依赖转换为base64):
class SOPasswordHasher
{
/// <summary>
/// Password Hasher
/// </summary>
/// <param name="password">The password you want to hash</param>
/// <param name="salt">byte array of (crypto-secure) random values</param>
/// <param name="iterations">Number of iterations. default is 60,000</param>
/// <returns>Byte array containing the hashed password</returns>
public static byte[] Hash(string password, byte[] salt, int iterations = 60000)
{
using (var sha256 = SHA256.Create())
{
byte[] passwordBytes = Encoding.UTF8.GetBytes(password);
// step 2
byte[] hash = sha256.ComputeHash(passwordBytes.Concat(salt).ToArray());
// step 3
byte[] result = sha256.ComputeHash(salt.Concat(hash).ToArray());
// step 4
for (int i = 0; i < iterations; i++)
{
result =
sha256.ComputeHash(salt.Concat(result).ToArray());
}
return result;
}
}
public static byte[] GetSalt(int size = 32)
{
byte[] salt = new byte[size];
using (var cryptoServiceProvider = new RNGCryptoServiceProvider())
{
cryptoServiceProvider.GetBytes(salt);
}
return salt;
}
}
这是一个用法示例:
// This should be stored in your DB for example along with the hash result
var salt = SOPasswordHasher.GetSalt();
// We calculate the hash then store the result. Next time you want to authenticate someone
// You'll have to reuse the same salt and recalculate the hash then compare
// the stored hash with the new one
var result = Convert.ToBase64String(SOPasswordHasher.Hash("hovercraft", salt));
重要提示:我不保证此代码可以安全使用,因为我不是安全专家。布鲁斯施奈尔说得最好:"Amateurs Produce Amateur Cryptography"