Java password hashing function

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

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.

SHA2 is not an encryption technique either. It is a family of cryptographical secure hash functions, it can be used for message digest, not encryption (at least no in normal mode). You need to describe a bit more what you want to do. Other than that yur MD5 code should work with other hash algrithms as well, just exchange the algorithm name. The output of all of them is a binary byte[] array, so you might want to use base64 or binhex to make the result ascii only.

SHA-512 is not an encryption algorithm either. Actually, it’s designed specifically to make it impossible to «decrypt» the digest produced by this hashing algorithm. What do you want to achieve?

A java String contains valid Unicode. Getting the bytes in some charset (like UTF-8) and then encrypting them yields bytes that cannot be correctly translated to a String (for decrypting), certainly not with UTF-8 which requires correct sequences. Hence often Base64 is added to translate encrypted bytes into ASCII.

There is no cryptographic algorithm that allows doing what you want. Either you want encryption (but you shouldn’t if the goal is to store passwords), and you need a key to encrypt/decrypt. Or you want a salt and a digest function (and a hashing function is what you want, although SHA-512 is considered too weak for that usage). The principle of salt + digest is that you can check if a submitted password is correct by resalting and redigesting it, and then check that the result is identical to the one stored in database. But it’s impossible to reverse the result and get the original password.

Use PBKDF2WithHmacSHA1 (which comes with the JDK) or BCrypt. But first, learn the principles of crypto.

7 Answers 7

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

@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.

@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).

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.

Читайте также:  Java invalid cen header

@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.

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.

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.

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!

@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.

@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.

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.

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

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.

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

Источник

Читайте также:  Java convert class to int

How can I hash a password in Java?

I need to hash passwords for storage in a database. How can I do this in Java? I was hoping to take the plain text password, add a random salt, then store the salt and the hashed password in the database. Then when a user wanted to log in, I could take their submitted password, add the random salt from their account information, hash it and see if it equates to the stored hash password with their account information.

@YGL this is actually not a recombination nowadays with GPU attacks being so cheap, SHA family is actually a very bad choice for password hashing (too fast) even with salt. Use bcrypt, scrypt or PBKDF2

Why was this question closed? This is a question for a real engineering problem, and the answers are invaluable. The OP is not asking for a library, he is asking how to solve the engineering problem.

This question should be re-opened. It’s a question about how to write a program to solve the problem described (password authentication), with a short code solution. Seeing the trigger word «library» doesn’t justify reflexively closing a question; he’s not asking for a library recommendation, he’s asking how to hash passwords. Edit: There, fixed it.

14 Answers 14

You can actually use a facility built in to the Java runtime to do this. The SunJCE in Java 6 supports PBKDF2, which is a good algorithm to use for password hashing.

SecureRandom random = new SecureRandom(); byte[] salt = new byte[16]; random.nextBytes(salt); KeySpec spec = new PBEKeySpec("password".toCharArray(), salt, 65536, 128); SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); byte[] hash = f.generateSecret(spec).getEncoded(); Base64.Encoder enc = Base64.getEncoder(); System.out.printf("salt: %s%n", enc.encodeToString(salt)); System.out.printf("hash: %s%n", enc.encodeToString(hash)); 

Here’s a utility class that you can use for PBKDF2 password authentication:

import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.spec.InvalidKeySpecException; import java.security.spec.KeySpec; import java.util.Arrays; import java.util.Base64; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; /** * Hash passwords for storage, and test passwords against password tokens. * * Instances of this class can be used concurrently by multiple threads. * * @author erickson * @see StackOverflow */ public final class PasswordAuthentication < /** * Each token produced by this class uses this identifier as a prefix. */ public static final String /** * The minimum recommended cost, used by default */ public static final int DEFAULT_COST = 16; private static final String ALGORITHM = "PBKDF2WithHmacSHA1"; private static final int SIZE = 128; private static final Pattern layout = Pattern.compile("\\$31\\$(\\d\\d?)\\$(.)"); private final SecureRandom random; private final int cost; public PasswordAuthentication() < this(DEFAULT_COST); >/** * Create a password manager with a specified cost * * @param cost the exponential computational cost of hashing a password, 0 to 30 */ public PasswordAuthentication(int cost) < iterations(cost); /* Validate cost */ this.cost = cost; this.random = new SecureRandom(); >private static int iterations(int cost) < if ((cost < 0) || (cost >30)) throw new IllegalArgumentException("cost: " + cost); return 1 /** * Hash a password for storage. * * @return a secure authentication token to be stored for later authentication */ public String hash(char[] password) < byte[] salt = new byte[SIZE / 8]; random.nextBytes(salt); byte[] dk = pbkdf2(password, salt, 1 /** * Authenticate with a password and a stored password token. * * @return true if the password and token match */ public boolean authenticate(char[] password, String token) < Matcher m = layout.matcher(token); if (!m.matches()) throw new IllegalArgumentException("Invalid token format"); int iterations = iterations(Integer.parseInt(m.group(1))); byte[] hash = Base64.getUrlDecoder().decode(m.group(2)); byte[] salt = Arrays.copyOfRange(hash, 0, SIZE / 8); byte[] check = pbkdf2(password, salt, iterations); int zero = 0; for (int idx = 0; idx < check.length; ++idx) zero |= hash[salt.length + idx] ^ check[idx]; return zero == 0; >private static byte[] pbkdf2(char[] password, byte[] salt, int iterations) < KeySpec spec = new PBEKeySpec(password, salt, iterations, SIZE); try < SecretKeyFactory f = SecretKeyFactory.getInstance(ALGORITHM); return f.generateSecret(spec).getEncoded(); >catch (NoSuchAlgorithmException ex) < throw new IllegalStateException("Missing algorithm: " + ALGORITHM, ex); >catch (InvalidKeySpecException ex) < throw new IllegalStateException("Invalid SecretKeyFactory", ex); >> /** * Hash a password in an immutable . * * 

Passwords should be stored in a so that it can be filled * with zeros after use instead of lingering on the heap and elsewhere. * * @deprecated Use instead */ @Deprecated public String hash(String password) < return hash(password.toCharArray()); >/** * Authenticate with a password in an immutable and a stored * password token. * * @deprecated Use instead. * @see #hash(String) */ @Deprecated public boolean authenticate(String password, String token) < return authenticate(password.toCharArray(), token); >>

Источник

Оцените статью