Skip to content

Make password salt generation algo-agnostic and isolate bcrypt-specific logic - #24281

Open
narfbg wants to merge 5 commits into
php:PHP-8.4from
narfbg:password_salt
Open

narfbg wants to merge 5 commits into
php:PHP-8.4from
narfbg:password_salt

Conversation

@narfbg

@narfbg narfbg commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor
  • Fixes a bug where the libargon2 implementation uses less entropy than intended (still safe, but below baseline).
  • Aligned bcrypt salt encoding more closely to bcrypt's variant. Previously, it relied on php_crypt() doing the error correction. This is still not entirely following bcrypt as designed, but that's for another time.
  • Stricter bcrypt sanity checks.

…ic logic

- Fixes a bug where the libargon2 implementation uses less entropy than intended (still safe, but below baseline)
- Aligned bcrypt salt encoding more closely to bcrypt's variant (previously, it relied on php_crypt() doing the error correction)
- Stricter bcrypt sanity checks, and slightly optimized code

@Sjord Sjord left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting bug. So the argon2 salt was base64-encoded twice?

Comment thread ext/standard/password.c Outdated
Comment thread ext/standard/password.c Outdated
Comment thread ext/standard/password.c Outdated
Comment thread ext/standard/password.c Outdated
@narfbg

narfbg commented Oct 13, 2026

Copy link
Copy Markdown
Contributor Author

Interesting bug. So the argon2 salt was base64-encoded twice?

Yes, and any new algorithm would inherit the flaw if unnoticed. That's how it came to affect argon2 - if you don't look closely at php_password_make_salt(), nothing about it suggests that it would apply extra encoding, especially since there's a separate encoding function.

Comment thread ext/standard/password.c
return 0;
}

if (ZSTR_LEN(hash) < 13) {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI would've changed this to fixed length too, but evidently all non-recognized algos default here during password_verify() calls and it's breaking a test.

I want to fix that, so the default is its own thing and bcrypt stays isolated. Will do that separately.

Comment thread ext/standard/password.c Outdated
@Sjord

Sjord commented Oct 14, 2026

Copy link
Copy Markdown
Contributor

I think the code can be made a little bit nicer, but functionally this looks good to me.

@Sjord

Sjord commented Oct 14, 2026

Copy link
Copy Markdown
Contributor

Looks good to me!

Originally designed with only bcrypt in mind and contributed to the argon2 salt bug.
Today it only exists to emit the ignored salt warning and is only complicating things.

Moved the warning trigger in PHP_FUNCTION(password_hash) to avoid a breaking change,
since argon2 inherited it even though it never accepted a user-provided salt. This is
a bug on its own, but it can be argued both ways so being safe with it.
I reckon the warning should eventually be dropped entirely in a major release.
@narfbg

narfbg commented Oct 14, 2026 •

Copy link
Copy Markdown
Contributor Author

I think I've rooted-out everything that would've contributed to the argon2 bug and/or remnants from when user-provided salt was supported (i.e. there's no reason for it to be a zend_string otherwise).

Will limit myself to reviewer-requested changes only from here on, and ready to squash.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants