2

私の開発は 2 つのコンポーネントに分かれています。

  • ウェブサイト、SHA512 を使用してパスワードを暗号化する FOSUserBundle を使用する Symfony アプリケーション、およびソルト。
  • C でプログラムされた認証モジュール。ソルトとクリアテキスト パスワードが与えられると、SHA512 ソルト付きハッシュを再現できるはずです。

私の環境に関するいくつかの情報

  • Linux Ubuntu 12.04 を使用しています。
  • ldd --version回答EGLIBC 2.15-0ubuntu10.4 2.15 (おそらく 2.7 が必要ですか?しかしapt-get、パッケージを正しくアップグレードすることになると、本当に苦痛です)。
  • crypt.hヘッダー ファイルには、@(#)crypt.h 1.5 12/20/96が記載されています。

問題そのもの

私の問題は認証モジュールで発生します: Symfony の FOSUserBundle によって生成されたものと同じハッシュを取得できません。これが私の例です:

  • Symfony が使用するパスワード salt はbcccy6eiye8kg44scw0wk8g4g0wc0sk.
  • パスワード自体はtest

この情報を使用して、Symfony はこの最終ハッシュを保存します。

fH5vVoACB4e8h1GX81n+aYiRkSWxeu4TmDibNChtLNZS3jmFKBZijGCXcfzCSJFg+YvNthxefHOBk65m/U+3OA==

ここで、私の C 認証モジュールで、次のコードを実行します (crypt.h含まれています)。

char* password = "test";
char* salt = "$6$bcccy6eiye8kg44scw0wk8g4g0wc0sk";

char* hash = malloc(256);
memset(hash, 0, 256);

encode64(crypt(password, salt), hash, strlen(password));
fprintf(stdout, "%s\n", hash);

(これが私の base64 エンコーダーです: http://libremail.tuxfamily.org/sources/base64-c.htm )

そして、これは出力します...

JDYkYg==

これは、私の Symfony2 ハッシュとは完全に異なります。

スタックオーバーフローをブラウジングすると、同じ問題に遭遇した人によって書かれたこの質問 ( Symfony2 (FOSUserBundle) SHA512 hash does not match C# SHA512 hash ) が見つかりました (C# で)。だから私はこのテストを実行することにしました...

char* password = "test{bcccy6eiye8kg44scw0wk8g4g0wc0sk}";
char* salt = "$6$bcccy6eiye8kg44scw0wk8g4g0wc0sk"; // I tried without salt, or with "$6$" as well.

char* hash = malloc(256);
memset(hash, 0, 256);

encode64(crypt(password, salt), hash, strlen(password));
fprintf(stdout, "%s\n", hash);

もちろん、それは完全な失敗でした。

JDYkYmNjY3k2ZWl5ZThrZzQ0cyRycmN6TnpJUXFOYU1VRlZvMA==

さまざまな方法でパスワードとソルトを混ぜてみましたが、認証モジュールで Symfony のソルトを取得できませんでした。途中で見逃したものはありますか?Symfony の FOSUserBundle がパスワードを保存する方法を誤解していませんか?

4

1 に答える 1

4

本当の答えではありませんが、Symfony がパスワードをどのようにエンコードするかを詳細に調べていないと思いますか? エンコーディング プロセスはエンコーダ オブジェクトに隠されています。SHA512 の場合、以下を使用します。

namespace Symfony\Component\Security\Core\Encoder;

class MessageDigestPasswordEncoder extends BasePasswordEncoder
{
/**
 * Constructor.
 *
 * @param string  $algorithm          The digest algorithm to use
 * @param Boolean $encodeHashAsBase64 Whether to base64 encode the password hash
 * @param integer $iterations         The number of iterations to use to stretch the password hash
 */
public function __construct($algorithm = 'sha512', $encodeHashAsBase64 = true, $iterations = 5000)
{
    $this->algorithm = $algorithm;
    $this->encodeHashAsBase64 = $encodeHashAsBase64;
    $this->iterations = $iterations;
}
public function encodePassword($raw, $salt)
{
    if (!in_array($this->algorithm, hash_algos(), true)) {
        throw new \LogicException(sprintf('The algorithm "%s" is not supported.', $this->algorithm));
    }

    $salted = $this->mergePasswordAndSalt($raw, $salt);
    $digest = hash($this->algorithm, $salted, true);

    // "stretch" hash
    for ($i = 1; $i < $this->iterations; $i++) {
        $digest = hash($this->algorithm, $digest.$salted, true);
    }

    return $this->encodeHashAsBase64 ? base64_encode($digest) : bin2hex($digest);
}
public function isPasswordValid($encoded, $raw, $salt)
{
    return $this->comparePasswords($encoded, $this->encodePassword($raw, $salt));
}
protected function mergePasswordAndSalt($password, $salt)
{
    if (empty($salt)) {
        return $password;
    }

    if (false !== strrpos($salt, '{') || false !== strrpos($salt, '}')) {
        throw new \InvalidArgumentException('Cannot use { or } in salt.');
    }

    return $password.'{'.$salt.'}';
}

ご覧のとおり、差し迫った問題の 1 つは、デフォルトでハッシュが 5000 回繰り返されることです。これ (およびその他の入力はすべて app/config/security.yml ファイルで調整できます)。

また、ソルトとパスワードがマージされる場所も確認できます。これは、他のstackoverflowの回答を説明しています。

テストのために symfony コンソールからこのエンコーディングアルゴリズムを実行するだけの symfony コマンドを作成するのは簡単です。その後は、入力を調整するか、結果が一致するまで C コードを微調整するだけです。

運が良ければ、反復ループを追加するだけです。

于 2013-08-17T18:20:14.523 に答える