Hello,
I propose to add a new hashing algorithm to use in password_hash and password_verify.
RFC: https://wiki.php.net/rfc/bcrypt_sha256
PR: https://github.com/php/php-src/pull/24073
The existing bcrypt has problems with null bytes and only hashes the first 72 bytes. The proposed PASSWORD_BCRYPT_SHA256 algorithm solves those problems by first hashing the password with HMAC SHA256 before passing it through bcrypt.
Tim suggested this in the discussion on my earlier RFC to throw errors on passwords longer than 72 bytes (https://wiki.php.net/rfc/bcrypt_max_password_length). That suggestion receives much criticism because of its backwards incompatibility, and I don't think it is worth pursuing further at the moment. I think this new hash is a gentler way to solve the underlying problem.
Regards,
Sjoerd Langkemper
Hi
I propose to add a new hashing algorithm to use in password_hash and
password_verify.RFC: https://wiki.php.net/rfc/bcrypt_sha256
PR: https://github.com/php/php-src/pull/24073The existing bcrypt has problems with null bytes and only hashes the
first 72 bytes. The proposed PASSWORD_BCRYPT_SHA256 algorithm solves
those problems by first hashing the password with HMAC SHA256 before
passing it through bcrypt.Tim suggested this in the discussion on my earlier RFC to throw errors
on passwords longer than 72 bytes
(https://wiki.php.net/rfc/bcrypt_max_password_length). That suggestion
receives much criticism because of its backwards incompatibility, and I
don't think it is worth pursuing further at the moment. I think this
new hash is a gentler way to solve the underlying problem.
Thank you for the RFC. I believe this is a much better solution than
modifying PASSWORD_BCRYPT in a way that breaks compatibility. I have
the following comments to the RFC:
-
The status in the RFC itself still says “Draft”.
-
The main NUL issue is resolved for PHP (by throwing ValueError for
new passwords). The proposal phrasing implies that this would not yet be
the case. In particular the referenced #21675 makes compatibility with
external BCrypt producers worse. The different between the NUL
truncation and the 72B truncation is that the latter is reasonably
reasonable by users, whereas NUL is not. -
Unrelated to the primary topic and a separate concern: Should we add
support for the$2b$identifier? My understanding is that it's
identical to$2y$.
The proposal itself I support, with Python’s passlib there is precedent
and the proposed behavior is the obvious one.
Best regards
Tim Düsterhus
Hi Sjoerd!
Hello,
I propose to add a new hashing algorithm to use in password_hash and
password_verify.RFC: https://wiki.php.net/rfc/bcrypt_sha256 <https://wiki.php.net/rfc/
bcrypt_sha256>
PR: https://github.com/php/php-src/pull/24073 <https://github.com/php/
php-src/pull/24073>
It appears to me like it needs a rounds config and a
PASSWORD_BCRYPT_SHA256_DEFAULT_ROUNDS constant, so we can have
// be extra secure
password_hash($password, PASSWORD_BCRYPT_SHA256, [
"cost" => PASSWORD_BCRYPT_SHA256_DEFAULT_COST + 2,
"rounds" => PASSWORD_BCRYPT_SHA256_DEFAULT_ROUNDS + 2,
];
Otherwise I love the proposal
p.s. Resent. I forgot I should reply to the list, sorry
--
Anton
Hi
Hello,
I propose to add a new hashing algorithm to use in password_hash and
password_verify.RFC: https://wiki.php.net/rfc/bcrypt_sha256 <https://wiki.php.net/rfc/
bcrypt_sha256>
PR: https://github.com/php/php-src/pull/24073 <https://github.com/php/
php-src/pull/24073>It appears to me like it needs a rounds config and a
PASSWORD_BCRYPT_SHA256_DEFAULT_ROUNDS constant, so we can have// be extra secure
password_hash($password, PASSWORD_BCRYPT_SHA256, [
"cost" => PASSWORD_BCRYPT_SHA256_DEFAULT_COST + 2,
"rounds" => PASSWORD_BCRYPT_SHA256_DEFAULT_ROUNDS + 2,
];
rounds and cost are the same thing. The format calls it rounds,
but the PHP API calls it cost. Keeping cost on the PHP API makes
sense to me for consistency with PASSWORD_BCRYPT, even if it is
inconsistent with the hash string.
Best regards
Tim Düsterhus
roundsandcostare the same thing. The format calls itrounds,
but the PHP API calls itcost. Keepingcoston the PHP API makes
sense to me for consistency withPASSWORD_BCRYPT, even if it is
inconsistent with the hash string.
Thank you for the explanation. This inconsistency made me believe there
may be several rounds of sha256 too
Hello Sjoerd Langkemper,
I propose to add a new hashing algorithm to use in password_hash and
password_verify.RFC: https://wiki.php.net/rfc/bcrypt_sha256
PR: https://github.com/php/php-src/pull/24073
I have 3 comments.
=================
Begin of comments
The RFC states:
Rather than inventing a new, PHP-specific pre-hashing scheme, this
RFC proposes adopting an existing, well-reviewed and widely deployed
one: Passlib's bcrypt_sha256 hash, in its current “version 2” form
(the default since Passlib 1.7.3).
=========
Comment 1
Who invented the bcrypt_sha256 hash specification? In what
official specification, IETF-RFC, NIST-specification is it described?
Passlib is not a trusted source for security related issues. Passlib
is a library that only implements things, that might or might not be
backed by an official security specification.
=========
Comment 2
Why is something proposed that goes against OWASP recommendations?
OWASP states, see
https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pre-hashing-passwords-with-bcrypt
To summarize if bcrypt has to be used and the password should to be
pre-hashed you should do
bcrypt(base64(hmac-sha384(data:$password, key:$pepper)), $salt, $cost)
and store the pepper not in the database.
=========
Comment 3
Is interoperability with other systems considered?
For example assume a C# application and a PHP application sharing
the same database for user credentials. Is this going to work out
of the C# box with this invented algorithm? Or has the C# side to do
all kinds of security sensitive programming to implement this
algorithm?
The same question for Delphi, Javascript and other languages.
===============
End of comments
Kind regards,
Mirco Babin
Hi Mirco Babin,
Passlib is not a trusted source for security related issues.
Why is something proposed that goes against OWASP recommendations?
Is interoperability with other systems considered?
Thank you for your feedback. Do you have a suggestion for a password hash that is specified by a recognized organization and has better interoperability with other systems?
I considered PBKDF2; it is widely supported and standardized by NIST, but it is generally seen as less secure than bcrypt. Would you prefer this, even if it is less resistant to offline cracking attacks?
Regards,
Sjoerd Langkemper
Hi Sjoerd,
On Thu, Oct 8, 2026 at 9:37 PM Sjoerd Langkemper sjoerd-php@linuxonly.nl
wrote:
Hi Mirco Babin,
Passlib is not a trusted source for security related issues.
Why is something proposed that goes against OWASP recommendations?
Is interoperability with other systems considered?Thank you for your feedback. Do you have a suggestion for a password hash
that is specified by a recognized organization and has better
interoperability with other systems?I considered PBKDF2; it is widely supported and standardized by NIST, but
it is generally seen as less secure than bcrypt. Would you prefer this,
even if it is less resistant to offline cracking attacks?
You seem too eager to deliver on this, having vibe-coded the bcrypt-sha256
PR just a day after the idea was thrown in, and now asking for other
suggestions after first pushback.
These aren't good foundations for a major security feature, which will
reflect poorly on it even if you stumble upon the best possible solution.
I've been working on an alternative for weeks already and hope to be able
to put it up soon. Have a small blocker outside of my hands that may take
another week or two.
Please allow me some time before rushing in with another RFC.
Cheers,
Andrey.
Hello Sjoerd Langkemper,
(Mirco Babin)
Passlib is not a trusted source for security related issues.
Why is something proposed that goes against OWASP recommendations?
Is interoperability with other systems considered?
(Sjoerd Langkemper)
Thank you for your feedback. Do you have a suggestion for a password
hash that is specified by a recognized organization and has better
interoperability with other systems?
(Mirco Babin) This question is wrongly addressed to me. I have no
intention of writing a RFC.
(Sjoerd Langkemper)
I considered PBKDF2; it is widely supported and standardized by NIST,
but it is generally seen as less secure than bcrypt. Would you prefer
this, even if it is less resistant to offline cracking attacks?
(Mirco Babin) My preference is of no importance. Also I don't have a
preference. Following security standards and interoperability is
what PHP should offer to its users, the programmers using PHP.
Kind regards,
Mirco Babin
Hi Mirco,
OWASP states, see
https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pre-hashing-passwords-with-bcrypt
I looked up the attack discussed there, "password shucking" or "hash shucking", and as I understand it, it requires the same inner hash to be used somewhere else, that the attacker can match to that user.
In the proposed algorithm, that means that somewhere else has passwords stored as HMAC-SHA256(salt, password) and has the same password, and the same salt, for the same user. Unless I'm missing something, that's staggeringly unlikely.
To put it another way, the salt in the proposal's HMAC is essentially doing the same thing as the pepper in the OWASP suggestion - making it sufficiently unlikely that an attacker can find the exact inner hash they need somewhere else.
I also see, in the section above that, that OWASP endorses Sjoerd's original proposal:
... so you should enforce a maximum password length of 72 bytes
Even an expert opinion is just an opinion, of course, but it does mean we're going in circles a bit.
Regards,
Rowan Tommins
[IMSoP]
Hello Rowan Tommins [IMSoP],
(Mirco Babin)
OWASP states, see
https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html#pre-hashing-passwords-with-bcrypt
(Rowan Tommins [IMSoP])
I looked up the attack discussed there, "password shucking" or
"hash shucking", and as I understand it, it requires
the same inner hash to be used somewhere else, that the attacker
can match to that user.
(Mirco Babin) I did not write the article in question. I think these
questions would be better addressed to OWASP.
Kind regards,
Mirco Babin
I did not write the article in question. I think these
questions would be better addressed to OWASP.
I didn't ask you any questions, nor do I have any questions I want to ask the OWASP authors.
You stated that the algorithm Sjoerd proposed including "goes against OWASP recommendations". I looked at the page you linked to, did some follow-up research of terms it mentioned, and I disagree with your conclusion.
My conclusion is that the page you linked discusses a possible vulnerability in similar algorithms, and suggests an algorithm that doesn't have that vulnerability. The algorithm proposed in this thread is not identical to that OWASP suggestion, but it has a different feature which addresses the same vulnerability.
As such, I think the algorithm is worth considering further.
Regards,
Rowan Tommins
[IMSoP]