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.

ziky90
  • 2,627
  • 4
  • 33
  • 47

10 Answers10

17

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.

Jonik
  • 80,077
  • 70
  • 264
  • 372
flurdy
  • 3,782
  • 29
  • 31
  • 8
    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. – daphshez Mar 27 '17 at 16:49
16

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.

BaCaRoZzo
  • 7,502
  • 6
  • 51
  • 82
ziky90
  • 2,627
  • 4
  • 33
  • 47
  • 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. – WISERDIVISOR Mar 01 '21 at 12:57
5

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
  }
sentenza
  • 1,608
  • 3
  • 29
  • 51
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.

Ben
  • 6,107
  • 6
  • 29
  • 40
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)
Ouissal
  • 1,519
  • 2
  • 18
  • 36
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

Black
  • 5,023
  • 6
  • 63
  • 92
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);
Nafaz M N M
  • 1,558
  • 2
  • 27
  • 41
  • i found that User.withDefaultPasswordEncoder is marked as deprecated and it exactly ouputs (as debugger shows) :{bcrypt}$2a$10$dXJ3SW6G7P50lGmMkkmwe.20cQQubK3.HZWzG3YB1tlRy.fqvM/BG – Sasha Bond Feb 27 '21 at 18:19
  • 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' – Nafaz M N M Feb 28 '21 at 10:03
0

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

BCrypt.checkpw("123", "$2a$10$lVPvO6zyyxEWEPlKBg5B3OTjUHGS4LZ2jlulWAUpOjGz3.helz9H2");
Syscall
  • 19,327
  • 10
  • 37
  • 52
ANJANA
  • 27
  • 1
  • 8
  • 6
    Welcome to StackOverflow. Please concern about posting your answer in the correct format. Refer to this: [how to answer](https://stackoverflow.com/help/how-to-answer) – Pawara Siriwardhane Mar 22 '21 at 06:13
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.

Zukaru
  • 320
  • 2
  • 11
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.

damisparks
  • 93
  • 1
  • 10