57 lines
2.2 KiB
C#
57 lines
2.2 KiB
C#
using System.Security.Cryptography;
|
|
using System.Text;
|
|
|
|
namespace PasswordMigrationUtil
|
|
{
|
|
public class PasswordHasherService
|
|
{
|
|
private const int SaltSize = 16; // 128 bit
|
|
private const int HashSize = 32; // 256 bit
|
|
private const int Iterations = 10000; // Número de iteraciones (ajustable)
|
|
|
|
// Genera un hash y una salt para una contraseña dada
|
|
public (string hash, string salt) HashPassword(string password)
|
|
{
|
|
// Generar una salt aleatoria
|
|
byte[] saltBytes = RandomNumberGenerator.GetBytes(SaltSize);
|
|
|
|
// Crear el hash usando PBKDF2
|
|
var pbkdf2 = new Rfc2898DeriveBytes(password, saltBytes, Iterations, HashAlgorithmName.SHA256);
|
|
byte[] hashBytes = pbkdf2.GetBytes(HashSize);
|
|
|
|
// Convertir bytes a strings Base64 para almacenamiento
|
|
string saltString = Convert.ToBase64String(saltBytes);
|
|
string hashString = Convert.ToBase64String(hashBytes);
|
|
|
|
return (hashString, saltString);
|
|
}
|
|
|
|
// Verifica si una contraseña coincide con un hash y salt almacenados
|
|
public bool VerifyPassword(string password, string storedHash, string storedSalt)
|
|
{
|
|
try
|
|
{
|
|
// Convertir strings Base64 de vuelta a bytes
|
|
byte[] saltBytes = Convert.FromBase64String(storedSalt);
|
|
byte[] storedHashBytes = Convert.FromBase64String(storedHash);
|
|
|
|
// Crear el hash de la contraseña ingresada usando la misma salt e iteraciones
|
|
var pbkdf2 = new Rfc2898DeriveBytes(password, saltBytes, Iterations, HashAlgorithmName.SHA256);
|
|
byte[] testHashBytes = pbkdf2.GetBytes(HashSize);
|
|
|
|
// Comparar los hashes de forma segura (evita timing attacks)
|
|
return CryptographicOperations.FixedTimeEquals(storedHashBytes, testHashBytes);
|
|
}
|
|
catch (FormatException)
|
|
{
|
|
// Manejar el caso donde las strings almacenadas no son Base64 válidas
|
|
return false;
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// Loggear la excepción si es necesario
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
} |