Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jBCrypt serious issue with checkpw (return true when it shouldn't?)

EDIT: Ok so I've somewhat found an answer here BCrypt says long, similar passwords are equivalent - problem with me, the gem, or the field of cryptography?

New question though, how can someone recommend using bCrypt for hashing if you have to limit the user's password length in a world where we are trying to educate the users to pick increasingly complex passwords, even passphrase, saying your password must be shorter than n characters seems like a way to end up in thedailywtf.com Friday's screenshots :)

Original question below:

I'm refactoring an old login page for an application and decided to give bCrypt a whirl using the JAVA implementation jBCrypt (http://www.mindrot.org/projects/jBCrypt/) and ran into one major show stopper.

Problem is with the checkpw method which always seem to return true when using a very long seed. I was going to salt the password of the user with {InternalSalt}{username}{password} and then hash that with bCrypt.

So I have the following code (stripped it down as much as possible to isolate checkpw).

public class Test {
public static void main(String[] args) {
    String plaintext = "jw~ct/f61y1m7q458GiLVQpiqDK|8kG=d368Id:D@$^_80I{qrn1HM6423{FtestAccountO1nu3jKN";

    String pw_hash = BCrypt.hashpw(plaintext, BCrypt.gensalt());

    if (BCrypt.checkpw("jw~ct/f61y1m7q458GiLVQpiqDK|8kG=d368Id:D@$^_80I{qrn1HM6423{FtestAccountO1nu3jKN", pw_hash))
        System.out.println("It matches");
    else
        System.out.println("It does not match");

}

}

This will, as it should, print "It matches".

Problem I am having is that say you add say aaa to the password you pass to checkpw making it

BCrypt.checkpw("jw~ct/f61y1m7q458GiLVQpiqDK|8kG=d368Id:D@$^_80I{qrn1HM6423{FtestAccountO1nu3jKNaaa", pw_hash)

It still return true! Not exactly what I was expecting. I don't see any password length limitation in the doc but I can't reproduce it with smaller password seed, also it looks like if I modify anything else than the end of the string it works as expected returning false.

Did I miss something major? I know I must not be the only one using jBcrypt on these forum as I have seen BCrypt recommended in many post while doing some research.

EDIT: Windows 7 64 bits - Java(TM) SE Runtime Environment (build 1.6.0_24-b07)

like image 418
jfrobishow Avatar asked May 30 '11 18:05

jfrobishow


2 Answers

Ok, so wording the question gave me enough to actually figure out what I was looking for (hurray for rubber ducking). The field of cryptography is safe for now!

BCrypt implementation XOR using P_orig which is 18 4 bytes integer until it gets to the end, which limits your encryption "key" to 72 bytes. Eveyrything after 72 bytes is ignored (a warning would have been nice).

What appears to be the accepted compromise is not to limit the user's password to 72 characters or less but simply let it pass silently. The idea behind this being that a 72 characters bCrypted password is better than the fast hashing alternative anyway.

Source: BCrypt says long, similar passwords are equivalent - problem with me, the gem, or the field of cryptography?

like image 162
jfrobishow Avatar answered Sep 30 '22 18:09

jfrobishow


Actually your own answer is great and helped me to find annoying issue ;) there is some tip for people who adds some kind of app's secret to plain before hashing (even if they limits the password length): include the app secret at the end especially if app's secret is 72 chars long - otherwise every hit will return true!

so instead:

String hashed = BCrypt.hashpw(APP_SECRET + plain, BCrypt.gensalt())

use:

String hashed = BCrypt.hashpw(plain + APP_SECRET, BCrypt.gensalt())

Even if Bcrypt's cropping will occur the checkpw result will be valid!

like image 30
biesior Avatar answered Sep 30 '22 16:09

biesior