1

I am trying a simple LDAP example using LDIF from here [LDIF example][1]. I was able to setup everything and run it correctly using the default user/pass.

However, I am trying to generate new users and I used the Java code below to generate passwords for "joe" but it doesn't seem to work :

 import java.nio.charset.StandardCharsets;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;

   private static String get_SHA_1_SecurePassword(String passwordToHash)
    {
        String generatedPassword = null;

        try {
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            byte[] bytes = md.digest(passwordToHash.getBytes());
            StringBuilder sb = new StringBuilder();
            for(int i=0; i< bytes.length ;i++)
            {
                sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
            }
            generatedPassword = sb.toString();

        }
        catch (NoSuchAlgorithmException e)
        {
            e.printStackTrace();
        }
        return generatedPassword;
    }

Code for checking password from the sample link above:

public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .ldapAuthentication()
                .userDnPatterns("uid={0},ou=people")
                .groupSearchBase("ou=groups")
                .contextSource()
                    .url("ldap://localhost:8389/dc=springframework,dc=org")
                    .and()
                .passwordCompare()
                    .passwordEncoder(new LdapShaPasswordEncoder())
                    .passwordAttribute("userPassword");
    }

Here is the LDIF file snippet with the passwords:

  //working copy for ben from example
    dn: uid=ben,ou=people,dc=springframework,dc=org
    dn: uid=ben,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Ben Alex
sn: Alex
uid: ben
userPassword: {SHA}nFCebWjxfaLbHHG1Qk5UU4trbvQ=

    //new user "joe"
    dn: uid=joe,ou=people,dc=springframework,dc=org
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
cn: Joe S
sn: joe
uid: joe
userPassword: {SHA}9c509e6d68f17da2db1c71b5424e54538b6b6ef4

The password I used for joe is "joe" and I cant seem to get it accepted. Is the encryption different? I am using Windows by the way.

2 Answers2

1

Your function looks fine and should output a correct salted SHA-1 hash.

However, the storage scheme prefix in your LDIF file should be {SSHA} (for salted SHA1) instead of {SHA} - or you did not intend to use salt (?).

Also, the actual output of a hash algorithm is binary data which can be represented in hexadecimal or base64 strings. LDAP storage schemes use base64 encoding.

What can you do ?

  • In your LDIF we can recognize hex strings, so the first thing is to make that hash encoded in base64 instead of hexadecimal, depending on imported base64 package :

    // Using org.apache.commons.codec.binary.Base64 
    generatedPassword = Base64.encodeBase64String(bytes);
    
    // Using java.util.Base64 
    generatedPassword = Base64.getEncoder().encodeToString(bytes);
    
  • If you don't want to salt, you need to comment out the following line (with an empty salt string it is still "salt" and won't yield the same output as no salting) :

    md.update(salt.getBytes(StandardCharsets.UTF_8));
    
  • Set the proper storage scheme prefix according to the point above. For example, using SHA-1 with salt, the password attribute value in ldif should look like this :

    userPassword: {SSHA}<base64_encoded_hash>
    

A few other things to consider :

  • OpenLDAP supports the following encryption scheme : SHA, SSHA, MD5, SMD5 and CRYPT.

  • SHA and SSHA both use SHA-1 algorithm.

  • To bring support for SHA-2 and its variants, use slapd's pw-sha2 overlay (support for SHA-224, SHA-256, SHA-384, SSHA-224, SSHA-256, SSHA-384). It can be either compiled statically with slapd, or loaded dynamically since it has module support enabled.

See also : 14.4. Password Storage from https://www.openldap.org/doc/admin24/security.html

EricLavault
  • 12,130
  • 3
  • 23
  • 45
  • I actually didnt know the syntax for salted in LDIF so i took it out and didnt use salt at all on another attempt. Also, wouldnt you need to provide the salt value in addition to telling it it's salted? So assuming i dont need salt (i am just using this implementation until we get certificates implemented) and just simple encryption on passwords for LDIF. What can i do? By the way, i did try to use java code to SHA-1 "ben" and didn't get the same result as LDIF which i think should match? –  Jun 22 '19 at 20:54
  • Either you consider using a salt (which you did in your function, whatever the salt string is - it *can* be empty) and use the corresponding {SSHA}, either you don't and use {SHA}. In the meantime I realized you use SHA512, sorry if I didn't catch this earlier but it could be an issue if you don't set the specific config in the first place. I will edit this post soon to clarify. – EricLavault Jun 23 '19 at 07:47
  • nope I was correct.. :/ I was induced by @bipil-raut's answer for the sha512 use case. I'm gonna re-edit to prevent confusion. :) – EricLavault Jun 23 '19 at 17:53
  • Ok, I just test it and didn't work. I updated the code to above and am using basic level of sha-1. I tried encoding but it seems to have made the string longer than shorter. I did notice that the original password for user "ben" is "benspassword" and its encoded string is "{SHA}nFCebWjxfaLbHHG1Qk5UU4trbvQ=" . My user "Joe" who i also used 'benspassword" has a generated string of "{SHA}9c509e6d68f17da2db1c71b5424e54538b6b6ef4" using the method above. They should be the same right since no salt involved? –  Jun 24 '19 at 12:53
  • Yes they should be the same but they are not : "9c509e6d68f17da2db1c71b5424e54538b6b6ef4" is not base64 but still hexa string. I just added another example for encoding the string in base64 with java.util package. Now it's up to you to import the correct one because I can't guess. Please don't say "I just test it and didn't work" when you just compare an hex string with a base64 string, don't say this when you just did a copy/paste without importing the base64 package in the first place. – EricLavault Jun 24 '19 at 13:24
  • I tried both using the login (benspassword worked for ben but didnt for other 2): 1. For the java example i had to conver result to string - generatedPassword = Base64.getEncoder().encode(generatedPassword.getBytes()).toString(); Encoded is "[B@15db9742" 2. for the apache commons I installed "commons-codec-1.12-bin" BUT it does not have the same syntax for the method as you posted. I had to use: generatedPassword = Base64.encodeBase64String(generatedPassword.getBytes()); Encoded is OWM1MDllNmQ2OGYxN2RhMmRiMWM3MWI1NDI0ZTU0NTM4YjZiNmVmNA== So is somehow the encoding method isnt same? –  Jun 24 '19 at 14:05
  • Ok sorry I didn't get to test it earlier and I missed the toString() bit. I also assumed that `generatedPassword.getBytes()` would return the same bytes array as `md.digest()` does which is completely wrong. I fixed the example : "benspassword" matches `nFCebWjxfaLbHHG1Qk5UU4trbvQ=` and "joe" yields `FqmlTd9CWZUuPBGMdjE46DaT1/0=`. `9c509e6d68f17da2db1c71b5424e54538b6b6ef4` is the hexadecimal form of "benspassword" hash, so again it's your ldif that is wrong here, you'll need to regenerate a new password or reset it to `{SHA}FqmlTd9CWZUuPBGMdjE46DaT1/0=` (the correct encoded hash for joe). – EricLavault Jun 24 '19 at 16:23
  • cool it worked! It is interesting how the "tostring" method didnt work as intended but have to call the encodeTostring. Thanks for all the help! Will try to investigate higher securities...but at least i have a baseline to play around with. –  Jun 24 '19 at 17:03
0

you can use this for SHA-512 You use instance of MessageDigest.getInstance("SHA-1") -->MessageDigest.getInstance("SHA-512");

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public String get_SHA_512_SecurePassword(String passwordToHash, String   salt){
String generatedPassword = null;
    try {
         MessageDigest md = MessageDigest.getInstance("SHA-512");
         md.update(salt.getBytes(StandardCharsets.UTF_8));
         byte[] bytes = md.digest(passwordToHash.getBytes(StandardCharsets.UTF_8));
         StringBuilder sb = new StringBuilder();
         for(int i=0; i< bytes.length ;i++){
            sb.append(Integer.toString((bytes[i] & 0xff) + 0x100, 16).substring(1));
         }
         generatedPassword = sb.toString();
        } 
       catch (NoSuchAlgorithmException e){
        e.printStackTrace();
       }
    return generatedPassword;
}

Please check this question how-to-hash-a-password-with-sha-512-in-java

Bipil Raut
  • 244
  • 1
  • 10
  • no that's not the issue. I did see that. The issue is storing it in the LDIF file and have it being accepted. I can't get it accepted for some reason. –  Jun 21 '19 at 18:48