I, Me and Myself

How to store passwords in Java

In Technology on October 9, 2009 at 12:33 am

There are two choices

Jasypt

Here are the cardinals rules of storing user passwords, and these not only apply to Java but to all other programming language as well.How to encrypt user passwords.Read this before going any further

To summarize, you must use an secure hashing algorithm which which allows for a random salt as an input, and one which hashes the resultant output at least 1000 times.

The generic form of any secure hashing works like this.

Generating a Hash

salt = GET salt
hash_bytes = algo("data to hash",salt,number of rounds)
hash_string = base64 ecnode(hash_bytes)
store(hash_string)


You supply a salt using any random salt generator. The number of rounds must be more than 1000. This is to make brute force reversal computationly expensive. The algorithm therefore takes 3 parameters the data itself, the random salt, and number of rounds. The resulting hash is in bytes. The raw bytes however cannot be stored easily to databases. Therefore we convert it to a hexadecimal string which can be easily stored.

Checking passwords

submitted_password = GET passwords
hash_bytes = algo(submitted_password,salt,number of rounds)
hash_string = base64 ecnode(hash_bytes)
stored_hash = GET stored hash
IF hash_string = stored_hash
	password is valid

Checking a password involves generating the hash again from the submitted password and then comparing the hash to the stored hash. The basic premise is that the same password, with the same salt and using the same number of rounds always generates the same hash.

However Jasypt makes all this super easy. It hides all that complexity. Here’s how you use it.

import org.jasypt.util.password.*;

import java.util.*;

/**
 * @author $Author$
 * @version $Revision$
 *          Created on Oct 8, 2009-3:01:49 PM
 */
public class JasyptDemo
{
	private static final String username = "testuser";
	private static final String userpass = "testpass";
	private static LinkedHashMap<String, String> database = new LinkedHashMap<String, String>();

	public String encryptPassword()
	{
		StrongPasswordEncryptor passwordEncryptor = new StrongPasswordEncryptor();
		String encryptedPassword = passwordEncryptor.encryptPassword(userpass);
		storePasswordForUser(username, encryptedPassword);
		return encryptedPassword;
	}

	public boolean checkPassword(String username, String submittedPassword)
	{
		StrongPasswordEncryptor passwordEncryptor = new StrongPasswordEncryptor();
		String encryptedPassword = database.get(username);
		return passwordEncryptor.checkPassword(submittedPassword, encryptedPassword);
	}

	public void storePasswordForUser(String username, String hashedPassword)
	{
		// use jdbc to store the username and hashed password in the database.
		database.put(username, hashedPassword);
	}

	public String getPasswordForUser(String username)
	{
		// use jdbc to retrieve the password for this username,
		return database.get(username);
	}

	public static void main(String[] args)
	{
		JasyptDemo encrypter = new JasyptDemo();
		encrypter.encryptPassword();

		JasyptDemo checker = new JasyptDemo();
		System.out.println("Passwords Matched " + (checker.checkPassword(username, userpass)));
	}
}

What Jasypt does is that it stores the salt inside the hash itself. This means there is no need to store the salt seprately. You just store the hashed password and retrieve it each time for comparision when the user supplies their login credentials. It can’t get easier than this.

JBcrypt

If you thought Jasypt was simple there something even simpler than this. It’s called JBcrypt. JBcrypt is a Java implementation of OpenBSD’s Blowfish password hashing scheme. Here’s example of using JBcrypt.

// Hash a password for the first time
String hashed = BCrypt.hashpw(password, BCrypt.gensalt());

// gensalt's log_rounds parameter determines the complexity
// the work factor is 2**log_rounds, and the default is 10
String hashed = BCrypt.hashpw(password, BCrypt.gensalt(12));

// Check that an unencrypted password matches one that has
// previously been hashed
if (BCrypt.checkpw(candidate, hashed))
	System.out.println("It matches");
else i
	System.out.println("It does not match");

Comparision Between JBcrypt and Jasypt

Now comes the fun part. Which is more secure Jasypt or JBcrypt?

Well, out of the box and both are as secure and may be as fast. Bcrypt’s strengths and weaknesses are outlined in this paper “A Future-Adaptable Password Scheme” by Niels Provos and David Mazières. On the other hand StrongPasswordEncryptor uses SHA-256 as it’s hashing algorithm. No you do a search of SHA256 VS Bcrypt and decide which to use. I am not suggesting anything.

Jasypt is also configurable. The ConfigurablePasswordEncryptor allows to you change the hashing algorithm. For example let’s use SHA-512. But since the JDK does not supply a SHA-512 hashing algorithm, you can use the setProvider(“provider name”) method of the ConfigurablePasswordEncryptor to set the JCE provider as Bouncy Castle which does support SHA-512.

Here’s how you use ConfigurablePasswordEncryptor with BouncyCastleProvider and SHA-512 as the hashing algorithm.

import org.bouncycastle.jce.provider.*;
import org.jasypt.util.password.*;

import java.util.*;

/**
 * @author $Author$
 * @version $Revision$
 *          Created on Oct 8, 2009-3:01:49 PM
 */
public class JasyptDemo
{
	private static final String username = "testuser";
	private static final String userpass = "testpass";
	private static LinkedHashMap<String, String> database = new LinkedHashMap<String, String>();

	public String encryptPassword()
	{
		ConfigurablePasswordEncryptor passwordEncryptor = new ConfigurablePasswordEncryptor();
		passwordEncryptor.setProvider(new BouncyCastleProvider());
		passwordEncryptor.setAlgorithm("SHA-512");
		String encryptedPassword = passwordEncryptor.encryptPassword(userpass);
		storePasswordForUser(username, encryptedPassword);
		return encryptedPassword;
	}

	public boolean checkPassword(String username, String submittedPassword)
	{
		ConfigurablePasswordEncryptor passwordEncryptor = new ConfigurablePasswordEncryptor();
		passwordEncryptor.setProvider(new BouncyCastleProvider());
		passwordEncryptor.setAlgorithm("SHA-512");
		String encryptedPassword = database.get(username);
		return passwordEncryptor.checkPassword(submittedPassword, encryptedPassword);
	}

	public void storePasswordForUser(String username, String hashedPassword)
	{
		// use jdbc to store the username and hashed password in the database.
		database.put(username,hashedPassword);
	}

	public String getPasswordForUser(String username)
	{
		// use jdbc to retrieve the password for this username,
		return database.get(username);
	}

	public static void main(String[] args)
	{
		JasyptDemo encrypter = new JasyptDemo();
		encrypter.encryptPassword();

		JasyptDemo checker = new JasyptDemo();
		System.out.println("Passwords Matched " + (checker.checkPassword(username, userpass)));
	}
}

Which one of Jasypt or JBcrypt do I use? I use JBcrypt, because it is just one Java File. However Jasypt is more than just one algorithm. It’s a complete framework. Just make sure that you don’t use the BasicPasswordEncryptor as this uses MD5 as it’s hashing algorithm. Use the StrongPasswordEncryptor class or the ConfigurablePasswordEncryptor class instead with SHA-512 as the hashing algorithm. Do also remember that SHA and MD5 type algorithms are fixed cost algorithms while Bcrypt is not.

Summary

Use JBcrypt.It only does one thing but does it right. Use Jasypt when you want to have a more fine grained control of the entire process.

  1. Hi, I’m Jasypt’s founder and main developer and first of all, I want to thank you for the review, it is great.

    Nevertheless, I have one point to make: StrongPasswordEncryptor uses the SHA-256 algorithm with a 16-byte salt and iterated 100,000 times, as you can read in the API docs. It is BasicPasswordEncryptor the one that uses MD5.

    Regards,
    Daniel.

    • Hi Daniel,

      I apologize for the oversight. The post has now been updated accordingly. I have now recommended StrongPasswordEncryptor, as this will be good enough for most things.

      Let me also thank you for this wonderfully written framework. It was a pleasure to read the code.

      Regards
      Swapnonil