BCrypt.checkpw() Invalid salt version exception
Asked Answered
A

10

26

I'm trying to implement authentication using BCrypt, in my Play 2.1. Java application, but I'm getting Invalid salt version exception when I'm trying to authenticate the user.

This is my stack trace

play.api.Application$$anon$1: Execution exception[[IllegalArgumentException: Invalid salt version]]
at play.api.Application$class.handleError(Application.scala:289) ~[play_2.10.jar:2.1.0]
at play.api.DefaultApplication.handleError(Application.scala:383) [play_2.10.jar:2.1.0]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anon$2$$anonfun$handle$1.apply(PlayDefaultUpstreamHandler.scala:132) [play_2.10.jar:2.1.0]
at play.core.server.netty.PlayDefaultUpstreamHandler$$anon$2$$anonfun$handle$1.apply(PlayDefaultUpstreamHandler.scala:128) [play_2.10.jar:2.1.0]
at play.api.libs.concurrent.PlayPromise$$anonfun$extend1$1.apply(Promise.scala:113) [play_2.10.jar:2.1.0]
at play.api.libs.concurrent.PlayPromise$$anonfun$extend1$1.apply(Promise.scala:113) [play_2.10.jar:2.1.0]
java.lang.IllegalArgumentException: Invalid salt version
at org.mindrot.jbcrypt.BCrypt.hashpw(BCrypt.java:664) ~[jbcrypt-0.3m.jar:na]
at org.mindrot.jbcrypt.BCrypt.checkpw(BCrypt.java:763) ~[jbcrypt-0.3m.jar:na]
at model.operations.DistrictOperations.authenticate(DistrictOperations.java:24) ~[na:na]
at controllers.Application.authenticateDistrict(Application.java:26) ~[na:na]
at Routes$$anonfun$routes$1$$anonfun$applyOrElse$2$$anonfun$apply$2.apply(routes_routing.scala:133) ~[na:na]
at Routes$$anonfun$routes$1$$anonfun$applyOrElse$2$$anonfun$apply$2.apply(routes_routing.scala:133) ~[na:na]

I'm using following maven repository: http://mvnrepository.com/artifact/org.mindrot/jbcrypt/0.3m

My code is based on the documentation, thus

district.setPassword(BCrypt.hashpw(json.findPath("password").getTextValue(), BCrypt.gensalt()));    

For saving the password (I'm also checking the password for being null)

BCrypt.checkpw(password, d.getPassword());

For checking if the entered password is correct, where password is String and d.getPassword() is hashed password.

I don't know if this is relevant information, but to be precise I'm using hibernate for ORM and PostgreSQL 8.4 as DB.

I'm kind of stuck in here so I'm asking if anyone could help me out. Than you very much in advance.

Anabas answered 10/5, 2013 at 9:0 Comment(0)
A
17

I'm very sorry for bothering with this question. I had just one bug in the code that was saving plain string to the DB instead of the BCrypted one. It was whole called from some other part of code.

Anabas answered 10/5, 2013 at 9:41 Comment(1)
I had a similar problem. I was doing bcrypt.checkpw(hashpass,plainpass) instead of the other way around. Feeling really stupid. I hope this comment makes people double check.Bekha
D
18

For others encountering the same exception, check that you have the BCrypt.checkpw parameters the right way round. (I didn't and therefore found this question before I realised my silly mistake.)

Or as the OP answered himself, log/debug the value of the hashed password to double check you are actually comparing a hashed password! It should be a 60-char string in the format $2a$10$llw0G6IyibUob8h5XRt9xuRczaGdCm/AiV6SSjf5v78XS824EGbh.

Daynadays answered 28/5, 2013 at 21:38 Comment(1)
In particular: the salt JBCrypt expects salt version 2a, so a salt starting with $2a$. If you used another BCrypt version that uses a more modern salt version 2y or 2b - JBCrypt throw an exception.Accomplice
A
17

I'm very sorry for bothering with this question. I had just one bug in the code that was saving plain string to the DB instead of the BCrypted one. It was whole called from some other part of code.

Anabas answered 10/5, 2013 at 9:41 Comment(1)
I had a similar problem. I was doing bcrypt.checkpw(hashpass,plainpass) instead of the other way around. Feeling really stupid. I hope this comment makes people double check.Bekha
S
6

jBcrypt is too old and actually unmaintained. Please consider switching to a new implementation of that library to handle the new $2y$ versions.

I solved this using this pure Java library https://github.com/patrickfav/bcrypt, adding it in my current Scala project.

With the following function I can finally verify the hashes created with VERSION_2Y:

  /**
    * Verifies an encrypted password against the expected value
    *
    * @link https://github.com/patrickfav/bcrypt
    * @param hash The hashed password (encypted with BCrypt version $2Y$)
    * @param password The unencrypted password string
    */
  private def verifyBcryptHash(hash: String, password: String): Boolean = {
    if (hash == null || hash.trim.isEmpty)
      false
    else
      BCrypt
        .verifyer()
        .verifyStrict(
          password.toCharArray(),
          hash.toCharArray(),
          BCrypt.Version.VERSION_2Y
        )
        .verified
  }
Springhouse answered 4/6, 2019 at 17:14 Comment(0)
M
4

I encountered the same problem; Make sure your password is stored in the database in hashed format instead of plain text. Here is a Bcrypt generator to translate your plain text password into a Bcrypt hash.

Maricruzmaridel answered 19/10, 2015 at 8:10 Comment(0)
M
2

You have to make sure that the first argument is the plaintext and the second one is the hashed password. This is the function's declaration :

 public static boolean checkpw(String plaintext, String hashed)
Metaplasm answered 29/5, 2018 at 8:15 Comment(0)
E
1

BCrypt seems to throw this red herring if the 'hash' value you pass in to checkpw(password, hash) isn't even a decipherable value

Empty answered 17/5, 2019 at 6:13 Comment(0)
L
1

in my case, I have used {bcrypt} as a prefix during the insertion into db.

instance

{bcrypt}$2a$12$Yb3YagKV8B3AXoY2p/Ldk.L2maVKfNlr2dedk4ZUs/YUlalS8EzYu

when I retrieve the password the whole value including prefix will be returned. So I have excluded the prefix from the hashing value.

String prefix= "{bcrypt}";

String hash_pw= user.getPassword().substring((prefix.length());

BCrypt.checkpw(loginRequest.getPassword(),hash_pw);
Lordling answered 30/11, 2020 at 7:19 Comment(2)
i found that User.withDefaultPasswordEncoder is marked as deprecated and it exactly ouputs (as debugger shows) :{bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BGOchrea
use PasswordEncoderFactories.createDelegatingPasswordEncoder() for encoding your password and mention encoding type as the prefix. If you don't use the encoding mechanism then mention {noop} as the prefix. PasswordEncoderFactory identifies your hashing type with `prefix'Lordling
B
0

can you split {bcrypt}, and try other details using

BCrypt.checkpw("123", "$2a$10$lVPvO6zyyxEWEPlKBg5B3OTjUHGS4LZ2jlulWAUpOjGz3.helz9H2");
Beldam answered 22/3, 2021 at 5:40 Comment(1)
Welcome to StackOverflow. Please concern about posting your answer in the correct format. Refer to this: how to answerIodism
P
0

In my case, I got this salt revision error because of applying hashed password from https://bcrypt-generator.com into my server's bcrypt checker (spring java security). However, with another same plain password but hashed from https://www.javainuse.com/onlineBcrypt, it worked and verified the password. Log rounds are configured the same (16).

I assumed that my case was because of using a different bcrypt encoder although some might work with a different one.

But, it is guaranteed for sure that hashed password doesn't have this issue if the bcrypt generator and the checker are from the same library.

Pragmaticism answered 12/7, 2021 at 5:55 Comment(0)
D
0

I had this error yesterday while working with bcryptjs. I figured out the error was because the salt defined in my environment variable was passed in as a string, and bcrypt was expecting a number. So I converted it to a number, and the issue was solved.

const hashedPassword = await hash(password, +config.SALT);
// +config.SALT the + sign before the config did the conversion.

I hope this helps someone.

Discophile answered 5/6, 2023 at 10:12 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.