Java autentication of Drupal passwords
===

I try to mimic the way Drupal 7 is checking for a correct password in Java.
Found some code as a guideline here: https://github.com/CraftFire/AuthDB-Legacy/blob/master/src/main/java/com/authdb/scripts/cms/Drupal.java and extracted the code i needed.

The thing is however that when i give the password and the hashed version (in order to extract the salt and amount of iterations needed), i get different results.


The passwords are generated using the Drupal password-hash script
resulting in:

    Expected   value = $S$DxVn7wubSRzoK9X2pkGx4njeDRkLEgdqPphc2ZXkkb8Viy8JEGf3
    Calculated value = $S$DxVn7wubSpQ1CpUnBZZHNqIXMp2XMVZHMYBqAs24NsUHMY7HBkYn

    Expected   value = $S$DOASeKfBzZoqgSRl/mBnK06GlLESyMHZ81jyUueEBiCrkkxxArpR
    Calculated value = $S$DOASeKfBzs.XMVZ1NkYXNmIqMpEHAoEaMYJ1NmUHCZJaBZFnAZFX

Anyone able to help me / tell me what i'm doing wrong here?
Thanks.

Code:

    import java.io.UnsupportedEncodingException;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
     
    class test {

      public static void main(String args[]) {
       // Passwords and hashes generated by Drupal.
       checkPassword("test"  , "$S$DxVn7wubSRzoK9X2pkGx4njeDRkLEgdqPphc2ZXkkb8Viy8JEGf3"); 
       checkPassword("barbaz", "$S$DOASeKfBzZoqgSRl/mBnK06GlLESyMHZ81jyUueEBiCrkkxxArpR");
      }
    
      private static String itoa64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
      private static final int DRUPAL_HASH_LENGTH = 55;
      private static int password_get_count_log2(String setting) { return itoa64.indexOf(setting.charAt(3)); }
        
      /**
       * Note: taken from the default Drupal 7 password algorithm
       * @param candidate
       *        the clear text password
       * @param saltedEncryptedPassword
       *        the salted encrypted password string to check => NEEDS TO BE THE DEFAULT DRUPAL 7 PASSWORD HASH.
       * @return true if the candidate matches, false otherwise.
       */
      public static boolean checkPassword(String candidate, String saltedEncryptedPassword) {
        if (candidate == null) {
          return false;
        }
        if (saltedEncryptedPassword == null) {
          return false; 
        }
    
        String hash = password_crypt(candidate, saltedEncryptedPassword);
        System.out.println("Tested value = " + saltedEncryptedPassword);
        System.out.println("Calced value = " + hash);
    
        return hash == saltedEncryptedPassword;
      }
    
      public static String SHA512(String text) {
        byte[] sha1hash = new byte[40];
        try {
          MessageDigest md = MessageDigest.getInstance("SHA-512");
          md.update(text.getBytes("UTF-8"), 0, text.length());
          sha1hash = md.digest();
        } catch (NoSuchAlgorithmException e) {
          e.printStackTrace();
        } catch (UnsupportedEncodingException e) {
          e.printStackTrace();
        }
        return convertToHex(sha1hash);
      }
        
      private static String convertToHex(byte[] data) {
        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < data.length; i++) {
          int halfbyte = (data[i] >>> 4) & 0x0F;
          int two_halfs = 0;
            do {
              if ((0 <= halfbyte) && (halfbyte <= 9))
                buf.append((char) ('0' + halfbyte));
              else
                buf.append((char) ('a' + (halfbyte - 10)));
                halfbyte = data[i] & 0x0F;
          }
          while(two_halfs++ < 1);
        }
        return buf.toString();
      }
  
      private static String password_crypt(String password, String setting) {
        // The first 12 characters of an existing hash are its setting string.
        setting = setting.substring(0, 12);
        int count_log2 = password_get_count_log2(setting);

        String salt = setting.substring(4, 12);
        // Hashes must have an 8 character salt.
        if (salt.length() != 8) {
          return null; 
        }
    
        // Convert the base 2 logarithm into an integer.
        int count = 1 << count_log2;
            
        String hash;
        try {
          hash = SHA512(salt + password);
          do {
            hash = SHA512(hash + password);
          } while (--count >= 0);
        } catch(Exception e) {
          return null; 
        }
        
        int len = hash.length();
        String output = setting + password_base64_encode(hash, len);         
        return (output.length() > 0) ? output.substring(0, DRUPAL_HASH_LENGTH) : null;
      }

      private static String password_base64_encode(String input, int count) {
        StringBuffer output = new StringBuffer();
        int i = 0, value;
        do {
          value = input.charAt(i++);
          output.append(itoa64.charAt(value & 0x3f));
          if (i < count) {
            value |= input.charAt(i) << 8;
          }
          output.append(itoa64.charAt((value >> 6) & 0x3f));
          if (i++ >= count) {
            break;
          }
          if (i < count) {
            value |= input.charAt(i) << 16;
          }
          output.append(itoa64.charAt((value >> 12) & 0x3f));
          if (i++ >= count) {
            break;
          }
          output.append(itoa64.charAt((value >> 18) & 0x3f));
        } while (i < count);
        return output.toString();
      }
  
    }


