Skip to content

Spring Security Bcrypt with strength/log rounds = 31 results in 'Bad number of rounds' error although 31 should be ok #11470

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
sabinewinklerboi opened this issue Jul 7, 2022 · 5 comments
Assignees
Labels
in: crypto An issue in spring-security-crypto status: backported An issue that has been backported to maintenance branches type: bug A general bug
Milestone

Comments

@sabinewinklerboi
Copy link

sabinewinklerboi commented Jul 7, 2022

Describe the bug:
I implement a webapp using Spring Boot and Spring Security. Passwords of my users are stored in my DB after encoding with Bcrypt (BCryptVersion $2a).
I use Bcrypt of Spring Security with strength = 31 (new BCryptPasswordEncoder(31)).
When I run my webapp and try to do a login with a user, I get the error Bad number of rounds.

Analysis:
As far as I have seen this is because within org.springframework.security.crypto.bcrypt.BCrypt, method crypt_raw(...) roundsForLogRounds method is called with log_rounds = 31 and returns the value 2147483648, but this calculated value is greater than Integer.MAX_VALUE (=2147483647) and thus results in the mentioned error.
See the following code in crypt_raw():

rounds = roundsForLogRounds(log_rounds);
if (rounds < 16 || rounds > Integer.MAX_VALUE) {
    throw new IllegalArgumentException("Bad number of rounds");
}

Expected behaviour:
As far as I have seen in the JavaDoc and in the source of Spring Security, BCryptPasswordEncoder accepts a strength (= log rounds) between 4 (inclusive) and 31 (inclusive). So 31 should be ok and the resulting Bad number of rounds error is probably a bug.

Version
Spring Boot v2.7.1
Spring v5.3.21
Spring Security v5.7.2

With Spring Boot v2.6.6 and Spring Security v5.6.2 strength = 31 worked as expected. Maybe the behaviour changed in commit e6297d3 ?

@sabinewinklerboi sabinewinklerboi added status: waiting-for-triage An issue we've not yet triaged type: bug A general bug labels Jul 7, 2022
@jzheaux
Copy link
Contributor

jzheaux commented Jul 7, 2022

I agree that the check probably needs an adjustment, though I wonder if you really want the rounds to be set to 31 as this will cause each hash to take 2-3 days to compute on typical hardware.

Are you able to submit a PR that corrects the logic so that 31 rounds works again?

@jzheaux jzheaux added in: crypto An issue in spring-security-crypto and removed status: waiting-for-triage An issue we've not yet triaged labels Jul 7, 2022
@jzheaux jzheaux self-assigned this Jul 7, 2022
@jzheaux jzheaux added this to the 6.0.0-M6 milestone Jul 7, 2022
@sabinewinklerboi
Copy link
Author

sabinewinklerboi commented Jul 8, 2022

@jzheaux Thanks for the hint regarding if 31 is really a meaningful value to use. I first did not question why the code was executed so fast (with the older version Spring Security v5.6.2) although 31 should lead to a computation of 2-3 days. 🙈
I will try to change it from 31 to a faster alternative (probably 12 so that the algorithm is maximally strong and encoding a pwd takes a reasonable time).

I'm new to Spring Security and new to contributing to open source projects so I would feel better if you could do the changes. Would that be ok?

I further analysed the code a little bit and as far as I have seen, if you want to support log_rounds = 31, probably the check of rounds > Integer.MAX_VALUE has to be removed and the variable i in the for loop has to be of type long instead of int.

rounds = roundsForLogRounds(log_rounds);
if (rounds < 16 || rounds > Integer.MAX_VALUE) {  // remove "rounds > Integer.MAX_VALUE" here?
    throw new IllegalArgumentException("Bad number of rounds");
}
for (int i = 0; i < rounds; i++) {  // use "long i" here?
    key(password, sign_ext_bug, safety);
    key(salt, false, safety);
}

Alternatively, from my point of view, it would also be possible to restrict strength/log_rounds to the range 4 (inclusive) to 30 (inclusive) to avoid the int overflows. But then you have to adapt the checks where the range 4 to 30 is checked and you have to adapt the samples/unit tests, JavaDoc, etc.

@jzheaux
Copy link
Contributor

jzheaux commented Jul 11, 2022

For help with changing your existing hashes, please see https://github.com/spring-io/cve-2022-22976-bcrypt-skips-salt.

I'm new to Spring Security and new to contributing to open source projects so I would feel better if you could do the changes. Would that be ok?

Sure no problem.

@apatelWU
Copy link

apatelWU commented Sep 26, 2022

@jzheaux still getting same issue with spring security 5.7.2. Recently pulled the latest version of 5.7.2 but doesnt look like
changes were pushed.
image

@jzheaux
Copy link
Contributor

jzheaux commented Sep 27, 2022

@apatelWU, it was fixed in 5.7.3. If you update to the latest 5.7, you should be good.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: crypto An issue in spring-security-crypto status: backported An issue that has been backported to maintenance branches type: bug A general bug
Projects
None yet
Development

No branches or pull requests

3 participants