How can I retrieve a salt from LDAP?

21.1k views Asked by At

The organization that I work for uses PPolicy (an OpenLDAP module) to automatically salt and hash passwords. Unfortunately, I don't have access to the machine running the OpenLDAP server, so i can't look at the config file. From what I've seen though, pretty much everything appears to be setup using the default settings.

I'd like to be able to retrieve the salt for a specific user. If I look at the user's attributes, userPassword is the SSHA password. I don't see anything about a salt for that specific user. I ended up looking at the LDAP schema and I see nothing about salts there either.

If you were to guess where the salt were being stored for each user, where would it be? I understand this is vague and probably not a lot of information, but I can't find anywhere in the OpenLDAP docs that explain where exactly the unique salts are stored. Perhaps someone who has configured an OpenLDAP server before would know where the default location is.

Thank you.

3

There are 3 answers

6
Syon On BEST ANSWER

With SSHA, normally the salt is appended to the SHA1 hash and then the whole thing is Base64 encoded (I've never seen an LDAP that didn't do SSHA this way). You should be able to tell this by looking at the userPassword attribute. If it's 28 character long with a = at the end, it's only the hash.

If the Base64 value is 32 character long or greater, it contains both the hash and the salt. Base64 decode the value and strip off the first 20 bytes, this is the SHA1 hash. The remaining bytes are the salt.

Example:

                     Base64 encoded hash with salt
userPassword: {SSHA}MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0

Base64 decoded value
     SHA1 Hash      Salt
--------------------++++
123456789012345678901234

Edit: After double checking, it seems that variable length salts are sometimes supported. Corrected the encoding description to account for this.

0
Parampal Pooni On

In PHP, this compares a plain text password (usually entered by a user) to a given ssha hash (usually stored in your db):

private function checkSshaPassword($encrypted_password, $password)
{
    //  get hash and salt from encrypted_password
    $base_64_hash_with_salt = substr($encrypted_password, 6);
    $hash_with_salt = base64_decode($base_64_hash_with_salt);
    $hash = substr($hash_with_salt, 0, 20);
    $salt = substr($hash_with_salt, 20);

    //  hash given password
    $hash_given = sha1($password . $salt, true);

    return ($hash == $hash_given);
}
0
Bouke Woudstra On

The post of Syon did help me a lot, thanks for that! I thought a working test would be a nice extra for someone else struggling with this topic ;).

public class SshaPasswordVerifyTest {
    private final static int SIZE_SHA1_HASH = 20;

    @Test
    public void itShouldVerifyPassword() throws Exception{
        String password = "YouNeverGuess!";
        String encodedPasswordWithSSHA = "{SSHA}M6HeeJAbwUCzuLwXbq00Fc3n3XcxFI8KjQkqeg==";
        Assert.assertEquals(encodedPasswordWithSSHA, getSshaDigestFor(password, getSalt(encodedPasswordWithSSHA)));
    }

    // The salt is the remaining part after the SHA1_hash
    private byte[] getSalt(String encodedPasswordWithSSHA){
        byte[] data = Base64.getMimeDecoder().decode(encodedPasswordWithSSHA.substring(6));
        return Arrays.copyOfRange(data, SIZE_SHA1_HASH, data.length);
    }

    private String getSshaDigestFor(String password, byte[] salt) throws Exception{
        // create a SHA1 digest of the password + salt
        MessageDigest crypt = MessageDigest.getInstance("SHA-1");
        crypt.reset();
        crypt.update(password.getBytes(Charset.forName("UTF-8")));
        crypt.update(salt);
        byte[] hash = crypt.digest();

        // concatenate the hash with the salt
        byte[] hashPlusSalt = new byte[hash.length + salt.length];
        System.arraycopy(hash, 0, hashPlusSalt, 0, hash.length);
        System.arraycopy(salt, 0, hashPlusSalt, hash.length, salt.length);

        // prepend the SSHA tag + base64 encode the result
        return "{SSHA}" + Base64.getEncoder().encodeToString(hashPlusSalt);
    }
}