この時代、自前でパスワードの管理などしたくはないのですが、しないといけないケースもあるでしょう。最低限やらないといけないこととしては、ソルト生成した上でハッシュ化したパスワードを保存することではないでしょうか。.NET Coreでこれらの処理を行う必要があった時に調べたコードをまとめます。
まずソルトを作成する場合、.NET CoreではRNGCryptoServiceProvider
クラスを使って暗号論的に乱数を生成します。GetBytes
メソッドは、引数に指定したbyte配列を、生成した乱数で埋めます。
次にパスワードのハッシュ化ですが、PBKDF2を利用する場合、Rfc2898DeriveBytes
クラスを利用できます。ハッシュ化対象の文字列、ソルト、反復回数、ハッシュアルゴリズム名を指定できます。ハッシュアルゴリズムはデフォルトがSHA1なので適宜変更しましょう。
以上をまとめてコードにするとこうなります。hashedPassword
はbyte配列なので適宜保存しましょう。
using System.Collections.Generic; using System.Security.Cryptography; var password = "<入力されたパスワード>"; //必要な長さ分の配列を先に用意する var salt = new byte[1024]; //RNGCryptoServiceProviderはIDisposableを実装しているので適宜破棄する using var rng = new RNGCryptoServiceProvider() rng.GetBytes(salt); var b = new Rfc2898DeriveBytes(password, salt, 100, HashAlgorithmName.SHA256); var hashedPassword = b.GetBytes(256);
ソルトとハッシュ値を保存しておき、入力されたパスワードと照合する場合は、保存したソルトを使って、同じ反復回数、ハッシュアルゴリズムでハッシュ化し、両者を比べます。byte配列なのでSequenceEqual
メソッドを使っています。
using System.Collections.Generic; using System.Security.Cryptography; using System.Linq; var password = "<入力されたパスワード>"; var salt = "<保存していたソルト>"; var hashedPassword = "<保存していたハッシュ値>"; var b = new Rfc2898DeriveBytes(password, salt, 100, HashAlgorithmName.SHA256); var challengePassword = b.GetBytes(256); if (!(hashedPassword?.SequenceEqual(challengePassword) == true)) { throw new Exception("ログイン失敗"); }