2

我的开发分为两个部分:

  • 该网站是一个使用 FOSUserBundle 的 Symfony 应用程序,该应用程序使用 SHA512 和盐来加密密码。
  • 一个用 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 doesn't 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.'}';
}

如您所见,一个直接的问题是哈希默认重复 5000 次。这(以及其他输入都可以在您的 app/config/security.yml 文件中进行调整)。

您还可以看到盐和密码在哪里合并在一起。这解释了另一个stackoverflow答案。

编写一个 symfony 命令来从 symfony 控制台运行这个编码算法进行测试是微不足道的。之后就是调整输入或调整 C 代码直到结果匹配的问题。

如果你很幸运,那么你所要做的就是添加迭代循环。

于 2013-08-17T18:20:14.523 回答