# [RFC] Add PASSWORD_BCRYPT_SHA256 to password_hash

- Thread: https://externals.io/message/132784
- Original archive: https://news-web.php.net/php.internals/132784
- Started by Sjoerd Langkemper on 2026-10-05T09:20:29+00:00
- Messages: 12
- RFC: Add PASSWORD_BCRYPT_SHA256 to password_hash (Under discussion) — https://externals.io/rfc/bcrypt_sha256.md
- RFC: Throw error for passwords longer than 72 bytes in password_hash() with bcrypt (Inactive) — https://externals.io/rfc/bcrypt_max_password_length.md
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · RFCs at https://externals.io/rfc.md · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #132784 — Sjoerd Langkemper — 2026-10-05T09:20:29+00:00

URL: https://externals.io/message/132784#132784

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

---

## #132788 — tim@bastelstu.be — 2026-10-05T13:04:58+00:00

URL: https://externals.io/message/132784#132788 · In reply to: #132784

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/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.

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:

1. The status in the RFC itself still says “Draft”.

2. 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.

3. 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

---

## #132790 — Anton Smirnov — 2026-10-05T13:25:53+00:00

URL: https://externals.io/message/132784#132790 · In reply to: #132784

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

---

## #132793 — tim@bastelstu.be — 2026-10-05T13:38:36+00:00

URL: https://externals.io/message/132784#132793 · In reply to: #132790

Hi


> > […]
> 
> 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

---

## #132803 — Anton Smirnov — 2026-10-06T08:13:00+00:00

URL: https://externals.io/message/132784#132803 · In reply to: #132793

> `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.
Thank you for the explanation. This inconsistency made me believe there 
may be several rounds of sha256 too

---

## #132838 — Mirco Babin — 2026-10-08T18:04:33+00:00

URL: https://externals.io/message/132784#132838 · In reply to: #132784

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

---

## #132839 — Sjoerd Langkemper — 2026-10-08T18:34:31+00:00

URL: https://externals.io/message/132784#132839 · In reply to: #132838

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

---

## #132840 — Andrey Andreev — 2026-10-08T21:03:13+00:00

URL: https://externals.io/message/132784#132840 · In reply to: #132839

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.

---

## #132850 — Rowan Tommins [IMSoP] — 2026-10-09T11:02:03+00:00

URL: https://externals.io/message/132784#132850 · In reply to: #132838

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]

---

## #132855 — Mirco Babin — 2026-10-09T14:02:48+00:00

URL: https://externals.io/message/132784#132855 · In reply to: #132839

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

---

## #132856 — Mirco Babin — 2026-10-09T14:03:11+00:00

URL: https://externals.io/message/132784#132856 · In reply to: #132850

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

---

## #132857 — Rowan Tommins [IMSoP] — 2026-10-09T16:24:47+00:00

URL: https://externals.io/message/132784#132857 · In reply to: #132856

> 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]
