Using SHA-256 to preprocess password before bcrypt?

In general, this will be fine. It's even a fairly well recommended method to allow arbitrary length passwords in bcrypt.

Mathematically, you are now using bcrypt on a 64 character string, where there are 2^256 possible values (SHA-256 gives 256 bit output, which is commonly represented as a 64 character hexadecimal string). Even if someone pre-calculated common passwords in SHA-256, they'd need to run those through bcrypt to find what the actual input for a given hash was.

The main potential drawback is implementation flaws: if you ever store the SHA-256 values, they're relatively fast to break, so an attacker wouldn't need to expend the effort to break the bcrypt values.

It would still be recommended to keep a high enough iteration count for the bcrypt step - this shouldn't have any particularly detrimental effect on your processing time, but makes brute force attacks much harder.

See Pre-hash password before applying bcrypt to avoid restricting password length for the general case.


Your suggested implementation is safe. However take care to document your special usage of the function.

Please note that password_hash will truncate the password at the first NULL-byte so you must NOT use the option $raw_output=true of the hash function.


Don't do it, you are limiting your key strength to much less than what bcrypt alone can accept.

Use this approach instead (pseudo-code not valid PHP):

if length($password) > 72 bytes
then
    $hash = sha256($password)
    $password = concat(substring($password, 320 bits), base255encode($hash))
end if
bcrypt($password)

In this way, passwords between 256 and 576 bits retain their full entropy, and passwords of above 576 bits use not only the 256 bits from the hash, but as much of the original entropy as can fit alongside the hash.

It's debatable whether the hash should be done across the whole password, or just the portion beyond 320 bits that the hash replaces. I seriously doubt it makes any difference when you've chosen a cryptographic hash with good properties.

The base255encode step avoids having a NUL byte terminate the key early, as @a-hersean warned about.