funcool / buddy-hashers

Collection of password hashers.
https://funcool.github.io/buddy-hashers/latest/
Apache License 2.0
75 stars 16 forks source link

[Question] Restoring salt as string from encrypted password #5

Closed timgluz closed 8 years ago

timgluz commented 8 years ago

Hi,

i'm currently trying to make my Rails APP to use same authorization passwords as my Clojure apis are already using.

In ruby, it's possible to use bcrypt-library, but it needs salt as plain string otherwise it keeps generating different password each time and makes checking impossible.

I thought maybe i can turn Buddy HEX-coded salt into plain string again and feed it into BCrypt::Engine.hash_secret, but i cant find out why encoding doesnt work.

I tried it similar solution on Clojure REPL and result was same gibberish.

For example, i've this hash in my DB: "bcrypt+sha512$67cc133815dc703a498b7ded$12$...somepassword"

I extracted salt: 67cc133815dc703a498b7ded and runned this on REPL: (bytes->str (hex->bytes "67cc133815dc703a498b7ded")) And it returned something like this here "g�8�p:I�}�" .

Is there a way to turn this hex presentation into plain UTF8 string again?

niwinz commented 8 years ago

Hi @timgluz. Sorry for my late response! I was on my holidays...

For do it, you should see the concrete hasher implementation. In case of bcrypt, buddy-hashers does not use plain bcrypt as is. Instead of it, it combines the bcrypt with sha512 (bcrypt has a limitation of max 72 chars password and for awoid it, the password is firstly hashed).

The salt parameter and salt part of the human readable output is not the salt of the bcrypt. Let see how it is implemented:

(defmethod derive-password :bcrypt+sha512
  [{:keys [algorithm password salt iterations] :as pwdparams}]
  (let [salt (->byte-array (or salt (nonce/random-bytes 12)))
        iterations (or iterations (get *default-iterations* algorithm))
        iv (BCrypt/gensalt iterations)
        pwd (-> password
                (bytes/concat salt)
                (hash/sha512)
                (bytes->hex)
                (BCrypt/hashpw iv)
                (str->bytes))]
    {:algorithm algorithm
     :iterations iterations
     :salt salt
     :password pwd}))
  1. The user salt is taken or randomly one is generated
  2. Choice the number of iterations.
  3. Generated random iv (bcrypt salt)
  4. Generated a raw bcrypt hash from user input password concatenated to the salt(1), generating the sha512 hash and later encode it with bcrypt hashpw function.
  5. (out of that function) the return value is formatted in uniform way to human readable output.

If you want to access and verify the password generated by buddy-hashers you should implement something like this in ruby.

timgluz commented 8 years ago

Thanks,

i decided not to replicate same logic in ruby - late night hacking is dangerous.

At the morning i got much better idea and i just wrote a new strategy for devise auth-framework.