
The hmac-bcrypt password hashing function
このリポジトリには、hmac-bcrypt パスワードハッシュ関数のリファレンス実装が複数の言語で含まれています。各リファレンス実装は、可能な限り @epixoip によって作成されたオリジナルのCおよびPerl実装の1:1ポートとなることを試みており、相互に完全に互換性があります(つまり、同じハッシュ値を生成・検証します)。
各リファレンス実装は、以下の擬似プロトタイプを持つ2つの手続き型関数を定義しています。
string hmac_bcrypt_hash(password, settings?, pepper?)
boolean hmac_bcrypt_verify(password, expected, pepper?)
これらの関数をプロジェクトに統合して使用する方法については、各リファレンス実装に付属するテストケースを参照してください。シンプルさのために手続き型インターフェースが選択されましたが、必要に応じてクラスやオブジェクトにこれらの関数を組み込むことは自由です。
この文脈での settings パラメータは、ハッシュ識別子(2a)、log2コスト(例: 13)、およびオプションの22バイトのradix64エンコードされたソルト値(例: LhayLxezLhK1LhWvKxCyLO)を含む標準的なbcrypt設定文字列を指します。これらの値はドル記号で区切られた文字列に連結されます。例: $2a$13$LhayLxezLhK1LhWvKxCyLO。
settings パラメータはオプションです。通常は、デフォルトのコスト 13 と生成されたソルトを使用するために、null/空のままにするべきです。せいぜい、13 以外のコスト値を使用したい場合に、id + コスト値のみ(例: $2a$10$)を指定できます。独自のソルト値を作成して指定することは推奨されません!
pepper パラメータはグローバルな共有シークレットを定義し、同じくオプションです。null/空白の場合、デフォルト値の hmac_bcrypt が使用されます。これは主にshucking攻撃への防御のためですが、セキュリティ、難易度、クラッキングコストを高めるためにも使用できます(特にHSMと併用する場合)。
hmac-bcrypt パスワードハッシュ関数は、適切な事前ハッシュと事後ハッシュを備えたbcryptを、オプションのペッパーと組み合わせて使用します。擬似コードでは、これはかなり単純です:
pre_hash = hmac_sha512_base64(password, pepper)
mid_hash = bcrypt(pre_hash, settings)
post_hash = hmac_sha512_base64(mid_hash, pepper)
return settings + post_hash
事前ハッシュは、bcryptの最大入力長である72バイトを超える入力長を可能にするために使用されます。SHA-512は、64ビットのワードサイズのため選択されました。これはCPU側の防御には有利ですが、GPU側の攻撃者には不利に働きます。ただし、生のSHA-512値はいくつかの理由で使用できません:
shucking攻撃を緩和するために、事前ハッシュはソルト処理される必要があります。この場合はペッパー処理ですが、HMACはハッシュにキーを与えるための便利な手段を提供します。得られたHMAC値はbase64でエンコードされ、nullバイトやバイナリデータに関する問題を緩和するクリーンなlower-ASCII入力が生成されます。
鋭い読者は、hmac_sha512_base64が88バイトのデータを生成する一方、bcryptの最大入力サイズが72バイトであることに気付くでしょう。これは問題ではなく、実際にはsha256などより少ない入力データを生成するハッシュアルゴリズムを使用するよりも好まれます。72バイトすべてを埋めたいのであり、sha512を432ビットに切り詰めても安全性は失われません(これはsha384が提供する384ビットよりも大きい値です)。
事後ハッシュは、主にhmac-bcryptハッシュをbcryptハッシュと区別するために使用されます(つまり、長さが異なります)。また、ペッパーによる追加の保護層を追加するためでもあります。事後ハッシュのステップは、さらに保護を強化するために、HSMに保存されたペッパー値を使用して実行することもできます(強く推奨!)。
メモリハードネスは興味深い実験でしたが、加速への耐性を達成するための正しい道は、明らかにキャッシュハードネスです。メモリの速度と帯域幅は増加し続ける一方、RAMはより大きく、安価で、高密度になっています。しかし、キャッシュサイズ、キャッシュ速度、キャッシュコストは比較的一定です。ハードウェアのscatter/gather命令でさえ、かつてキャッシュハードアルゴリズムに与えるかもしれないと予測したほどの劇的な影響はありませんでした。
最も優れたメモリハードアルゴリズムであるArgon2とscryptは、実際にはターゲット実行時間が1000ms未満の場合、キャッシュハードアルゴリズムよりも加速への耐性が低く、優れたKDFではあるものの、リアルタイム認証にはあまり適していません。
理想的には、pufferfishやbscryptなどの意図的にキャッシュハードなパスワードハッシュ関数を使用することです。しかし、これらの関数は新しく、研究が進んでおらず、利用可能なライブラリもほとんどありません。一方、bcryptは意図せずキャッシュハードではありますが、事実上すべての言語とフレームワークで簡単に利用できます。私たちが容易に利用できるアルゴリズムの中で、bcryptはリアルタイムのインタラクティブ認証(ターゲット実行時間 < 1000ms)において最も加速への耐性を提供するため、明白な答えは利用可能なbcryptを活用することです。
ただし、bcryptにはいくつかの顕著な制限もあります。これは、非常に声の大きな批評家たちがすぐに指摘するとおりです:
hmac-bcryptはこれらの両方の問題に対処し、さらにそれ以上のことを行います。