How to Hash a Password in Java

How can I hash a password in Java?

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.

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 <a href="http://stackoverflow.com/a/2861125/3474">StackOverflow</a>
*/
public final class PasswordAuthentication
{

/**
* Each token produced by this class uses this identifier as a prefix.
*/
public static final String ID = "$31$";

/**
* 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?)\\$(.{43})");

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

/**
* 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 << cost);
byte[] hash = new byte[salt.length + dk.length];
System.arraycopy(salt, 0, hash, 0, salt.length);
System.arraycopy(dk, 0, hash, salt.length, dk.length);
Base64.Encoder enc = Base64.getUrlEncoder().withoutPadding();
return ID + cost + '$' + enc.encodeToString(hash);
}

/**
* 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 {@code String}.
*
* <p>Passwords should be stored in a {@code char[]} so that it can be filled
* with zeros after use instead of lingering on the heap and elsewhere.
*
* @deprecated Use {@link #hash(char[])} instead
*/
@Deprecated
public String hash(String password)
{
return hash(password.toCharArray());
}

/**
* Authenticate with a password in an immutable {@code String} and a stored
* password token.
*
* @deprecated Use {@link #authenticate(char[],String)} instead.
* @see #hash(String)
*/
@Deprecated
public boolean authenticate(String password, String token)
{
return authenticate(password.toCharArray(), token);
}

}

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

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

How can I hash the password in my app

Ah ok. As per discussion in Comment. So in your class that takes the password as input you have to implement this method.

So what you have to do is implement the answer method in your class itself. So add below method in your class -

public String md5(String s) {
try {
// Create MD5 Hash
MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
digest.update(s.getBytes());
byte messageDigest[] = digest.digest();

// Create Hex String
StringBuffer hexString = new StringBuffer();
for (int i=0; i<messageDigest.length; i++)
hexString.append(Integer.toHexString(0xFF & messageDigest[i]));
return hexString.toString();

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

Now in your Async task you are doing this -

 String password = editTextPassword.getText().toString();

Instead pass this value to your md5 method and get the hashed code as password.

String password = md5(editTextPassword.getText().toString());

Java - Spring - Basic authentication - How to hash the password defined in application.properties

Since you want to define your credentials in properties file, I guess you can take advantage of inmemory authentication. Try the following:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

private static final Logger logger = LoggerFactory.getLogger(SecurityConfig.class);

private AuthenticationProvider authenticationProvider;

@Value("${user.name}")
private String userName;

@Value("${user.password}")
private String userHashedPassword; // hashed password

@Override
protected void configure(HttpSecurity http) throws Exception {

http.csrf().disable().authorizeRequests().anyRequest().authenticated().and().httpBasic()
.and().sessionManagement().and().authenticationProvider(authenticationProvider)
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
}

@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth
.inMemoryAuthentication()
.passwordEncoder(passwordEncoder())
.withUser(userName)
.password(userHashedPassword);
}

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}

Please, note, that in this case your password should be encrypted with BCryptPasswordEncoder first, and then you should put it into properties file (you can use its encoder.encode("password") method). Or you can use any other implementation of PasswordEncoder if you want. I've also noticed that you're using some custom autenticationProvider. Not sure how it works since you didnt share the code, and not sure that it will get along with inmemory autentication. But, anyway, I think it worth a shot and this is the right way to go in your scenario.
Hope it helps.



Related Topics



Leave a reply



Submit