Search code examples
phppassword-hash

Questions regarding PHP's password_hash()


I have a few question regarding PHP's password_hash function.

I've noticed that if do

echo password_hash("12345", PASSWORD_DEFAULT);

then I get somethng like

$2y$10$PgMmle9Ue4o3m7ITJcGa0ucmWXSZgqbJBF9I4qd/aqzn/vQIwbi/O

So my questions are

1) Wouldn't the part of $2y$10$ give a hint of what algorythm was used and make it easier for an attacker to know what the original string was?

2) Can I just store the string after $2y$10$ and concatenate it anytime I have to work with the password?

3) Why $2y$10$ is used? Could that change in the future? So in my DB I have passwords with $2y$10$ and some with $2y$25$? and everything would run smoothly using password_verify?


Solution

  • From reading the manual of password_hash it looks like in $aa$bb$, bb seems to stand for the "cost" of the algorithm used and aa seems to be (at least currently) always 2y.

    Wouldn't the part of $2y$10$ give a hint of what algorythm was used and make it easier for an attacker to know what the original string was?

    Yes it would give a hint, but

    1. so does the entire rest of a string for many functions (for example, an md5/sha1 hash will always consist of exactly 32/40 hexadecimal characters).
    2. this shouldn't be an issue, because you shouldn't rely on obfuscation anyway, but on a strong algorithm (as arkascha correctly points out in his comment).

    Why $2y$10$ is used?

    Because someone thought it was a good idea.

    Could that change in the future?

    I think so.
    The second part is varying already, and the first part is mentioned in the manual as the "$2y$" identifier, but there is no guarantee that no other identifier will be added.

    So in my DB I have passwords with $2y$10$ and some with $2y$25$? and everything would run smoothly using password_verify?

    Take a look at the examples in the manual - that's already how it is.
    password_hash(..., PASSWORD_DEFAULT) seems to produce a prefix of $2y$10$, but password_hash(..., PASSWORD_BCRYPT, ['cost' => 12]) produces $2y$12$.

    Can I just store the string after $2y$10$ and concatenate it anytime I have to work with the password?

    I would advise against this.
    You could probably make it work, and you could probably even prevent it from breaking on arbitrary changes, but if your only concern is that the encrypted string hints the encryption method used, a better option would be to add an additional layer of symmetric encryption.
    For example:

    $password = password_hash("12345", PASSWORD_DEFAULT);
    $key = pack('H*', md5('lorem').md5('ipsum')); // Must be 16, 24 or 32 bits
    $secret = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $password, MCRYPT_MODE_ECB);
    // Store $secret in the database
    

    This way, if an attacker does not have your source code, they have no way of telling what the encrypted data means, and if they do have access to your source code, they can just take a look at what encryption's being used anyway.

    But again, even if the attacker knows that password_hash and PASSWORD_DEFAULT are being used, they shouldn't be able to crack it.