2020-07-16 23:48:13
Elixir Bcrypt のパスワード認証がどうやって動いているのか全く分からない
全くわからない
おそらく Bcrypt のアルゴリズムだかを調べる必要がありそうです
以下おまけ
Bcrypt.hash_pwd_salt
によって生成されるハッシュ化パスワードは実行するごとに異なる文字列が生成されるのに、Bcrypt.verify_pass
で認証可能な仕組みが全くわからない。
iex(2)
でパスワード認証を行って true
となりますが、iex(9)
でも同様に true
となります。間にBcrypt.hash_pwd_salt("password")
で生成される文字列は毎回異なるにも関わらず。
/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
Bcryptモジュールを見ていくと以下のコードがありますが、この書き方がもう自分には理解できない。
@doc """
Verify the password by comparing it with the stored hash.
"""
def checkpass_nif(password, stored_hash)
def checkpass_nif(_, _), do: :erlang.nif_error(:not_loaded)
1つ目の checkpass_nif
に do:
ないけどいいの?という感じでした。試しに別ファイルで似たコードを書くとruntime errorにもならずに実行できました。
defmodule Sample do
def checkpass_nif(password, stored_hash)
def checkpass_nif(_, _), do: "hello world"
end
実行結果
/home # iex sample.ex
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)> Sample.checkpass_nif("password", "mock_hashed_password")
"hello world"
iex(2)>
おそらく def checkpass_nif(password, stored_hash)
側で認証が行われて、その実態はCプログラムなのかな状態です。depscrypt_elixirc_srccrypt_nif.c
のそれらしき関数の bcrypt_checkpass_nif
に printf
を埋め込んで mix deps.compile
してから、iex -S mix
を実行して、ctrl + c
で中断すると HELLO WORLD
の文字が確認できます。だから何だというのか。
@doc """
Verify the password by comparing it with the stored hash.
"""
def checkpass_nif(password, stored_hash)
def checkpass_nif(_, _), do: :erlang.nif_error(:not_loaded)
static ERL_NIF_TERM bcrypt_checkpass_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
char pass[BCRYPT_MAXPASS];
char goodhash[BCRYPT_HASHSPACE + 1];
char hash[BCRYPT_HASHSPACE + 1];
hash[BCRYPT_HASHSPACE] = '';
// 追加
printf("HELLO WORLD");
/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$WaivpjNwNb.P1LlQfewGsOv5pZlrI7JYJpwBu1UyModP.zPppJhnO"
iex(2)> Bcrypt.verify_pass("password", hpass)
true
iex(3)>
BREAK: (a)bort (A)bort with dump (c)ontinue (p)roc info (i)nfo
(l)oaded (v)ersion (k)ill (D)b-tables (d)istribution
HELLO WORLD
^C/home/nao000dotcom #
全くわからない