BvuRVKyUVlViVIc7
BvuRVKyUVlViVIc7

Reputation: 11821

Ruby-BCrypt: Specify salt

Is it possible to specify which salt is used when encrypting strings with ruby-bcrypt?

I know it's not very safe, but I only use it for not-high security data: I have a plattform, and when a user deletes his account, i still want to know if this user was registered with this email before (due to free credits on registration).

So I thought I will encrypt the email with Bcrypt (before deletion) and later I can query afterwards if this hash exists when the user wants to register again with this email address?

But now i realized that bcrypt always procudes a new salt... Can I specify the salt somehow?

Thanks,

DISCLAIMER/ATTENTION:

IN GENERAL YOU SHOULD NEVER SPECIFY SALTS DIRECTLY - ITS INSECURE!!!

Upvotes: 6

Views: 5883

Answers (3)

estani
estani

Reputation: 26547

This is a very old thread but still... here are other options to bcrypt with a fixed salt:

If security is not an issue (mere obfuscation): use md5

Digest::MD5.hexdigest 'some value'

pros: Its computationally inexpensive (faster generation)

cons: its computationally inexpensive (faster hacking)

If security is an issue, you may encrypt it using a shared secret (no hash). See https://ruby-doc.org/stdlib-2.5.1/libdoc/openssl/rdoc/OpenSSL.html#module-OpenSSL-label-Encryption

Upvotes: 1

Neil Slater
Neil Slater

Reputation: 27207

Yes you can:

BCrypt::Engine.hash_secret( '[email protected]', "$2a$10$ThisIsTheSalt22CharsX." )

The first 7 chars are not technically the salt, they identify the bcrypt algorithm, and set the number of iterations to 2**10 == 1024. For simplicity though, Ruby's bcrypt module treats the first characters as part of the salt, so you need to as well. You should probably use

BCrypt::Engine.generate_salt

To create your shared salt, as that doesn't rely on you to come up with something "random".

To improve security a little, you could keep the salt separate from the searchable hashes, and treat it much like any other secret data within the app. For example, make it a config item, and only store the hash part of the bcrypt for searching (the first part is redundant data for you anyhow and will reduce performance of the search, although that effect is probably very small):

email = '[email protected]'
full_hash = BCrypt::Engine.hash_secret( email, settings.email_search_salt )
searchable_hash = full_hash[29,31]
# Either store or search . . .

Upvotes: 11

struthersneil
struthersneil

Reputation: 2750

You could use BCrypt::Password.create, passing it the email, to generate those hashes along with a unique salt.

2.0.0-p195 :003 > hashed_email = BCrypt::Password.create '[email protected]'
 => "$2a$10$vX2tl3omW9h4k66XC7/BwOFH0n7EqtH4PJATPa7YVSeJh7TEpt/bK" 
2.0.0-p195 :004 > hashed_email = BCrypt::Password.create '[email protected]'
 => "$2a$10$RdQIHtz.L5To1F1XRK//..h6nHYdQ3uJ2PTgB58e3xufoqgZGqbO6" 
2.0.0-p195 :005 > hashed_email = BCrypt::Password.create '[email protected]'
 => "$2a$10$bTFVXO/d0/sf6SxzCcRMU.zBPcR5yjI6ID6O9J2eXKbqim/jPM3PC" 
2.0.0-p195 :006 > hashed_email = BCrypt::Password.create '[email protected]'
 => "$2a$10$gbXU4UEiHTC0HCnD672Dm.TeBhZeCa6sBiX8Pk50KSXcprDJnEYA." 

Now you don't have to worry about using a fixed salt as BCrypt has already stored it with the hash for you.

But what I guess you've identified is that it means that there will be a processing cost associated with the comparison later though as you can't just do a 'SELECT user WHERE email_hash = hash'...

If you absolutely want to use a fixed salt, you can.

salt = BCrypt::Engine.generate_salt
hash = BCrypt::Engine.hash_secret 'hello', salt

(Just store that salt string somewhere and you can use it later.)

Upvotes: 8

Related Questions