ASP.NET Core でパスワードをハッシュする

この記事では、RFC 2898、セクション 5.2 で説明されているように、PBKDF2 アルゴリズムを使用してパスワードをハッシュできるようにする KeyDerivation.Pbkdf2 メソッドを呼び出す方法について説明します。

KeyDerivation.Pbkdf2 API は、低レベルの暗号化プリミティブです。 使用目的は、アプリを既存のプロトコルまたは暗号化システムに統合することです。

警告

KeyDerivation.Pbkdf2 パスワードベースのサインインをサポートし、データストアにハッシュされたパスワードを格納する必要がある新しいアプリでは使用しないでください。 新しいアプリでは PasswordHasher クラスを使用する 必要があります。 詳細については、ASP.NET Core Identity PasswordHasher のしくみを探るを参照してください。

データ保護コードベースには、暗号鍵導出関数を含む NuGet パッケージ Microsoft.AspNetCore.Cryptography.KeyDerivation が含まれています。 このパッケージはスタンドアロン コンポーネントであり、データ保護システムの残りの部分には依存しません。 パッケージは個別に使用できます。 便宜上、ソースはデータ保護コード ベースと併置されています。

'KeyDerivation.Pbkdf2' を使用してキーを生成する

次のコードは、 KeyDerivation.Pbkdf2 メソッドを使用して共有秘密鍵を生成する方法を示しています。

警告

データストア内のストレージのパスワードをハッシュするために KeyDerivation.Pbkdf2 メソッドを呼び出さないでください。

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=
 */
 

ASP.NET Core IdentityPasswordHasher 型の実際のユース ケースについては、GitHubの source コードを参照してください。

通常、.NET 参照ソースへのドキュメント リンクを使用すると、リポジトリの既定のブランチが読み込まれます。このブランチは、.NET の次回リリースに向けて行われている現在の開発を表します。 特定のリリースのタグを選択するには、[Switch branches or tags](ブランチまたはタグの切り替え) ドロップダウン リストを使います。 詳細については、「ASP.NET Core ソース コードのバージョン タグを選択する方法」 (dotnet/AspNetCore.Docs #26205) を参照してください。