Trying to make bcrypt hashes with crypto


#1

Hello everyone. I’m trying to generate a bcrypt hash using the rust-crypto crate. I took a look at this post, which helped me along but my hash doesn’t look correct. I want to generate a hash that looks like this: $2y$10$QPLlURPYklGo.KZfZLDUne/zro3Am7KGKKoRprBCd4FmYZLzaZwsy

I’ve found two functions in the crate for bcrypt: bcrypt_pbkdf and bcrypt.

bcrypt-pbkdf returns a string 64 characters in length, but without the $ information, like this: 4137ff05dc28382925690e6fd53b8ea112da02d8f79b787e48adbe77b1ce5b30

bcrypt returns a string 48 characters in length, also without the $ information, like this: 4137ff05dc28382925690e6fd53b8ea112da02d8f79b787e

Which of these functions should I use? What is the difference between them? Should I simply prepend a string $2y$10$ or should this be generated from the salt? Should I be using the crypto crate instead of rust-crypto? Thanks for your help!

Here is the current state of my code:

extern crate crypto;
use crypto::bcrypt_pbkdf::{bcrypt_pbkdf};

fn main() {
    let mut out = [0u8; 32];
    bcrypt_pbkdf(b"password", b"salt", 5, &mut out);
    let mut password_hash = String::with_capacity(out.len() * 2);
    for c in out.iter() {
        password_hash.push_str(&format!("{:02x}", c));
    }
    println!("Hash: {}", password_hash);
    println!("Length: {}", password_hash.len());
}

#2

Your first problem is encoding, you are outputting the HEX value of the hash, while the value you want looks Base64 encoded.

I’m not sure what the 2y values are and even after reading wikipedia I’m still not sure, but they seem to be attached after the Base64 encoding, since $ is not a valid Base64 value.

I’m also not sure about the period, since that isn’t a valid Base64 character either.

It appears bcrypt is encoding the text and bcrypt_pbkdf is generating a hash, so that sounds like what you want. Then you will have to Base64 encode the salt and Base64 encode the result, combine those together then figure out where the dollar sign parameters come from.


#3

Actually reading a little bit more it appears you need to prepend the 2y to indicate that the string is a hash key, then add “5$” which is the “cost”, I’m guessing that is the 5 you are passing in for the rounds.

Still not sure about the period through :confused:.


#4

There are several things you should be aware of when using bcrypt. First, rust-crypto implements only the latest, bug-fixed version of the algorithm, denoted by $2y$ in the hash strings which use it. Second, Base64 encoding and decoding use a modified character set, which contains the dot. Third, the cleartext must be NUL-terminated before hashing or the produced hash will be incorrect.

I have a gist with a password-checking program which produces correct hashes. It doesn’t encode the resulting hash, but I’m sure you can use the code as a starting point.


#5

@rgdmarshall Thanks for the link to the gist. I’m getting closer with the suggestions from @pixel and this will definitely help out. Thanks!


#6

It looks like you’re trying to duplicate crypt(3)?

The ‘notes’ section of the manpage describes it. The $ is also described on wikipedia’s passwd page, search within the page for “salt and hashed password” and it’s described there.

It’s possible that other authentication storage besides the PAM backend uses this format, but it might be worth having a look at the library that implemented it: http://www.openwall.com/crypt/