[英]Can't Verify Hash Password in C#
在 C# 语言中,我的目的是使用 hash_password() 对密码进行哈希处理,然后使用 verify() 方法对其进行验证。 我对密码“s3cr3t”进行哈希和加盐,然后检查两个示例,如果密码为“s3cr3t”则返回真,对密码“s3cr4t”返回假。
using System;
using System.Text;
using System.Security.Cryptography;
public class Pbkdf2_test4
{
public const int salt_size = 24;
public const int hash_size = 24;
public const int iteration = 100000;
static byte[] salt1 = new byte[salt_size];
private static Rfc2898DeriveBytes hash_password(string password)
{
RandomNumberGenerator generator = RandomNumberGenerator.Create();
byte[] salt = new byte[salt_size];
generator.GetBytes(salt);
salt1 = salt;
Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(password, salt1, iteration);
return pbkdf2;
}
private static bool verify(Rfc2898DeriveBytes pw_hash, string password)
{
//data1 can be a string or contents of a file.
string data1 = "Some test data";
try
{
Rfc2898DeriveBytes k1 = pw_hash;
Rfc2898DeriveBytes k2 = new Rfc2898DeriveBytes(password, salt1, iteration);
// Encrypt the data.
Aes encAlg = Aes.Create();
encAlg.Key = k1.GetBytes(16);
MemoryStream encryptionStream = new MemoryStream();
CryptoStream encrypt = new CryptoStream(encryptionStream, encAlg.CreateEncryptor(), CryptoStreamMode.Write);
byte[] utfD1 = new System.Text.UTF8Encoding(false).GetBytes(data1);
encrypt.Write(utfD1, 0, utfD1.Length);
encrypt.FlushFinalBlock();
encrypt.Close();
byte[] edata1 = encryptionStream.ToArray();
k1.Reset();
// Try to decrypt, thus showing it can be round-tripped.
Aes decAlg = Aes.Create();
decAlg.Key = k2.GetBytes(16);
decAlg.IV = encAlg.IV;
MemoryStream decryptionStreamBacking = new MemoryStream();
CryptoStream decrypt = new CryptoStream(decryptionStreamBacking, decAlg.CreateDecryptor(), CryptoStreamMode.Write);
decrypt.Write(edata1, 0, edata1.Length);
decrypt.Flush();
decrypt.Close();
k2.Reset();
string data2 = new UTF8Encoding(false).GetString(decryptionStreamBacking.ToArray());
if (!data1.Equals(data2))
{
return false;
}
else
{
return true;
}
}
catch (Exception e)
{
return false;
}
}
public static void Run()
{
Rfc2898DeriveBytes pw_hash = hash_password("s3cr3t");
Console.WriteLine(System.Text.Encoding.UTF8.GetString(pw_hash.GetBytes(hash_size)));
var result1 = verify(pw_hash, "s3cr3t");
Console.WriteLine(result1);
var result2 = verify(pw_hash, "s3cr4t");
Console.WriteLine(result2);
}
}
我的问题,不知何故,verify(pw_hash, "s3cr3t") 存在一个问题,它返回false,但它应该返回true。 在 verify() 中,有一个问题但仍然无法理解,因为我将密钥 k1 和 k2 设置为 true,但仍然没有收到相同的 hash/salt,我该如何解决这个问题?
除此之外,我是否应该添加任何内容以使密码存储最安全?
这是加密和解密通行证的程序
internal class Program
{
static void Main(string[] args)
{
Pbkdf2_test4 test4 = new Pbkdf2_test4();
test4.Run();
Console.ReadLine();
}
}
public class Pbkdf2_test4
{
static string key = string.Empty;
static string iv = string.Empty;
public Pbkdf2_test4()
{
Aes encAlg = Aes.Create();
encAlg.GenerateKey();
key = Convert.ToBase64String(encAlg.Key);
encAlg.GenerateIV();
iv = Convert.ToBase64String(encAlg.IV);
}
public string Encrypt(string plainText, string Key, string IV)
{
// Check arguments.
if (string.IsNullOrWhiteSpace(plainText))
throw new ArgumentNullException(nameof(plainText));
if (string.IsNullOrWhiteSpace(Key))
throw new ArgumentNullException(nameof(Key));
if (string.IsNullOrWhiteSpace(IV))
throw new ArgumentNullException(nameof(IV));
byte[] encrypted;
// Create an AesCryptoServiceProvider object
// with the specified key and IV.
using (Aes aes = Aes.Create())
{
aes.Key = Convert.FromBase64String(Key);
aes.IV = Convert.FromBase64String(IV);
// Create an encrypt-or to perform the stream transform.
ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
// Create the streams used for encryption.
using (MemoryStream msEncrypt = new MemoryStream())
{
using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
}
encrypted = msEncrypt.ToArray();
}
}
// Return the encrypted bytes from the memory stream.
return Convert.ToBase64String(encrypted);
}
public string Decrypt(string cipherText, string Key, string IV)
{
// Check arguments.
if (string.IsNullOrWhiteSpace(cipherText))
throw new ArgumentNullException(nameof(cipherText));
if (string.IsNullOrWhiteSpace(Key))
throw new ArgumentNullException(nameof(Key));
if (string.IsNullOrWhiteSpace(IV))
throw new ArgumentNullException(nameof(IV));
// Declare the string used to hold
// the decrypted text.
string plaintext = string.Empty;
// Create an AesCryptoServiceProvider object
// with the specified key and IV.
using (Aes aes = Aes.Create())
{
aes.Key = Convert.FromBase64String(Key);
aes.IV = Convert.FromBase64String(IV);
// Create a decrypt-or to perform the stream transform.
ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(Convert.FromBase64String(cipherText)))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
}
return plaintext;
}
public void Run()
{
Console.WriteLine("Key is : " + key);
Console.WriteLine("IV is : " + iv);
string passord = "s3cr3t";
string encryptedPassowrd = Encrypt(passord, key, iv);
string decryptedPassowrd = Decrypt(encryptedPassowrd, key, iv);
Console.WriteLine($"Password = {passord} and Encrypted password = {encryptedPassowrd}");
Console.WriteLine($"Password = {passord} and Decrypted password = {decryptedPassowrd}");
string passord1 = "s3cr4t";
string encryptedPassowrd1 = Encrypt(passord1, key, iv);
string decryptedPassowrd1 = Decrypt(encryptedPassowrd1, key, iv);
Console.WriteLine($"Password = {passord1} and Encrypted password = {encryptedPassowrd1}");
Console.WriteLine($"Password = {passord1} and Decrypted password = {decryptedPassowrd1}");
}
}
我认为您误解了Rfc2898DeriveBytes文档中的示例。 此功能可用于密码散列(PBKDF2),但您不需要加密部分。 像 PBKDF2 这样的密钥派生函数的原始用例是获取(弱)用户密码并将其转换为(强)密钥,然后可用于加密数据(因此名称密钥派生)。 后来发现同样的函数也适用于生成密码哈希。
在您的情况下,我建议使用适当的库进行密码散列,例如BCrypt.Net 。 用法如下所示:
// Hash a new password for storing in the database.
// The function automatically generates a cryptographically safe salt.
string hashToStoreInDb = BCrypt.HashPassword(password);
// Check if the hash of the entered login password, matches the stored hash.
// The salt and the cost factor will be extracted from existingHashFromDb.
bool isPasswordCorrect = BCrypt.Verify(password, existingHashFromDb);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.