需要帮助在 C# 中为 PBKDF2 创建 IsValidPassword
Need help creating IsValidPassword for PBKDF2 in C#
在尝试创建 PBKDF2 有效密码检查程序时遇到了最困难的情况。 PBKDF2代码来自一个SharpHash项目; https://github.com/ron4fun/SharpHash。 Class 是:SharpHash/SharpHash.Tests/KDF/PBKDF2_HMACTests.cs
该示例展示了如何实现它,但没有任何关于之后如何验证哈希的示例。我设法尝试了几种不同的方法 "IsValidPassword" 是其中一种方法,但其中 none 似乎有效。无论我向 PBKDF2 或 IsValidPassword 方法添加什么值,它们中的每一个结果都是错误的。我也尝试更改为十六进制和 base64,但得到了相同的结果;失败了。
我什至替换了 Rfc2898DeriveBytes。
有没有人有过 PBKDF2 密码验证的经验。这将基于应用程序,而不是基于网站。 IDE 环境 Visual Studios 2019 - C#。
谢谢。
public void TestOne()
{
IPBKDF2_HMAC PBKDF2 = HashFactory.KDF.PBKDF2_HMAC.CreatePBKDF2_HMAC(hash, Password, Salt, 100000);
byte[] Key = PBKDF2.GetBytes(64);
PBKDF2.Clear();
string ActualString = Converters.ConvertBytesToHexString(Key, false);
Assert.AreEqual(ExpectedString, ActualString);
}
public bool IsValidPassword(string password, string hashPass)
{
bool result = false;
// Extract the bytes
byte[] hashBytes = Encoding.ASCII.GetBytes(hashPass);
// Get the salt
byte[] salt = new byte[20]; // Doesn't matter what values and here; same issue… False
Array.Copy(hashBytes, 0, salt, 0, 20);// Doesn't matter what values and here; same issue… False
// Compute the hash on the password the user entered
var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 100000);
byte[] hash = pbkdf2.GetBytes(64);
// compare the results
for (int i = 0; i < 20; i++) // If I go to 64 I get an error
{
if (hashBytes[i + 20] != hash[i])
{
return false;
}
}
return true;
}
// Replaced Rfc2898DeriveBytes
public bool IsValidPassword(string password, string hashPass)
{
bool result = false;
IHash hash1 = HashFactory.Crypto.CreateSHA1();
// Extract the bytes
byte[] hashBytes = Encoding.ASCII.GetBytes(hashPass);
byte[] Password = Encoding.ASCII.GetBytes(password);
// Get the salt
byte[] salt = new byte[20]; // Doesn't matter what values and here; same issue… False
Array.Copy(hashBytes, 0, salt, 0, 20); // Doesn't matter what values and here; same issue… False
// Compute the hash on the password the user entered
var pbkdf2 = HashFactory.KDF.PBKDF2_HMAC.CreatePBKDF2_HMAC(hash1, Password, salt, 100000); // Replaced Rfc2898DeriveBytes
byte[] Key = pbkdf2.GetBytes(64);
pbkdf2.Clear();
string test = Converters.ConvertBytesToHexString(Key, false); // Taking a peek
string test2 = Encoding.ASCII.GetString(hashBytes); // Taking a peek
// compare the results
for (int i = 0; i < 20; i++)
{
if (hashBytes[i + 20] != Key[i])
{
return false;
}
}
return true;
}
快速看一下,您遇到的问题只是对所涉及数据内容的错误陈述。
password
是基于 base256
的数据,而 hashPass
是基于 base16
的数据。
将 hashPass
转换为 byte[]
时,您必须使用适当的转换例程。
为此,也只需使用转换器 class 中的 this 方法。
byte[] hashBytes = Converters.ConvertHexStringToBytes(hashPass);
请注意,我假设您的密码在 base256
中(因为您没有在问题中指定),所以您可以保留原样。
您需要做的唯一更改是我在上面描述的更改。
好吧,我想这会对以后的其他人有所帮助。我不得不进行一些认真的搜索并将我的头撞到墙上,因为这是我在 PBKDF2 中第一次尝试提出一种功能验证方法,该方法不包含在 SharpHash 项目中。只是为了让任何阅读本文的人都能理解我的问题所在。该代码生成的密码没有任何问题。但是,代码项目中并没有实际使用salt、生成密码和迭代验证密码的函数。
提供的代码是简单版本,因为我还为不需要的方法添加了重载 post。此方法具有默认设置,而其中一个重载允许完全自定义哈希算法、salt 和迭代。我已经测试了其中的每一个,并且它们按预期工作。
希望这对某人有所帮助。 :-)
private static Int32 Salt256bit { get; } = 256 / 8; // 256 bits = 32 Bytes
public static string GetHashPBKDF2Password(string password)
{
// Notes:
// Create a 32-byte secure salt and the same size of the key. This 32-byte produces 256 bits key output.
// Add the same 32-byte size to the pbkdf2.GetBytes.
// KDF.PBKDF2_HMAC.CreatePBKDF2_HMAC hashes these values using the crypto SHA presented.
// Double the hashBytes bytes then add the salt and pbkdf2.GetBytes value.
// Copy each of the 32-bytes to the hashBytes bytes from the hashed salt and hashed value.
//
byte[] Password = Encoding.Unicode.GetBytes(password);
string hashPass = string.Empty;
// Create the salt value with a cryptographic PRNG
byte[] salt;
new RNGCryptoServiceProvider().GetBytes(salt = new byte[ByteSize]); // 32 Bytes = 256 bits.
// Create the KDF.PBKDF2_HMAC.CreatePBKDF2_HMAC and get the hash value using the SHA presented.
// I know SHA1 is not that secured at all anymore. Just using it to test with. :-)
IHash sha = HashFactory.Crypto.CreateSHA1();
IPBKDF2_HMAC pbkdf2 = HashFactory.KDF.PBKDF2_HMAC.CreatePBKDF2_HMAC(sha, Password, salt, Pbkdf2Iterations);
byte[] hash = pbkdf2.GetBytes(ByteSize); // 32 Bytes = 256 bits.
// Double the size of the byte array to include the "pbkdf2.GetBytes" and salt.
Int32 g = hash.Length + salt.Length;
byte[] hashBytes = new byte[g];
// Combine the salt and password bytes.
Array.Copy(salt, 0, hashBytes, 0, ByteSize);
Array.Copy(hash, 0, hashBytes, ByteSize, ByteSize);
// Turn the combined salt+hash into a string for storage
hashPass = Convert.ToBase64String(hashBytes);
return hashPass;
}
public static bool ValidatePBKDF2Password(string password, string hashPass)
{
try
{
byte[] Password = Encoding.Unicode.GetBytes(password);
bool result = true;
// Extract the bytes
byte[] hashBytes = Convert.FromBase64String(hashPass);
// Get the salt
byte[] salt = new byte[32];
Array.Copy(hashBytes, 0, salt, 0, 32);
// Compute the hash on the password that user entered.
// I know SHA1 is not that secured at all anymore. Just using it to test with. :-)
IHash hash1 = HashFactory.Crypto.CreateSHA1();
IPBKDF2_HMAC pbkdf2 = HashFactory.KDF.PBKDF2_HMAC.CreatePBKDF2_HMAC(hash1, Password, salt, Pbkdf2Iterations);
byte[] hash = pbkdf2.GetBytes(32);
// compare the results
for (int i = 0; i < 32; i++)
{
if (hashBytes[i + 32] != hash[i])
{
result = false;
}
}
return result;
}
catch (Exception)
{
return false;
}
}
How to use: string GeneratedHash = PBKDF2Helper.GetHashPBKDF2Password("password");
Results: hv6t8N4rrVSKYFm80cCoVUEiUk2o11xLBc6lJb5kBXKTcwcKwl9dZwSdce01X0bi8BBhJY/QGGnNVAcR7ZhSvQ==
Verify Paword: Boolean tester = PBKDF2Helper.ValidatePBKDF2Password("password", GeneratedHash);
txtVerificationResults.Text = tester.ToString();
在尝试创建 PBKDF2 有效密码检查程序时遇到了最困难的情况。 PBKDF2代码来自一个SharpHash项目; https://github.com/ron4fun/SharpHash。 Class 是:SharpHash/SharpHash.Tests/KDF/PBKDF2_HMACTests.cs
该示例展示了如何实现它,但没有任何关于之后如何验证哈希的示例。我设法尝试了几种不同的方法 "IsValidPassword" 是其中一种方法,但其中 none 似乎有效。无论我向 PBKDF2 或 IsValidPassword 方法添加什么值,它们中的每一个结果都是错误的。我也尝试更改为十六进制和 base64,但得到了相同的结果;失败了。
我什至替换了 Rfc2898DeriveBytes。
有没有人有过 PBKDF2 密码验证的经验。这将基于应用程序,而不是基于网站。 IDE 环境 Visual Studios 2019 - C#。
谢谢。
public void TestOne()
{
IPBKDF2_HMAC PBKDF2 = HashFactory.KDF.PBKDF2_HMAC.CreatePBKDF2_HMAC(hash, Password, Salt, 100000);
byte[] Key = PBKDF2.GetBytes(64);
PBKDF2.Clear();
string ActualString = Converters.ConvertBytesToHexString(Key, false);
Assert.AreEqual(ExpectedString, ActualString);
}
public bool IsValidPassword(string password, string hashPass)
{
bool result = false;
// Extract the bytes
byte[] hashBytes = Encoding.ASCII.GetBytes(hashPass);
// Get the salt
byte[] salt = new byte[20]; // Doesn't matter what values and here; same issue… False
Array.Copy(hashBytes, 0, salt, 0, 20);// Doesn't matter what values and here; same issue… False
// Compute the hash on the password the user entered
var pbkdf2 = new Rfc2898DeriveBytes(password, salt, 100000);
byte[] hash = pbkdf2.GetBytes(64);
// compare the results
for (int i = 0; i < 20; i++) // If I go to 64 I get an error
{
if (hashBytes[i + 20] != hash[i])
{
return false;
}
}
return true;
}
// Replaced Rfc2898DeriveBytes
public bool IsValidPassword(string password, string hashPass)
{
bool result = false;
IHash hash1 = HashFactory.Crypto.CreateSHA1();
// Extract the bytes
byte[] hashBytes = Encoding.ASCII.GetBytes(hashPass);
byte[] Password = Encoding.ASCII.GetBytes(password);
// Get the salt
byte[] salt = new byte[20]; // Doesn't matter what values and here; same issue… False
Array.Copy(hashBytes, 0, salt, 0, 20); // Doesn't matter what values and here; same issue… False
// Compute the hash on the password the user entered
var pbkdf2 = HashFactory.KDF.PBKDF2_HMAC.CreatePBKDF2_HMAC(hash1, Password, salt, 100000); // Replaced Rfc2898DeriveBytes
byte[] Key = pbkdf2.GetBytes(64);
pbkdf2.Clear();
string test = Converters.ConvertBytesToHexString(Key, false); // Taking a peek
string test2 = Encoding.ASCII.GetString(hashBytes); // Taking a peek
// compare the results
for (int i = 0; i < 20; i++)
{
if (hashBytes[i + 20] != Key[i])
{
return false;
}
}
return true;
}
快速看一下,您遇到的问题只是对所涉及数据内容的错误陈述。
password
是基于 base256
的数据,而 hashPass
是基于 base16
的数据。
将 hashPass
转换为 byte[]
时,您必须使用适当的转换例程。
为此,也只需使用转换器 class 中的 this 方法。
byte[] hashBytes = Converters.ConvertHexStringToBytes(hashPass);
请注意,我假设您的密码在 base256
中(因为您没有在问题中指定),所以您可以保留原样。
您需要做的唯一更改是我在上面描述的更改。
好吧,我想这会对以后的其他人有所帮助。我不得不进行一些认真的搜索并将我的头撞到墙上,因为这是我在 PBKDF2 中第一次尝试提出一种功能验证方法,该方法不包含在 SharpHash 项目中。只是为了让任何阅读本文的人都能理解我的问题所在。该代码生成的密码没有任何问题。但是,代码项目中并没有实际使用salt、生成密码和迭代验证密码的函数。
提供的代码是简单版本,因为我还为不需要的方法添加了重载 post。此方法具有默认设置,而其中一个重载允许完全自定义哈希算法、salt 和迭代。我已经测试了其中的每一个,并且它们按预期工作。
希望这对某人有所帮助。 :-)
private static Int32 Salt256bit { get; } = 256 / 8; // 256 bits = 32 Bytes
public static string GetHashPBKDF2Password(string password)
{
// Notes:
// Create a 32-byte secure salt and the same size of the key. This 32-byte produces 256 bits key output.
// Add the same 32-byte size to the pbkdf2.GetBytes.
// KDF.PBKDF2_HMAC.CreatePBKDF2_HMAC hashes these values using the crypto SHA presented.
// Double the hashBytes bytes then add the salt and pbkdf2.GetBytes value.
// Copy each of the 32-bytes to the hashBytes bytes from the hashed salt and hashed value.
//
byte[] Password = Encoding.Unicode.GetBytes(password);
string hashPass = string.Empty;
// Create the salt value with a cryptographic PRNG
byte[] salt;
new RNGCryptoServiceProvider().GetBytes(salt = new byte[ByteSize]); // 32 Bytes = 256 bits.
// Create the KDF.PBKDF2_HMAC.CreatePBKDF2_HMAC and get the hash value using the SHA presented.
// I know SHA1 is not that secured at all anymore. Just using it to test with. :-)
IHash sha = HashFactory.Crypto.CreateSHA1();
IPBKDF2_HMAC pbkdf2 = HashFactory.KDF.PBKDF2_HMAC.CreatePBKDF2_HMAC(sha, Password, salt, Pbkdf2Iterations);
byte[] hash = pbkdf2.GetBytes(ByteSize); // 32 Bytes = 256 bits.
// Double the size of the byte array to include the "pbkdf2.GetBytes" and salt.
Int32 g = hash.Length + salt.Length;
byte[] hashBytes = new byte[g];
// Combine the salt and password bytes.
Array.Copy(salt, 0, hashBytes, 0, ByteSize);
Array.Copy(hash, 0, hashBytes, ByteSize, ByteSize);
// Turn the combined salt+hash into a string for storage
hashPass = Convert.ToBase64String(hashBytes);
return hashPass;
}
public static bool ValidatePBKDF2Password(string password, string hashPass)
{
try
{
byte[] Password = Encoding.Unicode.GetBytes(password);
bool result = true;
// Extract the bytes
byte[] hashBytes = Convert.FromBase64String(hashPass);
// Get the salt
byte[] salt = new byte[32];
Array.Copy(hashBytes, 0, salt, 0, 32);
// Compute the hash on the password that user entered.
// I know SHA1 is not that secured at all anymore. Just using it to test with. :-)
IHash hash1 = HashFactory.Crypto.CreateSHA1();
IPBKDF2_HMAC pbkdf2 = HashFactory.KDF.PBKDF2_HMAC.CreatePBKDF2_HMAC(hash1, Password, salt, Pbkdf2Iterations);
byte[] hash = pbkdf2.GetBytes(32);
// compare the results
for (int i = 0; i < 32; i++)
{
if (hashBytes[i + 32] != hash[i])
{
result = false;
}
}
return result;
}
catch (Exception)
{
return false;
}
}
How to use: string GeneratedHash = PBKDF2Helper.GetHashPBKDF2Password("password");
Results: hv6t8N4rrVSKYFm80cCoVUEiUk2o11xLBc6lJb5kBXKTcwcKwl9dZwSdce01X0bi8BBhJY/QGGnNVAcR7ZhSvQ==
Verify Paword: Boolean tester = PBKDF2Helper.ValidatePBKDF2Password("password", GeneratedHash);
txtVerificationResults.Text = tester.ToString();