I don't know bcrypt very well, but it seems that Twin-Bcrypt expects the salt parameter to include the full type tag ( 2a / 2y / 2x ), the cost parameter and the actual value of the cryptographic salt. (I believe that this was done to meet the expectations of other libraries.) The value of cryptographic salt is only the last 22 characters of the salt parameter string, which are a 128-bit value.
To solve your problem, you need to do two things:
Attach the salt to $2y$10$ so that it has a type tag and a cost parameter.
Match the result of PHP base64_encode with non-standard base64 bcrypt values. For reference:
Standard: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ bcrypt: ./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
If you just want to make standard base64 into brcypt-base64 string, you can replace all + with . but this will lead to a different value (since the standard + is 62 - this is 0 , and all other values ββare also biased). If you want a brypt string with the same value as the original, you need to replace each character with its own bcrypt equivalent.
You may also need to exclude the end = from the standard string, if one exists.
Additional Information: Why should salt end in [.Oeu] ?
The salt in bcrypt is 128 bits. Each base64 character transmits 6 bits of information. This means that 21 base64 characters can transmit 126 bits evenly. The final 2 bits must be encoded in the last 22nd character. Since this character is defined by only two bits, it can have only 4 possible values.
When we examine the base64 character pool for brypt, we see:
./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
Counting from scratch, we will see that these values ββare displayed in signs:
. => 0 = 000000 O => 16 = 010000 e => 32 = 100000 u => 48 = 110000
So, these last two bits set the high order of the final character.
source share