Contraseñas hash en ASP.NET Core

En este artículo se muestra cómo llamar al método KeyDerivation.Pbkdf2 que permite aplicar hash a una contraseña mediante el algoritmo PBKDF2.

Advertencia

La API KeyDerivation.Pbkdf2 es un primitivo criptográfico de bajo nivel y está pensado para integrar aplicaciones en un protocolo o sistema criptográfico existente. KeyDerivation.Pbkdf2 no debe usarse en nuevas aplicaciones que admitan el inicio de sesión basado en contraseñas y necesiten almacenar contraseñas con hash en un almacén de datos. Las nuevas aplicaciones deben usar PasswordHasher. Para obtener más información sobre PasswordHasher, vea Explorar el IdentityPasswordHasher de ASP.NET Core.

La base de código de protección de datos incluye un paquete NuGet Microsoft.AspNetCore.Cryptography.KeyDerivation que contiene funciones de derivación de claves criptográficas. Este paquete es un componente independiente y no tiene dependencias en el rest del sistema de protección de datos. Se puede usar de forma independiente. El origen existe junto con la base de código de protección de datos por comodidad.

Advertencia

En el código siguiente se muestra cómo usar KeyDerivation.Pbkdf2 para generar una clave secreta compartida. No se debe usar para aplicar un hash a una contraseña para el almacenamiento en un almacén de datos.

using Microsoft.AspNetCore.Cryptography.KeyDerivation;
using System.Security.Cryptography;

Console.Write("Enter a password: ");
string? password = Console.ReadLine();

// Generate a 128-bit salt using a sequence of
// cryptographically strong random bytes.
byte[] salt = RandomNumberGenerator.GetBytes(128 / 8); // divide by 8 to convert bits to bytes
Console.WriteLine($"Salt: {Convert.ToBase64String(salt)}");

// derive a 256-bit subkey (use HMACSHA256 with 100,000 iterations)
string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
    password: password!,
    salt: salt,
    prf: KeyDerivationPrf.HMACSHA256,
    iterationCount: 100000,
    numBytesRequested: 256 / 8));

Console.WriteLine($"Hashed: {hashed}");

/*
 * SAMPLE OUTPUT
 *
 * Enter a password: Xtw9NMgx
 * Salt: CGYzqeN4plZekNC88Umm1Q==
 * Hashed: Gt9Yc4AiIvmsC1QQbe2RZsCIqvoYlst2xbz0Fs8aHnw=
 */
using System;
using System.Security.Cryptography;
using Microsoft.AspNetCore.Cryptography.KeyDerivation;

public class Program
{
    public static void Main(string[] args)
    {
        Console.Write("Enter a password: ");
        string password = Console.ReadLine();

        // generate a 128-bit salt using a cryptographically strong random sequence of nonzero values
        byte[] salt = new byte[128 / 8];
        using (var rngCsp = new RNGCryptoServiceProvider())
        {
            rngCsp.GetNonZeroBytes(salt);
        }
        Console.WriteLine($"Salt: {Convert.ToBase64String(salt)}");

        // derive a 256-bit subkey (use HMACSHA256 with 100,000 iterations)
        string hashed = Convert.ToBase64String(KeyDerivation.Pbkdf2(
            password: password,
            salt: salt,
            prf: KeyDerivationPrf.HMACSHA256,
            iterationCount: 100000,
            numBytesRequested: 256 / 8));
        Console.WriteLine($"Hashed: {hashed}");
    }
}

/*
 * SAMPLE OUTPUT
 *
 * Enter a password: Xtw9NMgx
 * Salt: CGYzqeN4plZekNC88Umm1Q==
 * Hashed: Gt9Yc4AiIvmsC1QQbe2RZsCIqvoYlst2xbz0Fs8aHnw=
 */
 

Consulte el código fuente del tipo de PasswordHasher de ASP.NET CoreIdentity para ver un caso de uso real.

Nota

Los vínculos de la documentación al origen de referencia de .NET cargan normalmente la rama predeterminada del repositorio, que representa el desarrollo actual para la próxima versión de .NET. Para seleccionar una etiqueta de una versión específica, usa la lista desplegable Cambiar ramas o etiquetas. Para obtener más información, vea Procedimientos para seleccionar una etiqueta de versión de código fuente de ASP.NET Core (dotnet/AspNetCore.Docs #26205).