web-dev-qa-db-ja.com

どのようにしてbcryptはビルトイン塩を持つことができますか?

Coda Haleの記事 "パスワードを安全に保存する方法" は次のように述べています。

bcryptには、Rainbow table攻撃を防ぐための塩が組み込まれています。

彼は この論文 を引用しています。これはOpenBSDのbcryptの実装の中で次のように述べています。

OpenBSDはarcfour(arc4random(3))キーストリームから128ビットのbcryptソルトを生成します。これはカーネルがデバイスタイミングから収集したランダムなデータをシードしたものです。

これがどのように機能するのか理解できません。私の塩の概念では:

  • 保存されたパスワードごとに異なる必要があるため、それぞれに個別のRainbowテーブルを生成する必要があります。
  • ユーザーがログインしようとするとパスワードの試行を試み、最初にパスワードを保存したときと同じソルトアンドハッシュ手順を繰り返します。

私がDevise(Railsログインマネージャ)をbcryptと一緒に使っているとき、データベースにsaltカラムがないので、混乱します。塩がランダムで、どこにも保存されていない場合、どのようにしてハッシングプロセスを確実に繰り返すことができますか?

一言で言えば、bcryptはどのようにビルトイン塩を持つことができますか

535
Nathan Long

これはbcryptです:

ランダムな塩を作ります。 「コスト」要因が事前に設定されています。パスワードを収集してください。

Saltとcostの要素を使ってパスワードから暗号化キーを導出します。よく知られている文字列を暗号化するために使用します。 コストsalt、、および暗号文を格納します。これら3つの要素は長さがわかっているので、それらを連結して単一のフィールドに格納するのは簡単ですが、後でそれらを分割することもできます。

誰かが認証を試みると、保存されているコストと塩を取得します。入力したパスワード、コスト、およびソルトからキーを導き出します。同じ既知の文字列を暗号化します。生成された暗号テキストが保存されている暗号テキストと一致する場合、パスワードは一致です。

Bcryptは、PBKDF2のようなアルゴリズムに基づくより伝統的な方式と非常によく似た方法で動作します。主な違いは、既知のプレーンテキストを暗号化するための派生キーの使用です。他の方式は(合理的に)鍵導出関数が不可逆的であると仮定し、導出された鍵を直接格納します。


データベースに格納されているbcryptの「ハッシュ」は、次のようになります。

$ 2a $ 10 $ vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTa

これは実際には「$」で区切られた3つのフィールドです。

  • 2aは、使用されたbcryptアルゴリズムのバージョンを識別します。
  • 10はコスト要因です。 210年 キー導出関数の反復が使用されます(ところで、これでは不十分です。私は12以上のコストを推奨します)。
  • vI8aWBnW3fID.ZQ4/zo1G.q1lRps.9cGLcZEiGDMVr5yUP1KUOYTaはソルトと暗号テキストで、修正されたBase-64で連結およびエンコードされています。最初の22文字はsaltの16バイト値にデコードされます。残りの文字は認証のために比較される暗号文です。

この例はCoda HaleのRuby実装の ドキュメントから抜粋したものです。

694
erickson

フレーズは次のように表現されるべきだったと思います。

bcryptは生成されたハッシュに組み込まれた塩を持っています Rainbow table攻撃を防ぐために。

bcryptユーティリティ自体は塩のリストを維持しているようには見えません。そうではなく、ソルトはランダムに生成されて関数の出力に追加されるので、後で Java実装のbcrypt に従って記憶されます)。別の言い方をすれば、bcryptによって生成される "ハッシュ"はjustハッシュではありません。むしろ、それはハッシュおよび連結されたソルトです。

162
Adam Paynter

これはSpring SecurityのPasswordEncoderインターフェースドキュメントからのものです。

 * @param rawPassword the raw password to encode and match
 * @param encodedPassword the encoded password from storage to compare with
 * @return true if the raw password, after encoding, matches the encoded password from
 * storage
 */
boolean matches(CharSequence rawPassword, String encodedPassword);

つまり、次回のログイン時にユーザーが再度入力するrawPasswordと、前回のログイン/登録時にデータベースに保存されているBcryptでエンコードされたパスワードとを照合する必要があります。

0
Meet Shah