Nao000のぶろぐ

蝶を追っている少年になりたい

Elixir Bcrypt のパスワード認証の仕組みをちょっと理解しました

エンジニア用語の「ちょっと」ではありません。少量という意味の「ちょっと」です。

ハッシュ化パスワードのフォーマット

以前の記事で生成されるハッシュ化パスワードが毎回異なるというのを記載しました。

    /home/nao000dotcom # iex -S mix
    Erlang/OTP 22 [erts-10.7.1] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:1]

    Interactive Elixir (1.9.4) - press Ctrl+C to exit (type h() ENTER for help)
    iex(1)> hpass = Bcrypt.hash_pwd_salt("password")
    "$2b$12$XLmj0DluwBk4JEpcIAc4HeJTP.NM3fmAscPHaDJhd2zHAYEv//F/G"
    iex(2)> Bcrypt.verify_pass("password", hpass)
    true
    iex(3)> hpass = Bcrypt.hash_pwd_salt("password")
    "$2b$12$6ibm1qg0yIR.3WvyQ08E6uT0xGPNUntipPH/vbiTgJqXmluh6VTi2"
    iex(4)> hpass = Bcrypt.hash_pwd_salt("password")
    "$2b$12$8iViLepEinSIsnmvo6W3ne0QbjIrhUupzi0kDf7LEpOae7.Ri1foe"
    iex(5)> hpass = Bcrypt.hash_pwd_salt("password")
    "$2b$12$uFt22FVkZuyOKcVeSLVT6Oh166Ib6jrZY7r97wbXCSOn8rHqOInwy"
    iex(6)> hpass = Bcrypt.hash_pwd_salt("password")
    "$2b$12$vF/JUeqBxNAf0N/ckBLLueU.GX84HX80DY3Kk0xnjfyq.zJi67nxu"
    iex(7)> hpass = Bcrypt.hash_pwd_salt("password")
    "$2b$12$YjMXcb62vtzqaFEfh1rfe.kg3LeBK7IUl.9acaUZONRYBb.33vbia"
    iex(8)> hpass = Bcrypt.hash_pwd_salt("password")
    "$2b$12$vTzhVBm9NDfnfDQxiDob2O8hirOUHN986C823nY9HkY49d1YzXWw2"
    iex(9)> Bcrypt.verify_pass("password", hpass)
    true

1つのハッシュ化パスワード "$2b$12$6ibm1qg0yIR.3WvyQ08E6uT0xGPNUntipPH/vbiTgJqXmluh6VTi2" をピックアップして見ます。先頭にある $2b$ は使用するBcryptのバージョンを示すそうです。続く $12$ はコストパラメータと言って複雑度を制御する部分だそうです。続く22文字の 6ibm1qg0yIR.3WvyQ08E6u はソルトだそうです。残りの31文字の T0xGPNUntipPH/vbiTgJqXmluh6VTi2 がハッシュ値だそうです。

毎回異なるハッシュ化パスワードが生成されたとしても、認証時にバージョンとコストパラメータ、ソルトの3つが分かっていれば入力されたパスワードを再度同じ条件でハッシュ化することも可能だと思いますので納得です。具体的なハッシュ化文字列生成のアルゴリズムは追っていませんがとりあえず納得です。

参考資料