49

I am using BCryptPasswordEncoder with Spring security. My expectation was that for the same input I will always get the same output. But for the same input I get different output. You could test it with the code snippet below:

String password = "123456"; 
PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); 
String encodedPassword = passwordEncoder.encode(password);
System.out.print(encodedPassword);

output: $2a$10$cYLM.qoXpeAzcZhJ3oXRLu9Slkb61LHyWW5qJ4QKvHEMhaxZ5qCPi

output2: $2a$10$KEvYX9yjj0f1X3Wl8S.KPuWzSWGyGM9ubI71NOm3ZNbJcwWN6agvW

output3: $2a$10$nCmrPtUaOLn5EI73VZ4Ouu1TmkSWDUxxD4N6A.8hPBWg43Vl.RLDC

Could someone explain, why BCryptPasswordEncoder behave like this?

2
  • Why do you need the passwords to have the same hash? Commented Sep 15, 2014 at 10:06
  • 1
    The best answer to this question is here: How can bcrypt have built-in salts? Commented Feb 9, 2018 at 6:11

5 Answers 5

55
public static void main(String[] args) {
  // spring 4.0.0
  org.springframework.security.crypto.password.PasswordEncoder encoder
   = new org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder();

   // $2a$10$lB6/PKg2/JC4XgdMDXyjs.dLC9jFNAuuNbFkL9udcXe/EBjxSyqxW
   // true
   // $2a$10$KbQiHKTa1WIsQFTQWQKCiujoTJJB7MCMSaSgG/imVkKRicMPwgN5i
   // true
   // $2a$10$5WfW4uxVb4SIdzcTJI9U7eU4ZwaocrvP.2CKkWJkBDKz1dmCh50J2
   // true
   // $2a$10$0wR/6uaPxU7kGyUIsx/JS.krbAA9429fwsuCyTlEFJG54HgdR10nK
   // true
   // $2a$10$gfmnyiTlf8MDmwG7oqKJG.W8rrag8jt6dNW.31ukgr0.quwGujUuO
   // true

    for (int i = 0; i < 5; i++) {
      // "123456" - plain text - user input from user interface
      String passwd = encoder.encode("123456");

      // passwd - password from database
      System.out.println(passwd); // print hash

      // true for all 5 iteration
      System.out.println(encoder.matches("123456", passwd));
    }
}
Sign up to request clarification or add additional context in comments.

4 Comments

Made a simple tool using your code, might save time for some folks : github.com/raags/SpringPasswordEncoder
It is a bit counterintuitive that the name passwd in this example represents the encodedPassword (the hash code) -- not the rawPassword.
The question was "Could someone explain why BCryptPasswordEncoder behaves like this?" - This answer does not explain, but only provides code without a single word of explanation.
Version reference (4.0.0). full package-names for the objects. Upvote!
28

The generated password are salted and therefore different.

Please read the documentation for the encode() method where it clearly states the the password is salted.

5 Comments

can you give me example of it for same password ?
@Bhavesh what do you want to achieve? Why do you need the same hash for passwords?
i want to perform simple login & register operation with spring security using bcrpt .
@Bhavesh for this there exists the method matches()[docs.spring.io/spring-security/site/docs/3.2.5.RELEASE/apidocs/…. Please read the documentation of the classes you want to use.
Your phrasing tripped me up a bit: the encoder does not generate passwords, it generated codes that consist salt + hashed password + other detalis (see other answer). In addition: the documentation (at time of this writing) is copied from the interface and only states that a good encoder uses a salt.
22

The 22 characters directly after the 3rd $ represent the salt value, see https://en.wikipedia.org/wiki/Bcrypt#Description . "Salt" is some random data added to the password before hashing, so a given hash algorithm with given parameters will in most cases produce different hash values for the same password (protection against so called rainbow attacks).

Let's dissect the first output shown in the original question: $2a$10$cYLM.qoXpeAzcZhJ3oXRLu9Slkb61LHyWW5qJ4QKvHEMhaxZ5qCPi

  • $2a : Identifier for BCrypt algorithm
  • $10 : Parameter for number of rounds, here 2^10 = 1.024 rounds
  • cYLM.qoXpeAzcZhJ3oXRLu : Salt (128 bits)
  • 9Slkb61LHyWW5qJ4QKvHEMhaxZ5qCPi : Actual hash value (184 bits)

The salt and the hash value are both encoded using Radix-64.

Comments

8

That is perfectly normal because BCryptPasswordEncoder uses a salt to generate the password. You can read about the idea behind "salting" a password here and here.

This is what the documentation says for the encode method

Encode the raw password. Generally, a good encoding algorithm applies a SHA-1 or greater hash combined with an 8-byte or greater randomly generated salt.

Comments

1

The BCrypt output is: $2a$10$cYLM.qoXpeAzcZhJ3oXRLu9Slkb61LHyWW5qJ4QKvHEMhaxZ5qCPi

$2a$ means the hash algorithm

10$ is the log rounds

following is the salt and hashed password

since the Spring will generate the salt will different on each time, so your output is not same. the BCrypt syntax you can reference https://en.wikipedia.org/wiki/Bcrypt#Description

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.