web-dev-qa-db-ja.com

bcryptの推奨されるラウンド数

今日(2012年7月)の平均的なWebサイトのパスワードのハッシュに推奨されるbcryptラウンドの数(名前、メールアドレス、自宅のアドレスのみを保存し、クレジットカードや医療情報は保存しない)はどれくらいですか?

言い換えれば、bcryptパスワードクラッキングコミュニティの現在の機能は何ですか?いくつかのbcryptライブラリは、デフォルト設定として12ラウンド(2 ^ 12反復)を使用します。それは推奨される作業要素ですか? 6ラウンドは十分強力ではないでしょうか(これはたまたまJavaScriptでのクライアント側のbcryptハッシュの制限です。参照 挑戦的なチャレンジ:クライアント側のパスワードハッシュとサーバー側のパスワード検証 )?

私は回答を読みました https://security.stackexchange.com/a/3993/11197 これは、さまざまな要因のバランスを取る方法を詳細に説明します(PBKDF2-SHA256の場合は)。しかし、私は実際の数を探しています。経験則。

94
Jason Smith

あなたのすべての質問に対する答えはすでに Thomas Porninの答え に含まれていると思います。あなたはそれにリンクしているので、おそらくそれについて知っていますが、もう一度読むことをお勧めします。

基本原則は次のとおりです。ラウンド数を選択しないでください。代わりに、パスワードの確認にサーバーでかかる時間を選択し、それに基づいてラウンド数を計算します。あなたが立つことができる限り検証に時間がかかることを望みます。

具体的な数値の例については、Thomas Porninの回答を参照してください。彼は、妥当な目標はパスワードの検証/ハッシュがパスワードごとに241ミリ秒かかることになると示唆しています。 (注:Thomasが最初に「8ミリ秒」と書いたが、これは誤りです。これは、1か月ではなく1日の忍耐力の数値です。)それでもサーバーは1秒あたり4つのパスワードを確認できます(並行して実行できる場合はさらに多くのパスワードが必要です)。トーマスは、これがあなたの目標である場合、約20,000ラウンドが適切な球場にあると推定しています。

ただし、最適なラウンド数はプロセッサーによって異なります。理想的には、プロセッサーにかかる時間をベンチマークし、それに応じて数を選択します。これにはそれほど時間がかかりません。したがって、最良の結果を得るには、スクリプトを作成して、サーバー上でパスワードのハッシュに約240ミリ秒(耐えられる場合はそれ以上)がかかることを保証するために必要なラウンド数を調べてください。

41
D.W.

BCryptが最初に公開されたとき、1999年に彼らは実装のデフォルトのコスト要因をリストしました:

  • 通常のユーザー:6
  • スーパーユーザー:8

彼らはまた注意します:

もちろん、人々が選択した費用は時々再評価されるべきです

Bcryptコスト6は64ラウンド(26 = 64)。

その初期「通常のユーザー」値を使用する場合は、計算のインフレを調整してみます( 平均すると18か月ごとに2倍になると仮定 )。

R = R ×2(月/ 18)
R = 64×2(月/ 18)

今日(2015年3月9日)は1999年12月31日から171か月です(または単純にするために2000年1月1日を使用します)、ラウンド数は9倍強の2倍になっているはずです。

R = 64×2(171/18)
R = 64×29.5
R = 64×724.1
R = 46,341.0

最後に、これをコスト係数に変換します

コスト= ln(R)/ ln(2)
コスト= ln(46,341.0)/ ln(2)
コスト= 15.5

15のコスト係数の実用性は、サーバーのコンピューティング能力に依存します。たとえば、私のデスクトップPCはIntel Core i7-2700K CPU @ 3.50 GHzです。私は当初、BCryptの実装を2014年1月23日にベンチマークしました。

1/23/2014  Intel Core i7-2700K CPU @ 3.50 GHz

| Cost | Iterations        |    Duration |
|------|-------------------|-------------|
|  8   |    256 iterations |     38.2 ms | <-- minimum allowed by BCrypt
|  9   |    512 iterations |     74.8 ms |
| 10   |  1,024 iterations |    152.4 ms | <-- current default (BCRYPT_COST=10)
| 11   |  2,048 iterations |    296.6 ms |
| 12   |  4,096 iterations |    594.3 ms |
| 13   |  8,192 iterations |  1,169.5 ms |
| 14   | 16,384 iterations |  2,338.8 ms |
| 15   | 32,768 iterations |  4,656.0 ms |
| 16   | 65,536 iterations |  9,302.2 ms |

しかしそれは2014年でした

これらのタイミングは、もともと2014年の初めに計算されました。私の計算では、171ヶ月ではなく156ヶ月のみを使用する必要がありました。

R = 64×2(156/18)
R = 64×28.66
R = 64×406.8
R = 26,035.2

コスト= ln(R)/ ln(2)
コスト= ln(26,035.2)/ ln(2)
コスト= 14.7

しかし、i7-2700Kはすでに廃止されました

I7-2700Kは、ベンチマークを実行した時点ですでに中止されています(2013年第1四半期)。それは2011年第4四半期にリリースされ、最先端の技術でした。2011年第4四半期の数値を実行すると、

R = 64×2(129/18)
R = 64×27.16
R = 64×143.7
R = 9,196.8

コスト= ln(R)/ ln(2)
コスト= ln(9,196.8)/ ln(2)
コスト= 13.2

13のコストは、私のデスクトップでは、 約2秒 1秒以上。

どれだけ長く耐えられますか?

これにより、元の実装者が書いたときに考慮していた遅延の種類(約0.5〜1秒)がわかります。

しかし、もちろん、あなたがより長く立つことができるほど、より良いです。私が見たすべてのBCrypt実装は、デフォルトのコストとして10を使用しました。そして 私の実装 はそれを使用しました。デフォルトのコストを12に増やす時がきたと思います。

将来の校正

ハッシュ関数を変更することもできます:

hash = HashPassword("correct battery horse stapler");

つまり、デフォルトのコストに依存している代わりに、自動的にスライドするコストを使用します。このようにして、コストは時間とともに自己増加します。変化:

String HashPassword(String password)
{
   return BCrypt.HashPassword(password, BCRYPT_DEFAULT_COST);
}

次のようなものに:

String HashPassword(String password)
{  
   /*
     Rather than using a fixed default cost, run a micro-benchmark
     to figure out how fast the CPU is.
     Use that to make sure that it takes **at least** 250ms to calculate
     the hash
   */
   Int32 costFactor = this.CalculateIdealCost();
   //Never use a cost lower than the default hard-coded cost
   if (costFactor < BCRYPT_DEFAULT_COST) 
      costFactor = BCRYPT_DEFAULT_COST;

   return BCrypt.HashPassword(password, costFactor);
}

Int32 CalculateIdealCost()
{
    //Benchmark using a cost of 5 (the second-lowest allowed)
    Int32 cost = 5;

    var sw = new Stopwatch();
    sw.Start();
    this.HashPassword("microbenchmark", cost);
    sw.Stop();

    Double durationMS = sw.Elapsed.TotalMilliseconds;

    //Increasing cost by 1 would double the run time.
    //Keep increasing cost until the estimated duration is over 250 ms
    while (durationMS < 250)
    {
       cost += 1;
       durationMS *= 2;
    }

    return cost;
}

2015年3月12日編集:速度の数値を更新しました。 Delphi XE6 32ビットコンパイラ(c.2013)は、同じプロセッサに対してDelphi 5(c.1999)が行ったよりも1桁速いコードを生成します。 Delphi XE6 64ビットコンパイラは、32ビットコンパイラよりも20%遅いコードを生成します。

61
Ian Boyd

Sequential Memory-Hard関数によるより強力なキーの導出 は、キーストレッチングのトピックに関する非常に優れた論文です。 14ページでは、さまざまなハッシュアルゴリズムと、ハッシュを解読するのにかかる費用を比較しています。これは、これらのことについて考えるのに便利な方法です。 (余談ですが、TPMが利用できない場合、ChromeOSはScryptを使用します。)

考えられるのは、これらのパスワードハッシュをできるだけ長く解読しないようにすることです。ムーアの法則では、これは指数関数的に速く移動するターゲットです。 Scryptは可変量のメモリとCPUを使用します。この変数は時間の関数として重くなる可能性があります。そのため、クライアントがログインするたびに、パスワードハッシュを更新してより安全にすることができます。 PBKDF2の場合、これはrounds=2^(current_year-2000)などのようになります。

この処理をクライアントにオフロードして、プロトコルの安全性を期待することはできないことに注意することが重要です。私が知っているすべてのクライアント側のハッシュ認証プロトコルでは、サーバーが認証資格情報を検証するために同じ計算を行う必要があります(NTLM、NTLMv2、SRP、WPA-PSK ...)。

3
rook