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; | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | } |