web-dev-qa-db-ja.com

パスワードをハッシュするときに反復を実装する方法は?

パスワードを安全にハッシュするために、PBKDF2などのアルゴリズムは、SHA1などの一般的なハッシュを何度も繰り返します。安全のためにこれらの反復を実行する必要がある特定の方法はありますか?

特に、 password-hash.js から:

function generateHash(algorithm, salt, password, iterations) {
  iterations = iterations || 1;
  try {
    var hash = password;
    for(var i=0; i<iterations; ++i) {
      hash = crypto.createHmac(algorithm, salt).update(hash).digest('hex');
    }

    return algorithm + '$' + salt + '$' + iterations + '$' + hash;
  } catch (e) {
    throw new Error('Invalid message digest algorithm');
  }
}

これはパスワードをハッシュ化する安全な方法ですか?このようなアルゴリズムがあれば、次のようになると想像できます。

HMAC(HMAC(HMAC(password)))

その後、いくつかのより高速な機能が存在します

HMAC3(password)

同じ出力が得られます。これは事実ですか?

1
Sjoerd

はい、反復ハッシュ関数にはいくつかの要件があります。

  • Rainbowテーブルを使用するなど、事前計算を行うことはできません。
  • 実装では、ハッシュ関数での循環や固定小数点の実行を避ける必要があります。
  • 攻撃者が使用するため、実装は可能な限り高速である必要があります。

特に最後のポイントでは、サンプルコードが欠けています。 crypto.createHmac(algorithm, salt)は、ループの外にある必要があります。攻撃者は同じソルトで多くのパスワードをハッシュするため、createHmac呼び出しをパスワードループの外に置くこともできます。

_hmac = crypto.createHmac(algorithm, salt)
for (password in allpasswords) {
    var hash = password;
    for(var i=0; i<iterations; ++i) {
        hash = hmac.update(hash).digest('hex');
    }
    ...
}
_

これにより、攻撃者はパスワードをクラックするときに利点を得ることができます。これは、PBKDF2のように、HMACがソルトではなくパスワードをキーとして使用した場合に回避されます。

Cで指定されたコードを実装する といくつかの最適化を行うことにより、元のNodeJS実装よりも10倍速くなるようにしました。これは、攻撃者がGPUやFPGAを使用しなくても、意図したよりも10倍速くパスワードを解読できることを意味します。

つまり、HMACがすべての反復でほぼ同じ処理を行うため、doesHMAC(HMAC(HMAC(password)))の高速バージョンを実行する関数が存在します。

これについて ブログ投稿 と書きました。

2
Sjoerd