環境
.NET Core Sdk 3.0.100、C# の言語バージョンは 8 です。
$ dotnet --version
3.0.100
自前でハッシュ化する
DB にパスワードを保存する際、セキュリティのため平文のままではなくハッシュ化してから保存したい場合があります。
下記は文字列をハッシュ関数SHA-256
で暗号化する例です。
// using System.Linq;
// using System.Security.Cryptography;
// using System.Text;
string password = "ハッシュ化したいテキスト";
// SHA256 デフォルト実装のインスタンスを呼び出します。
using SHA256 sha256 = SHA256.Create();
// 文字列をバイト配列にエンコードします。
byte[] encoded = Encoding.UTF8.GetBytes(password);
// ハッシュ値を計算します。
byte[] hash = sha256.ComputeHash(encoded);
// ハッシュ値を 16 進数文字列に変換します。書き方がちょっと面倒。
// System.BitConverter.ToString(hash).Replace("-", "").ToLower() と同じ。
// 16 進数文字列でなく Base64 文字列に変換する場合 -> System.Convert.ToBase64String(hash) で OK。
// 各要素を 16 進数文字列に変換して結合しています。
string hashed = string.Concat(hash.Select(b => $"{b:x2}")); // -> 93541bd68ccf06f3d4f9cf56a3ca415f1d2d315f3f672ecec9f52b0c7c3ad9fc
Microsoft.AspNetCore.Cryptography.KeyDerivation
でハッシュ化する
ただし、上記のような1度だけのハッシュ化では脆弱であるため、
- パスワードにソルトを付与して、その結果をハッシュ化する
- ハッシュ化した結果をさらに何重にもハッシュ化する
する必要があります。
そのための便利な関数が用意されてるパッケージをインストールします。
$ dotnet add package Microsoft.AspNetCore.Cryptography.KeyDerivation
// using Microsoft.AspNetCore.Cryptography.KeyDerivation;
// using System.Linq;
// using System.Security.Cryptography;
string password = "ハッシュ化したいテキスト";
// ソルトを作成する。
byte[] salt = new byte[128 / 8];
using var rng = RandomNumberGenerator.Create();
rng.GetBytes(salt);
// Pbkdf2 メソッドではハッシュ化する反復回数や作成するハッシュの長さを指定することができます。
// OS をよって最適化された実装が選択され、自前で実装するよりもパフォーマンスが向上するそうです。
// https://docs.microsoft.com/ja-jp/aspnet/core/security/data-protection/consumer-apis/password-hashing?view=aspnetcore-3.0
byte[] hash = KeyDerivation.Pbkdf2(
password,
salt,
prf: KeyDerivationPrf.HMACSHA256,
iterationCount: 10000, // 反復回数
numBytesRequested: 256 / 8); // ハッシュの長さ
// ハッシュ値を 16 進数文字列に変換します。
string hashed = string.Concat(hash.Select(b => $"{b:x2}")); // -> 93541bd68ccf06f3d4f9cf56a3ca415f1d2d315f3f672ecec9f52b0c7c3ad9fc
実際の Web アプリケーションを開発する際にはKeyDerivation.Pbkdf2
を使うことになると思います。