Skip to content
David Bertoldi edited this page May 4, 2021 · 3 revisions

bcrypt is a password-hashing function, based on the Blowfish cipher. Besides incorporating a salt to protect against rainbow table attacks, bcrypt is an adaptive function: over time, the iteration count can be increased to make it slower, so it remains resistant to brute-force search attacks even with increasing computation power.

📑 Define bcrypt parameters

bcrypt accepts 2 parameters: the version of the algorithm (a, x, y or b) and the cost factor, that is the number of rounds in logarithmic form (e.g. cost factor of 10 means 210 = 1024 rounds).

Name Default value Properties Description
Version b hash.bcrypt.minor Defines the minor version of bcrypt
Cost factor 10 hash.bcrypt.rounds Defines the number of rounds expressed as exponent of base 2

The suggested version of the algorithm is b, the latest one. The other versions should be used only for backward compatibility reasons and we recommend to update your hashes as soon as possible.

You can define a singleton custom bcrypt function by calling BCryptFunction.getInstance(BCrypt, int) or BCryptFunction.getInstance(int)

BcryptFunction bcrypt = BcryptFunction.getInstance(Bcrypt.Y, 11);

In this case you have created a singleton instance which uses version y of bcrypt and has a cost factor of 211 = 2048.

Alternatively if you have defined the parameters in the psw4j.properties file

BcryptFunction bcrypt = AlgorithmFinder.getBcryptInstance();

Additionally you can create a BcryptFunction singleton instance from the hash, since all the parameters required are stored into it.

String hashed = "$2y$06$9JujYcoWPmifvFA3RUP90e5rSEHAb5Ye6iv3.G9ikiHNv5cxjNEse";

BcryptFunction bcrypt = BcryptFunction.getInstanceFromHash(hashed);

#️⃣ How to hash passwords

Hashing passwords with bcrypt can be done quite easily.

Hash hash = Password.hash(plainTextPassword).withBcrypt();

hash.getResult(); // $2b$10$LgfYWkbzEvQ4JakH7rOvHe0y8pHKF9OaFgwUZ2q7W2FFZmZzJYlfS

This approach takes the parameters from psw4j.properties file (like AlgorithmFinder.getBCryptInstance()). However it's possible to use user-defined parameters as we saw previously

BcryptFunction myBcrypt = BcryptFunction.getInstance(Bcrypt.Y, 11);

Password.hash(plainTextPassword).with(myBcrypt);

Add salt

bcrypt calculates the salt by its own depending on the algorithm's parameters and it is not possible to specify a custom salt in order to avoid inconsistencies.

Add pepper

Method addPepper(CharSequence) make you define the intended pepper.

Hash hash = Password.hash(plainTextPassword).addPepper("AlicePepper").withBCrypt();

Alternatively you can define the pepper in the psw4j.properties file at the property global.pepper

Hash hash = Password.hash(plainTextPassword).addPepper().withBCrypt();

The pepper is always prepended.

✔️ How to check the hash

Ideally the hash is retrieved from the database. Once retrieved you can check the user-provided passwords against the hash from your database. The salt is always encoded within the hash.

String hashFromDB = getHashFromDatabase(user);

boolean verified = Password.check(userProvidedPassword, hashFromDB).withBcrypt();

The parameters used are taken from your psw4j.properties file. Alternatively you can define your own parameters

String hashFromDB = getHashFromDatabase(user);

BcryptFunction myBcrypt = BcryptFunction.getInstance(Bcrypt.Y, 11);

boolean verified = Password.check(userProvidedPassword, hashFromDB).with(myBcrypt);

🔄 How to update the hash

If you want to migrate your cryptographic hashes from the original configuration to a more secure one, you can refresh them during the first user login.

String hashFromDB = getHashFromDatabase(user);

BcryptFunction myBcrypt = BcryptFunction.getInstance(Bcrypt.B, 12);

HashUpdate update = Password.check(userProvidedPassword, hashFromDB)
                            .andUpdate()
                            .addNewRandomSalt().with(myBcrypt);

if(update.isVerified()) 
{
    Hash newHash = update.getHash();
    storeNewHash(user, newHash.getHash());
}

You can switch to any other hashing function offered by Password4j (for example Argon2)

BcryptFunction oldFunction = BCryptFunction.getInstance(Bcrypt.A, 10);
Argon2Function newFunction = AlgorithmFinder.getArgon2Function();

HashUpdate update = Password.check(userProvidedPassword, hashFromDB)
                            .andUpdate()
                            .addNewRandomSalt().with(oldFunction, newFunction);