One standard password-hash format everywhere: mux_sha_crypt implements
the sha-crypt construction (glibc/musl/openssl-compatible, including
rounds= presence, clamping-with-clamped-value-in-output, and 16-char
salt truncation) over OS crypto primitives -- OpenSSL EVP on Unix,
Windows CNG with a reusable hash handle. mux_crypt routes $5$/$6$
through it on BOTH platforms, so a Unix-written password database
verifies on Windows and vice versa, and Unix stops depending on which
libc crypt(3) understands those formats (macOS's does not). The libc
fall-through remains only for the legacy tail (DES, _-extended, $1$).
New hashes are $6$ with an explicit rounds= from the new conf directive
password_hash_rounds (default 220000, tracking current OWASP guidance
for the SHA-512 PRF; measured ~190 ms/hash on 2022-era server
hardware). The check_pass auto-upgrade trigger becomes parameter-aware:
a $5$/$6$ hash whose stored rounds differ from policy re-encodes on the
next successful login (work-factor migration, automatic), P6H/legacy
conversion-on-login is preserved, and the implicit default
(password_methods unset) no longer rewrites SHA1-or-stronger hashes --
it used to re-hash every login and would silently downgrade $6$ to
$SHA1$ after a config reset.
tests/shacrypt (make test-shacrypt, also in test-asan) pins 14 KATs
with every golden value from `openssl passwd` as an external oracle,
including both published spec vectors. Verified on Windows: 14/14 KATs,
digest KATs still 17/17, smoke ALL 1601 PASSED / 0 failed, and a live
netmux end-to-end: @pcreate under sha512 policy stores $6$, a $SHA1$
player auto-upgrades on login, a rounds=5000 hash refreshes to 220000 on
login, and every Windows/CNG-generated hash re-derives byte-identically
with `openssl passwd -6`.
Stacked on #1963's CNG backend (same OS-primitives posture and
bcrypt.lib link).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>