Example is worth a thousand words, hopefully. In case it doesn't, here're a couple tests to hash the plainText hello world
using a salt seed static seed to be used
in the first test and static seed to be usedd
in the second test.
Salt seed is used to generate a static salt that can be passed into BCrypt.hashpw(plainText, staticSalt)
function. As you can see, the salt bytes, and salt byte strings are similar length but it is throwing an error. I know it's bad but I have my reasons for static salt, so please put your focus on the question.
org.mindrot.jbcrypt.BCrypt with JDK1.7 Test 1 - PlainText: "hello world", saltseed: "static seed to be used":
Salt bytes for "static seed to be used": [-30, -8, 86, -8, 6, -126, -64, -30, -82, -82, -104, -64, -8, -118, -64, 108, -82, -64, 14, -30, -82, -104]
Salt bytes string: 4vhW+AaCwOKurpjA+IrAbK7ADuKumA==, length: 32
complete salt: $2a$12$4vhW+AaCwOKurpjA+IrAbK7ADuKumA==
Exception in thread "main" java.lang.IllegalArgumentException: Bad salt length
at org.mindrot.jbcrypt.BCrypt.crypt_raw(BCrypt.java:619)
at org.mindrot.jbcrypt.BCrypt.hashpw(BCrypt.java:684)
org.springframework.security.crypto.bcrypt.BCrypt with JDK1.8 Test 1 - PlainText: "hello world", saltseed: "static seed to be used":
Salt bytes for "static seed to be used": [-30, -8, 86, -8, 6, -126, -64, -30, -82, -82, -104, -64, -8, -118, -64, 108, -82, -64, 14, -30, -82, -104]
Salt bytes string: 4vhW+AaCwOKurpjA+IrAbK7ADuKumA==, length: 32
complete salt: $2a$12$4vhW+AaCwOKurpjA+IrAbK7ADuKumA==
Plain text: hello world, Hash text: $2a$12$4vhWHrTxEMtyyv6wmpOtX.YYbTqHwHv/dxe
org.mindrot.jbcrypt.BCrypt with JDK1.7 Test 2 - PlainText: "hello world", saltseed: "static seed to be usedd":
Salt bytes for "static seed to be usedd": [85, 108, -73, 108, 111, -27, -32, 85, 19, 19, -4, -32, 108, -7, -32, -50, 19, -32, -125, 85, 19, -4]
Salt bytes string: VWy3bG/l4FUTE/zgbPngzhPgg1UT/A==, length: 32
complete salt: $2a$12$VWy3bG/l4FUTE/zgbPngzhPgg1UT/A==
Plain text: hello world, Hash text: $2a$12$VWy3bG/l4FUTE/zgbPngze9KDSXjF72NBMBNE6ZJk4StahyAhykgO
org.springframework.security.crypto.bcrypt.BCrypt with JDK1.8 Test 2 - PlainText: "hello world", saltseed: "static seed to be usedd":
Salt bytes for "static seed to be usedd": [85, 108, -73, 108, 111, -27, -32, 85, 19, 19, -4, -32, 108, -7, -32, -50, 19, -32, -125, 85, 19, -4]
Salt bytes string: VWy3bG/l4FUTE/zgbPngzhPgg1UT/A==, length: 32
complete salt: $2a$12$VWy3bG/l4FUTE/zgbPngzhPgg1UT/A==
Plain text: hello world, Hash text: $2a$12$VWy3bG/l4FUTE/zgbPngze9KDSXjF72NBMBNE6ZJk4StahyAhykgO
I've tried adding and deleting more letters and got successful hashes. I was kind of happy that the first String used in the JUnit test threw an error.
Thanks in advance.
I found the reason by looking at its implementation on a GitHub page... This implementation of BCrypt supports base64 dot(.) character instead of the standard plus(+) character.
"+" character has integer value of 43, thus returns a -1 from this array, and the function that is retrieving the salt bytes from salt breaks earlier leaving me with a 4 bytes salts. Even its implementation says it doesn't support standard base64 encoding string:
Switching from . to + gives me a different hashed from Spring on salts containing +. Not that familiar with shift and & to make the changes so going to look for the Spring-Security's implementation instead.
EDIT: Just took a look at Spring's implementation. No wonder it didn't work... It is exactly the same except Spring continues to hash with a 4 bytes salt while jbcrypt throws an error, thus there's a bug in Spring whereas if you generate your own hash and it contains +, then the checkpw(plainText, hashedText) will return false because the generated salt part of the hashtedText is different from the user generated salt.