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
On 2026-10-05 11:20, Sjoerd Langkemper wrote:
I propose to add a new hashing algorithm to use in password_hash and password_verify.
RFC: PHP: rfc:bcrypt_sha256
PR: ext/standard: bcrypt-sha256 password hash by Sjord · Pull Request #24073 · php/php-src · GitHub
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 (PHP: 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
Hi Sjoerd!
On 05/10/2026 12:20, Sjoerd Langkemper wrote:
Hello,
I propose to add a new hashing algorithm to use in password_hash and password_verify.
RFC: PHP: rfc:bcrypt_sha256 <PHP: rfc bcrypt_sha256>
PR: ext/standard: bcrypt-sha256 password hash by Sjord · Pull Request #24073 · php/php-src · GitHub <php.net · GitHub 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
On 2026-10-05 15:25, Anton Smirnov wrote:
Hello,
I propose to add a new hashing algorithm to use in password_hash and password_verify.
RFC: PHP: rfc:bcrypt_sha256 <PHP: rfc bcrypt_sha256>
PR: ext/standard: bcrypt-sha256 password hash by Sjord · Pull Request #24073 · php/php-src · GitHub <php.net · GitHub 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
On 05/10/2026 16:38, Tim Düsterhus wrote:
`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