Skip to content

Instantly share code, notes, and snippets.

@craSH
Last active January 19, 2024 14:26
Show Gist options
  • Star 83 You must be signed in to star a gist
  • Fork 26 You must be signed in to fork a gist
  • Save craSH/5217757 to your computer and use it in GitHub Desktop.
Save craSH/5217757 to your computer and use it in GitHub Desktop.
A simple example Java class to safely generate and verify bcrypt password hashes for use in authentication systems.
/**
* Author: Ian Gallagher <igallagher@securityinnovation.com>
*
* This code utilizes jBCrypt, which you need installed to use.
* jBCrypt: http://www.mindrot.org/projects/jBCrypt/
*/
public class Password {
// Define the BCrypt workload to use when generating password hashes. 10-31 is a valid value.
private static int workload = 12;
/**
* This method can be used to generate a string representing an account password
* suitable for storing in a database. It will be an OpenBSD-style crypt(3) formatted
* hash string of length=60
* The bcrypt workload is specified in the above static variable, a value from 10 to 31.
* A workload of 12 is a very reasonable safe default as of 2013.
* This automatically handles secure 128-bit salt generation and storage within the hash.
* @param password_plaintext The account's plaintext password as provided during account creation,
* or when changing an account's password.
* @return String - a string of length 60 that is the bcrypt hashed password in crypt(3) format.
*/
public static String hashPassword(String password_plaintext) {
String salt = BCrypt.gensalt(workload);
String hashed_password = BCrypt.hashpw(password_plaintext, salt);
return(hashed_password);
}
/**
* This method can be used to verify a computed hash from a plaintext (e.g. during a login
* request) with that of a stored hash from a database. The password hash from the database
* must be passed as the second variable.
* @param password_plaintext The account's plaintext password, as provided during a login request
* @param stored_hash The account's stored password hash, retrieved from the authorization database
* @return boolean - true if the password matches the password of the stored hash, false otherwise
*/
public static boolean checkPassword(String password_plaintext, String stored_hash) {
boolean password_verified = false;
if(null == stored_hash || !stored_hash.startsWith("$2a$"))
throw new java.lang.IllegalArgumentException("Invalid hash provided for comparison");
password_verified = BCrypt.checkpw(password_plaintext, stored_hash);
return(password_verified);
}
/**
* A simple test case for the main method, verify that a pre-generated test hash verifies successfully
* for the password it represents, and also generate a new hash and ensure that the new hash verifies
* just the same.
*/
public static void main(String[] args) {
String test_passwd = "abcdefghijklmnopqrstuvwxyz";
String test_hash = "$2a$06$.rCVZVOThsIa97pEDOxvGuRRgzG64bvtJ0938xuqzv18d3ZpQhstC";
System.out.println("Testing BCrypt Password hashing and verification");
System.out.println("Test password: " + test_passwd);
System.out.println("Test stored hash: " + test_hash);
System.out.println("Hashing test password...");
System.out.println();
String computed_hash = hashPassword(test_passwd);
System.out.println("Test computed hash: " + computed_hash);
System.out.println();
System.out.println("Verifying that hash and stored hash both match for the test password...");
System.out.println();
String compare_test = checkPassword(test_passwd, test_hash)
? "Passwords Match" : "Passwords do not match";
String compare_computed = checkPassword(test_passwd, computed_hash)
? "Passwords Match" : "Passwords do not match";
System.out.println("Verify against stored hash: " + compare_test);
System.out.println("Verify against computed hash: " + compare_computed);
}
}
@ValeriyaChudnay
Copy link

what library should be included to use BCrypt?

org.springframework.security

@craSH
Copy link
Author

craSH commented May 15, 2021

what library should be included to use BCrypt?

org.springframework.security

In this example code I used http://www.mindrot.org/projects/jBCrypt/ - but this gist of mine is fairly old at this point, I've not checked to see if it still holds up! Use at your own risk and please research the specifics to understand any risks :)

@majguido
Copy link

Great example! Thank you. Some friendly advice: check out camel case variables. https://www.geeksforgeeks.org/java-naming-conventions/

@yhojann-cl
Copy link

BCrypt package is defined in multiple artifacts, the code is ambiguous.

@craSH
Copy link
Author

craSH commented Jan 20, 2022

The original gist states that it used http://www.mindrot.org/projects/jBCrypt/ for the implementation - but this gist is also 9 years old and was just a proof of concept then, I suspect there are far better references available these days - I don't maintain this, so please use at your own risk and at this point for reference only.

@22584943
Copy link

Thank you so much

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment