pythonldapopenldapldap3

Compare LDAP Password with another value (ldap3, Python)


I want to implement a comparison-function with ldap3 in Python that can compare a user-given value with a password stored in my ldap-entry.

This is easy to do with non-salted passwords but I'm struggling with salted ones. For example, the stored password in my ldap-entry looks like this:

{SSHA}F5GwOd39wiK+jEKD6UwCs+9XvzvdRYlX

and represents the Salted SHA value of

testpassword

I do not want to check the value with a bind because there might be more than one password saved in the entry. A bind would only check if the user-given value is indeed one of the passwords, and not the password I want to compare it to.

Edit: I want to do this in a LDAP-Editor. A function like this is already implemented in the LDAP-Editor I'm currently using (LDAP Account Manager / LAM). This comparison is not there to handle a login of some sort, it is there so the user himself can check if the password matches his user-given value.

This would be perfect for entries that have more than one password (yes, that is possible) and you have to delete one of them. Of course you could delete all values and add back the ones you still want to use. A comparison would be handy here because the step of deleting every password and adding all the ones back that are still in use would be skipped.

If there is anything else to clarify, I can elaborate more.

Any help is appreciated!


Solution

  • The LDAP faq-o-matic explains how to generate SSHA password hashes). Using that information, we know how to extract the salt from the SSHA password, which then allows us to hash our test password using the same salt to see if we get the same digest:

    import sys
    import base64
    import hashlib
    
    SSHA_TAG = '{SSHA}'
    
    def salt_from_ssha(pw):
        if pw.startswith(SSHA_TAG):
            pw = pw[len(SSHA_TAG):]
        dec = base64.b64decode(pw)
        digest, salt = dec[:20], dec[20:]
        return digest, salt
    
    def compare_password_with_hashed_password(hashed_password, plaintext_password):
        digest, salt = salt_from_ssha(hashed_password)
        plaintext_hash = hashlib.sha1(plaintext_password + salt)
        return plaintext_hash.digest() == digest
    
    
    target = sys.argv[1]
    
    while True:
        testpw = input("Enter a test password: ").encode()
        if compare_password_with_hashed_password(target, testpw):
            print("You found it!")
            break
    

    Running this might look like:

    $ py hasher.py {SSHA}F5GwOd39wiK+jEKD6UwCs+9XvzvdRYlX
    Enter a test password: foo
    Enter a test password: bar
    Enter a test password: testpassword
    You found it!