web-dev-qa-db-ja.com

C#でハッシュパスワード? Bcrypt / PBKDF2

私はこれを行う方法についてmsdnと他のリソースを調べましたが、明確な解決策が見つかりませんでした。これは私が見つけた最高のものです http://blogs.msdn.com/b/shawnfa/archive/2004/04/14/generated-a-key-from-a-password.aspx?Redirected=true

BcryptまたはPBKDF2(bcryptに関連すると思われる)を使用して、C#でパスワードをハッシュしたいと思います。私は自分のコンピューターがパスワードをハッシュするのに何ラウンドかかるか試してみたい。しかし、誰もがハッシュについて話す間、すべては暗号化についてのようです。わかりません。パスワードをハッシュするにはどうすればよいですか? PBKDF2(Rfc2898?)は乱数ジェネレーターであり、GetBytes(amount)を使用してハッシュサイズを選択します。

よくわかりません。 bcrypt/PBKDFを使用してパスワードを正確にハッシュするにはどうすればよいですか?

36
user34537

PBKDF2

あなたは実際に本当に近くにいました。指定したリンクは、PBKDF2ハッシュ結果を取得するために Rfc2898DeriveBytes 関数を呼び出す方法を示しています。ただし、この例では暗号化の目的で派生キーを使用しているという事実に失敗しました(PBKDF1および2の当初の動機は、暗号化キーとして使用するのに適した「キー」派生関数を作成することでした)。もちろん、暗号化に出力を使用するのではなく、独自のハッシュとして使用します。

PBKDF2が必要な場合は、まさにこの目的のために書かれた SimpleCrypto.Net ライブラリを試すことができます。 実装を見る の場合、実際には(ご想像のとおり)単なる薄いラッパー Rfc2898DeriveBytes であることがわかります。

Bクリプト

このバリアントを試してみたい場合は、(その他) BCrypt.NET という名前のC#実装を試すことができます。

免責事項:リンクしたライブラリを使用またはテストしていません... YMMV

33
paracycle

永久に (何日もかかった日)から 実際にコーディングするものを見つける がハッシュされたパスワードを機能させるのにかかった!!便宜上、ここに配置します。

documentation および theory1theory2 を読む必要があります。その後、セキュリティホールにさらされる可能性があります。セキュリティは非常に大きなトピックです!バイヤーは注意してください!

NuGetパッケージBCrypt.Netをソリューションに追加します

const int WorkFactor = 14;
var HashedPassword = BCrypt.Net.BCrypt.HashPassword(Password, WorkFactor); 

WorkFactor を適切なものに調整する必要があります discussions を参照してください。その log2関数

「数値はlog2なので、コンピューターの速度が2倍になるたびに、デフォルトの数値に1を加算します。」

次に、ハッシュされたパスワードをpasswordFromLocalDBとしてデータベースに保存し、着信passwordを次のようにテストします。

if (BCrypt.Net.BCrypt.Verify(password, passwordFromLocalDB) == true)

幸運を!

9
JPK

今年の初めに、ASP.NET Webフォームプロジェクトのハッシュを作成するために同じことを検討していましたが、MVCプロジェクトがそのまま使用するのと同じ方法でやりたいと思いました。

私はこの質問につまずいた=> ASP.NET Identity Default Password Hasher、どのように機能し、安全ですか? ここでByteArraysEqualメソッドを使用してソースを見つけました=> http:/ /www.symbolsource.org/MyGet/Metadata/aspnetwebstacknightly/Project/Microsoft.AspNet.Identity.Core/2.0.0-rtm-140327/Release/Default/Microsoft.AspNet.Identity.Core/Microsoft.AspNet.Identity.Core /Crypto.cs?ImageName=Microsoft.AspNet.Identity.Core

3
Luke T O'Brien

まず第一に、プラットフォーム自体に含まれる暗号で検証された参照アルゴリズムを使用するよう皆に促します。

サードパーティのパッケージおよび検証されていないOSSコンポーネントまたはインターネットからコピーアンドペーストした他のコードを使用しないでください。

.NETの場合PBKDF2not bCryptを使用してください。 bCrypt for .NET

私は高貴なオープンソース開発者(自分自身である)に対する軽視を意味するものではありませんが、彼らのWebサイトが10年以内にハッキングされないことは決して保証できません。パッケージマネージャー。

検証の詳細については、 this SO answer

さて、PBKDF2に戻って、ここに簡単なコードがあります

public static byte[] PBKDF2Hash(string input, byte[] salt)
{
    // Generate the hash
    Rfc2898DeriveBytes pbkdf2 = new Rfc2898DeriveBytes(input, salt, iterations: 5000);
    return pbkdf2.GetBytes(20); //20 bytes length is 160 bits
}

ハッシュの文字列表現(バイト配列ではない)が必要な場合-この回答からこの超高速変換クラスを使用できます http://stackoverflow.com/a/624379/7147

2
Alex

PBKDF2はHMACSHA1を使用します。より近代的でカスタマイズ可能なソリューションが必要な場合は、PBKDF2と同じようにキーストレッチを行うHMACSHA256または512を使用してこのAPIをご覧ください。

https://sourceforge.net/projects/pwdtknet/

ソースコードに含まれるサンプルGUIは、暗号ランダムソルトの作成を含むパスワードからハッシュを取得する方法を示しました。

1
thashiznets

Microsoftは、.Net Coreを使用しているユーザー向けにPBKDF2を使用したサンプルコードを掲載しています。

ASP.NET Coreのハッシュパスワード

記事から:

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 secure PRNG
        byte[] salt = new byte[128 / 8];
        using (var rng = RandomNumberGenerator.Create())
        {
            rng.GetBytes(salt);
        }
        Console.WriteLine($"Salt: {Convert.ToBase64String(salt)}");

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

/*
 * SAMPLE OUTPUT
 *
 * Enter a password: Xtw9NMgx
 * Salt: NZsP6NnmfBuYeJrrAKNuVQ==
 * Hashed: /OOoOer10+tGwTRDTrQSoeCxVTFr6dtYly7d0cPxIak=
 */
1
pcdev

PBKDF2の場合、System.Security.Cryptography.Rfc2898DeriveBytesを使用できる場合があります。

こちらのMSDNを参照してください: http://msdn.Microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.aspx

1
Jay S

PBKDF2

http://msdn.Microsoft.com/en-us/library/system.security.cryptography.rfc2898derivebytes.aspx の例では、「Rfc2898DeriveBytes k1 = new Rfc2898DeriveBytes( pwd1、salt1、myIterations); "、k1はハッシュです。この例が暗号化の理由は、Rfc2898DeriveBytesが元々暗号化キーを作成するように設計されていたためです。

ソルトを提供しない場合、Rfc2898DeriveBytesは独自に作成しますが、RNGCryptoServiceProviderが暗号的にランダムであるというより良い仕事をするかどうかはわかりません。

OWASP( https://www.owasp.org/index.php/Using_Rfc2898DeriveBytes_for_PBKDF2 )によると、Rfc2898DeriveBytesによるSHA1の基本的な使用は、長さが160ビットまでのハッシュにのみ適していることを意味します。より長いハッシュを作成する場合、攻撃者は最初の160ビットだけを心配する必要がありますが、パスワードハッシュ/認証は自分にとってはコストがかかり、利益はありません。

Rfc2898DeriveBytesパスワードハッシュのサンプルコードを次に示します(ハッシュ、ソルト、および反復をDBに保存します)。

public class Rfc2898PasswordEncoder
{
    private int _byteLength = 160 / 8; // 160 bit hash length

    public class EncodedPassword
    {
        public byte[] Hash { get; set; }
        public byte[] Salt { get; set; }
        public int Iterations { get; set; }
    }

    public EncodedPassword EncodePassword(string password, int iterations)
    {
        var populatedPassword = new EncodedPassword
        {
            Salt = CreateSalt(),
            Iterations = iterations
        };

        // Add Hash
        populatedPassword.Hash = CreateHash(password, populatedPassword.Salt, iterations);

        return populatedPassword;
    }

    public bool ValidatePassword(string password, EncodedPassword encodedPassword)
    {
        // Create Hash
        var testHash = CreateHash(password, encodedPassword.Salt, encodedPassword.Iterations);

        return testHash == encodedPassword.Hash;
    }

    public byte[] CreateSalt()
    {
        var salt = new byte[_byteLength]; // Salt should be same length as hash

        using (var saltGenerator = new RNGCryptoServiceProvider())
        {
            saltGenerator.GetBytes(salt);
        }

        return salt;
    }

    private byte[] CreateHash(string password, byte[] salt, long iterations)
    {
        byte[] hash;
        using (var hashGenerator = new Rfc2898DeriveBytes(password, salt, (int)iterations))
        {
            hash = hashGenerator.GetBytes(_byteLength);
        }

        return hash;
    }
} 
0
Phil