PHP - Generate SSHA (sha1) Password For LDAP User
Updated 2026-08-07: the snippet I originally posted produced an unsalted {SHA} hash despite the {SSHA} in the title. Replaced it with the password modify extended operation.
This is what I originally posted here, and it was wrong:
$info['userpassword'][0] = "{SHA}" . base64_encode(sha1("pass", TRUE));
That produces {SHA}, a plain unsalted SHA-1, not the {SSHA} the title promises. In the RFC 2307-style schemes OpenLDAP uses, {SHA} is base64(SHA-1(password)), while {SSHA} hashes the password with a random salt and stores that salt alongside the digest, as slappasswd documents. Skipping the salt means every user who picks the same password ends up with the same hash, so one lookup table cracks all of them at once.
The better fix is to stop generating the hash in PHP. The LDAP password modify extended operation (RFC 3062) exists so the client never has to pick a storage scheme. You hand the server the new password and it applies whatever hash it’s configured for:
ldap_exop_passwd($ldap, "uid=someone,ou=people,dc=example,dc=com", "", $newPassword);
PHP has had that wrapper since 7.2. The password travels in the clear inside the request, so run it over LDAPS or StartTLS, and you can confirm the server supports the operation by reading supportedExtension on the root DSE and looking for 1.3.6.1.4.1.4203.1.11.1.
Doing it this way makes the scheme a server setting instead of something frozen into application code. OpenLDAP calls that setting olcPasswordHash (password-hash in the older slapd.conf), and it defaults to {SSHA}. OpenLDAP also ships an argon2 module adding an {ARGON2} scheme, which is a far better choice than anything built on SHA-1. Debian has it in slapd after 2.5.4+dfsg-1, where it needs a moduleload argon2. Changing that directive re-hashes new passwords with no application deploy.
If you’re stuck generating the value yourself, salt it:
$salt = random_bytes(8);
$userPassword = "{SSHA}" . base64_encode(sha1($password . $salt, true) . $salt);
That produces a correct {SSHA}. It’s still SHA-1, which is why I’d rather let the server do it.