How to hash a password with SHA-512 in Java?

102,498

Solution 1

you can use this for SHA-512 (Not a good choice for password hashing).

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;
}

Solution 2

Please stop using hash functions to encode passwords! They do not provide the protection you need. Instead, you should be using an algorithm like PBKDF2, bcrypt, or scrypt.

References:

Solution 3

Using Guava:

Hashing.sha512().hashString(s, StandardCharsets.UTF_8).toString()

Solution 4

Use Apache Commons Crypt, it features SHA-512 based crypt() functions that generate salted hashes that are even compatible to libc's crypt and thus usable in PHP/Perl/Python/C and most databases, too.

https://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/digest/Crypt.html#Crypt%28%29

Solution 5

you could use this to hash a password in java if you want to.

public static boolean isHashMatch(String password, // the password you want to check.
                                  String saltedHash, // the salted hash you want to check your password against.
                                  String hashAlgorithm, // the algorithm you want to use.
                                  String delimiter) throws NoSuchAlgorithmException // the delimiter that has been used to delimit the salt and the hash.
{
    // get the salt from the salted hash and decode it into a byte[].
    byte[] salt = Base64.getDecoder()
                        .decode(saltedHash.split(delimiter)[0]);
    // compute a new salted hash based on the provided password and salt.
    String pw_saltedHash = computeSaltedBase64Hash(password, 
                                                   salt,
                                                   hashAlgorithm,
                                                   delimiter);
    // check if the provided salted hash matches the salted hash we computed from the password and salt.
    return saltedHash.equals(pw_saltedHash);
}

public static String computeSaltedBase64Hash(String password, // the password you want to hash
                                             String hashAlgorithm, // the algorithm you want to use.
                                             String delimiter) throws NoSuchAlgorithmException // the delimiter that will be used to delimit the salt and the hash.
{
    // compute the salted hash with a random salt.
    return computeSaltedBase64Hash(password, null, hashAlgorithm, delimiter);
}

public static String computeSaltedBase64Hash(String password, // the password you want to hash
                                             byte[] salt, // the salt you want to use (uses random salt if null).
                                             String hashAlgorithm, // the algorithm you want to use.
                                             String delimiter) throws NoSuchAlgorithmException // the delimiter that will be used to delimit the salt and the hash.
{
    // transform the password string into a byte[]. we have to do this to work with it later.
    byte[] passwordBytes = password.getBytes();
    byte[] saltBytes;

    if(salt != null)
    {
        saltBytes = salt;
    }
        else
        {
            // if null has been provided as salt parameter create a new random salt.
            saltBytes = new byte[64];
            SecureRandom secureRandom = new SecureRandom();
            secureRandom.nextBytes(saltBytes);              
        }

    // MessageDigest converts our password and salt into a hash. 
    MessageDigest messageDigest = MessageDigest.getInstance(hashAlgorithm);
    // concatenate the salt byte[] and the password byte[].
    byte[] saltAndPassword = concatArrays(saltBytes, passwordBytes);
    // create the hash from our concatenated byte[].
    byte[] saltedHash = messageDigest.digest(saltAndPassword);
    // get java's base64 encoder for encoding.
    Encoder base64Encoder = Base64.getEncoder();
    // create a StringBuilder to build the result.
    StringBuilder result = new StringBuilder();

    result.append(base64Encoder.encodeToString(saltBytes)) // base64-encode the salt and append it.
          .append(delimiter) // append the delimiter (watch out! don't use regex expressions as delimiter if you plan to use String.split() to isolate the salt!)
          .append(base64Encoder.encodeToString(saltedHash)); // base64-encode the salted hash and append it.

    // return a salt and salted hash combo.
    return result.toString();
}

public static byte[] concatArrays(byte[]... arrays)
{   
    int concatLength = 0;
    // get the actual length of all arrays and add it so we know how long our concatenated array has to be.
    for(int i = 0; i< arrays.length; i++)
    {
        concatLength = concatLength + arrays[i].length;
    }
    // prepare our concatenated array which we're going to return later.
    byte[] concatArray = new byte[concatLength];
    // this index tells us where we write into our array.
    int index = 0;
    // concatenate the arrays.
    for(int i = 0; i < arrays.length; i++)
    {
        for(int j = 0; j < arrays[i].length; j++)
        {
            concatArray[index] = arrays[i][j];
            index++;
        }
    }
    // return the concatenated arrays.
    return concatArray;     
}
Share:
102,498
stack man
Author by

stack man

hello world

Updated on July 18, 2022

Comments

  • stack man
    stack man almost 2 years

    I've been investigating a bit about Java String encryption techniques and unfortunately I haven't find any good tutorial how to hash String with SHA-512 in Java; I read a few blogs about MD5 and Base64, but they are not as secure as I'd like to (actually, Base64 is not an encryption technique), so I prefer SHA-512.

  • stack man
    stack man over 8 years
    That's exactly what I was looking for my friend, thanks a lot.
  • artbristol
    artbristol over 8 years
    does not take character encoding into account, this has potential to break when you switch platform
  • A. Sinha
    A. Sinha over 8 years
    @artbristol please elaborate, what are the threats and how it can be minimized
  • artbristol
    artbristol over 8 years
    any time you turn a string into bytes, you need to specify an encoding. E.g. you should have passwordToHash.getBytes("UTF-8")
  • martinstoeckli
    martinstoeckli over 8 years
    @stackpepe - This should not be used to hash passwords, the SHA*-family is too fast and can be brute-forced too easily. With a good GPU you can calculate about 4 Giga SHA512 per second, that why one should switch to BCrypt, PBKDF2 or SCrypt.
  • martinstoeckli
    martinstoeckli over 8 years
    I support your answer, but commonly those algorithms are called hash functions too (PBKDF even uses SHA for example). It is difficult enough to explain the difference between encryption and hashing, so the advice not to use hash functions may be a bit confusing. The slowness makes the difference.
  • A. Sinha
    A. Sinha over 8 years
    @martinstoeckli Sir but we generally say dat we cud use a salt value to protect against dictionary attack...........can it also be compromised ?
  • martinstoeckli
    martinstoeckli over 8 years
    @Abhi - A salt prevents that an attacker can build one single rainbow-table to get all passwords at once, instead (s)he has to build a rainbow-table for each salt, what makes the attack unpracticable. The salt doesn't help at all against brute-forcing (often dictionary attack) a single password though. If brute-forcing a whole english dictionary only takes a fraction of a millisecond, then we need an algorithm with a cost factor, which defines how much time is necessary to calculate a single hash (BCrypt, PBKDF2, SCrypt).
  • TheGreatContini
    TheGreatContini over 8 years
    I entirely agree that the terminology is confusing! I have my only complaints in Section 1.4: eprint.iacr.org/2015/387.pdf . Terminology matters!
  • Maarten Bodewes
    Maarten Bodewes over 7 years
    @martinstoeckli Reading this back, this is not a correct remark. PBKDF2 is a key derivation function or password hashing function. That it uses a secure hash doesn't make it a secure hash in itself. There are many PBKDF's / password hashes that do not use secure hashes internally.
  • martinstoeckli
    martinstoeckli over 7 years
    @MaartenBodewes - Maybe the best expression for appropriate algorithms is password hashing function. What I meant is, that it sounds confusing when we say: don't use hash functions, use password hash functions. If we do that, we should explain what makes the difference, and the important point in this case is the "cost factor", or more generally, that we can control the necessary time to calculate a hash.
  • Maarten Bodewes
    Maarten Bodewes over 7 years
    Besides that the Salt is input as an UTF-8 String (while it is usually defined in bytes), the length is not checked, the exception handling isn't well defined (to the point that the code doesn't compile), the hexadecimal routine is hard to read and included in the method, Java naming conventions are not adhered to, bad coding practice by first assigning null when not needed...just a bad demo on how to use SHA-512. I guess the main reason for the upvotes is that this question comes up first in google for "SHA-512 Java" search term.
  • A. Sinha
    A. Sinha over 7 years
    @MaartenBodewes People need to put some efforts from their side as well to get a better output. The code that I have provided is not for copy paste but is just a hint that can surely be improved as per requirement.
  • Martijn Pieters
    Martijn Pieters about 7 years
    @Abhi: yet that is exactly what people will do: copy and paste.
  • ayke
    ayke over 5 years
    Sorry, but that's a downvote. Like TheGreatContini answers below (and martinstoeckli mentions in a comment) simply hashing a password is not good enough. Salting first is a bit better, but still not enough, you're working with passwords! Really, the only good answer to "how do I hash a password with SHA512" is "don't use SHA512 but something better like Argon2".
  • A. Sinha
    A. Sinha over 5 years
    @ayke People are free to use whatever they want depending upon their wish, may be someone could use bcrypt, others might like Argon2 etc. but since the question was regarding the implementation of SHA-512, I just provided that. With all due respect, I must say that my post is not to suggest the right approach (one should explore it at their own) but just to show the right implementation of the question asked. :)
  • ayke
    ayke over 5 years
    Of course people are free to use what they want. But giving them a false sense of security is not good. SHA-512 should not be used on it's own for password hashing except for rare cases where compatibility is needed with legacy system. The question indicates this is not the case.
  • 9ilsdx 9rvj 0lo
    9ilsdx 9rvj 0lo over 5 years
    It doesn't answer the question.
  • TheGreatContini
    TheGreatContini over 5 years
    I think this summarises the confusion: When Hashing isn't Hashing.
  • tresf
    tresf over 4 years
    I agree, this doesn't answer the question at all. People looking for SHA-512 Java code examples (regardless of WHY they need this) find a non-solution. Perhaps in the future you could 1. Offer a solution. 2. Offer the BETTER solution as a side-note.
  • salvador
    salvador almost 4 years
    this is still in beta btw