3

I have a Dovecot server with MySQL database for storing usernames and passwords. The passwords in the database are in SHA512-CRYPT scheme.

I am inserting the hashed passwords in the database using a script.

doveadm pw -s SHA512-CRYPT -p password -r 500000

I want to hash the passwords using a JAVA application. I found this questions and I tried to create the same resulting hash using same password firstpassword and salt FooBarBaz. For some reason the resulting hash I get is different, although I am using the same hashing algorithm, salt and password.

Here is my Java code:

byte[] password = "firstpassword".getBytes();
byte[] salt = "FooBarBaz".getBytes();

MessageDigest digest = MessageDigest.getInstance("SHA-512");
digest.reset();
digest.update(salt);
byte[] hashed = digest.digest(password);

String encodedHash = Base64.getEncoder().encodeToString(hashed);

System.out.printf("{SHA512-CRYPT}$6$%s$%s", "FooBarBaz",encodedHash);

This outputs the hash:

{SHA512-CRYPT}$6$FooBarBaz$5WPtOnXVI/a6f003WByGKIcsfa6x0ansxiyE8uEfJ0TE5pI+Rv9kcMLgdZboKg7ZSWQgWFg+pIqruvdg6aiP/g==

I also tried swapping the order of salt + password to make it:

digest.update(password);
byte[] hashed = digest.digest(salt);

this gives me:

{SHA512-CRYPT}$6$FooBarBaz$QWS8+W5EWhModF+uO2tcsd55tDxzdzGJ5FurIbEgwVCwKfT5UqwIvBNG1Oyws8bZEFdeGgyD0u6zS1KArvGf9Q==

Does anyone have any idea how can I accomplish the same hash results in Java if I use the same password and salt?

The hash I am looking for is:

{SHA512-CRYPT}$6$FooBarBaz$.T.G.7FRJqZ6N2FF7b3BEkr5j37CWhwgvPOOoccrr0bvkBbNMmLCxzqQqKJbNhnhC.583dTBLEuZcDuQe7NEe.
Community
  • 1
  • 1
Abdulrahman Alsoghayer
  • 16,462
  • 7
  • 51
  • 56
  • I guess, sha will generate random hashes for same strings and salts. You just have to check them using builtin check functions – waplet Jul 14 '15 at 08:21
  • 1
    @waplet that's not true. Same input = same hash, that's one basic requirement of every hashing algorithm. Furthermore, the op asks explicitly how to create those hashes, not to check them. – bratkartoffel Jul 14 '15 at 08:55

1 Answers1

7

doveadm uses the Unix crypt family of functions to generate the hash and outputs the hash as a Base64 encoded string. The alphabet used for the encoding (by crypt) is [a-zA-Z0-9./] (as mentioned on the man page for the functions). However, the alphabet used by the java.util.Base64 class is [A-Za-z0-9+/] (compliant with RFC 4648, as mentioned on the JavaDoc page for the Base64 class). Therefore, even if the hashed values are the same, they will get encoded differently.

A reliable option is to use the Crypt class from Apache Commons Codec as Crypt.crypt("firstpassword", "$6$FooBarBaz") (The prefix $6$ is mandatory to instruct Crypt that the SHA512-CRYPT algorithm needs to be used). This will generate your expected hash value.

manish
  • 19,695
  • 5
  • 67
  • 91
  • 1
    Thank you manish.. could you also add in your answer that it's possible to to specify the number of iterations "rounds".. with `Crypt.crypt("firstpassword", "$6$rounds=123123$FooBarBaz")` I already tried it and it works perfectly – Abdulrahman Alsoghayer Jul 14 '15 at 16:45
  • It's not only the different alphabet, the crypt() function uses an algorithm that is based on the SHA-512 digest but also takes a salt value into account and then does several thousand rounds of SHA-512 just to make it slower and thus brute-forcing less likely. Using Apache Commons Codec Crypt.crypt() is the correct solution nevertheles! – lathspell Jul 14 '15 at 16:46
  • You sir are a life-safer! A single upvote is not enough to show my gratitude. So expect more than that ;-) – GhostCat Jan 24 '17 at 14:24
  • I created a simple webservice based on your answer to generate Dovecot hashes: https://passwordhasher.projecttac.com/ – Tarator May 09 '19 at 12:04