4

We have an LDAP server which stores passwords and other user data.
The server is not used for authentication of client machines though but only for authentication of client apps.
So users change their passwords locally on their clients.
As long as we used crypt I could just store the linux hashes as {CRYPT}$hash in LDAP and it worked fine.
Now the passwords are stored as salted sha512 hashes
and the password format in /etc/shadow is like this:

printf( "$6$%s$%s", $salt, $hash )  

$salt seems to be just an ASCII string
I think $hash the base64 encoded result of the sha512 digest from the concatenation of $plainPW and $salt but I am not sure.

LDAP instead stores password hashes like this:

printf( "{SSHA512}%s", $_96byteString )  

where $_96byteString is the base64 encoded result of the concatenation of 512bits of the $saltedPWhash and $salt

I tried to base64_decode the $hash, append the $salt, base64_encode the result and store it as the $_96byteString in the above LDAP format.
Alas LDAP fails to authenticate with this, a simple ldapbind just fails.

Does anybody know how to convert linux sha512 hashes so that the LDAP server accepts it as valid?

I have found that linux crypt uses a different base64 encoding than standard mime.
The standard uses [A-Za-z0-9+/] whereas crypt uses [./0-9A-Za-z].
So I tried to convert with tr but the result still fails :-(

  • Not sure what is you intend, user change password using passwd on any client, then a shell script insert new password in AD ? It might be easiest (altough not that simple) to authenticate user using AD. – Archemar Mar 8 '16 at 13:44
  • Yes, users change passwords using passwd on any client + shell script inserting new password in local LDAP (not AD). Linux users are not allowed in AD in our company. Our LDAP server is not high available and we do not authenticate logins against it but only some applications. As long as we used crypt, the passwords could be inserted into ldap as is and everything worked fine. With ssha512 the format in linux is different to ldap and I don't know how to convert it. – user333869 Mar 9 '16 at 7:44
  • Today I created a hash with perl {SHA512}" . MIME::Base64::encode( Digest::SHA::sha512( $plainPW ), '' ) and this works with LDAP. So it is just the salt that gives me headaches. – user333869 Mar 9 '16 at 11:25
0

The short answer is no, you can't directly recode one password hash to another if you don't know original passwords and don't use brute force or any other attacks. But you can build transparent layer, that convert hashes if password is correct.

The question has been asked many times, like here.

In my software I use passlib library which can do this operation without my interception.

0

I think this is not feasible.

As @Eir Nym says, you fairly obviously can't translate, for example, an MD5-hash of a password into a SHA-256 hash, without knowing the password.

However you would think that you'd be able to translate a SHA-256 hash (according to crypt(3)) into a SHA-256 hash (according to OpenLDAP): surely it's just a matter of identifying the salt and hash in one format, and reordering them into the format the other expects. No? What, it's not?!

In OpenLDAP, the format of the userPassword attribute, though not quite documented, is relatively straightforward: it's the fixed-length hash of the password followed by the salt (see eg contrib/slapd-modules/passwd/sha2 in the OpenLDAP sources). This is also evident in notes such as this OpenLDAP FAQ-o-matic article which shows how to generate a {SSHA} hash from password + salt.

For systems which use crypt(3), however, you'll see ‘password hashes’ of the form

$id$salt$hash

where $5$ indicates SHA-256, $6$ indicates SHA-512, and so on. The hash element of that is the base64 encoded form of some function of key, salt, and (in some variants) number of encryption rounds, but the actual function is... not documented.

  • The Wikipedia page on crypt(3) mentions that ‘Over time various algorithms have been introduced.’
  • It points to the ‘Password Hashing Competition’ specification (PHC), which narrows down the gross format of the ‘hash’ string, but not as much as you'd hope. It doesn't even conclusively identify what base64 variant the string uses (it appears to, but acknowledges that characters [.-] can appear in a base64 string without saying what they are).
  • The passlib library acknowledges some of the mess (‘All of the above is guesswork based on examination of existing hashes and OS implementations’) and recommends the PHC format.
  • A linuxquestions.org question indicates that the relevant base64 encoding is peculiar.

So we can look at the glibc sources for crypt. There, we discover (in crypt_util.c) that the base64 alphabet is indeed odd, using "./0-9A-Za-b" rather than the more usual (and PHC-specified) "A-Za-z0-9+/" (with occasional variants in the last two characters). Not helpful, but we could cope if this were the only difference.

However, the sha256-crypt.c function in that library (for example) takes the key and salt and does something very odd and long-winded with them to produce the hash value. I wouldn't presume to venture an opinion on whether what it's doing is sensible, but it's certainly not straightforward.

What that means is that although the crypt(3) $5$ and OpenLDAP ‘SHA-256’ hashes are on the face of it using the same cryptographic primitive, they are actually using it in sufficiently different ways that they amount to different hash functions so that, as with the point at the top, you can't translate one to the other without knowing the password. A similar point can be made about $6$/SHA-512 passwords.

This is very annoying.


Parenthetical note: As it happens, it is possible to convert the $1$/SMD5 ‘hashes’ between crypt(3) format and OpenLDAP:

$1$salt$hash

corresponds to

'{SMD5}' + hash + salt

where + is simple string concatenation. But we probably shouldn't be using MD5 hashes any more, so this doesn't much help.

Note also that you can port your crypt(3) hashes to OpenLDAP unchanged, using

{CRYPT}$1$salt$hash

if your libc is compatible (which it typically will be, if OpenLDAP is running on Linux), but OpenLDAP won't generate new passwords this way, so this is a one-way street.

0

You can simply use {CRYPT} prefix to add any password hash from /etc/shadow as userPassword value provided the crypt(3) functions on system holding local account data and on your LDAP server both implement the same hashing schemes. Check the crypt(3) man pages of the different systems.

You can also let OpenLDAP's slapd generate crypt(3) hashes with a specific hashing schema and salt format when setting the password via LDAP Password Modify Extended Operation (see also slapd.conf):

password-hash {CRYPT}
password-crypt-salt-format "$6$rounds=20000$%.16s"

Actually the example above is better than {SSHA512} because 20000 hash rounds are used instead of only one which raises effort needed to conduct a brute-force attack.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.