Frage

My developement is separated into two components :

  • The website, a Symfony application using FOSUserBundle, which encrypts password using SHA512, and a salt.
  • An authentication module, programmed in C, which should be able to reproduce the SHA512 salted hash once it's given the salt, and the cleartext password.

Some information about my environment

  • I'm using Linux Ubuntu 12.04.
  • ldd --version answers EGLIBC 2.15-0ubuntu10.4 2.15 (maybe I need 2.7 ? But apt-get is a real PAIN when it comes to upgrading packages correctly).
  • The crypt.h header files mentions @(#)crypt.h 1.5 12/20/96

The problem itself

My problem occurs in the authentication module : I'm unable to get the same hash as the one produced by Symfony's FOSUserBundle. Here's my example :

  • The password salt, used by Symfony, is bcccy6eiye8kg44scw0wk8g4g0wc0sk.
  • The password itself is test

With this information, Symfony stores this final hash :

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

Now, in my C authentication module, I run this piece of code (crypt.h is included) :

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);

(here is my base64 encoder : http://libremail.tuxfamily.org/sources/base64-c.htm)

And this outputs...

JDYkYg==

Which is completely different from my Symfony2 hash.

Browsing Stack Overflow, I found this question (Symfony2 (FOSUserBundle) SHA512 hash doesn't match C# SHA512 hash) written by someone encountering the same issue (with C# though). So I decided to run this test...

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);

Of course, it was a complete failure, I got :

JDYkYmNjY3k2ZWl5ZThrZzQ0cyRycmN6TnpJUXFOYU1VRlZvMA==

I've tried mixing the password and the salt in various ways, but I could never get the Symfony's salt in the authentication module. Is there something I've missed on the way ? Have I misunderstood the way Symfony's FOSUserBundle stores passwords ?

War es hilfreich?

Lösung

Not really an answer but I'm guessing you have not looked into how Symfony encodes passwords in any great detail? The encoding process is tucked away into an encoder object. For SHA512 we use:

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.'}';
}

As you can see, one immediate problem is that hashing is repeated 5000 times by default. This (as well as the other inputs can all be adjusted in you app/config/security.yml file).

You can also see where the salt and password get merged together. Which explains the other stackoverflow answer.

It would be trivial to make a symfony command to just run this encoding algorithm from the symfony console for testing. After that is just a question of adjusting the inputs or tweaking your C code until the results match.

If you are lucky then all your will have to do is add the iteration loop.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top