bcrypt #
パスワードをシステムに保存する際には、生のパスワード文字列をそのまま保存するのではなく、ハッシュにした文字列で保存するようにします。
bcryptはパスワードに使うことができるハッシュです。
bcryptの結果は次のような文字列となります。
$2b$rounds$salt checksum
最初の$2bはバージョンを表します。$2aか$2bとなります。
次の$roundは10進数2文字の数字で、ラウンド回数(繰り返し計算回数)を表しています。
その次の$マークのあとに、salt 22文字、checksum 31文字と続きます。
合計で、3 + 3 + 1 + 22 + 31 = 60文字となります。
パスワードハッシュの計算 #
ここではGo, Python, Denoでの例を示します。
Go #
golang.org/x/crypto/bcryptを使います。
password_string := "password"
hash, err := bcrypt.GenerateFromPassword([]byte(password_string), bcrypt.DefaultCost)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(len(hash), string(hash))
Python #
passlibを使います。
import passlib
import passlib.hash
p = passlib.hash.bcrypt.hash("password")
print(f"{len(p)=}, {p=}")
Deno #
import * as bcrypt from "https://deno.land/x/bcrypt/mod.ts";
const hash = await bcrypt.hash("passowrd");
console.log(hash.length, hash)
パスワードの確認 #
bcryptは同じパスワードを入力したとしても、毎回異なるハッシュとなります。これは、ハッシュの計算のたびにSaltが違う値になるためです。そのため、パスワードを照合する際には、ハッシュを計算したときと同じSaltを使う必要があります。Saltはハッシュに含まれています。
この例では5種類のbcryptハッシュは異なりますが、すべて"password"というパスワードから生成したものです。
Go #
hash := []string{
"$2a$12$Lt0bQqvq3YwsAnCQr6.oNOaUbKW4AGq1.Gi7k.lQwQnsk6k6jDBSS",
"$2b$12$m3e0.QF7FCHGUjsePXGUCeWcXGZZP.SBqabv34..SzpDnw31btRdS",
"$2b$12$5iEjjV6MGrqOOUqC3L5gd.yacxx1/jDo73gfrq1VejeyyHnaPRU9q",
"$2a$10$Kzbor1QTV5cLwCpXIUhkzem5W/yE5ONAY3fA0tPFShrvzZ9KFKD0K",
"$2a$10$yNc9FGRhno2h8o8la0YYmeE46M4aEx3G6tLLdGl/xrX8cSvtaKTNa",
}
for _, h := range hash {
error := bcrypt.CompareHashAndPassword([]byte(h), []byte("password"))
fmt.Println(error)
}
Python #
hash = [
'$2a$12$Lt0bQqvq3YwsAnCQr6.oNOaUbKW4AGq1.Gi7k.lQwQnsk6k6jDBSS',
'$2b$12$m3e0.QF7FCHGUjsePXGUCeWcXGZZP.SBqabv34..SzpDnw31btRdS',
'$2b$12$5iEjjV6MGrqOOUqC3L5gd.yacxx1/jDo73gfrq1VejeyyHnaPRU9q',
'$2a$10$Kzbor1QTV5cLwCpXIUhkzem5W/yE5ONAY3fA0tPFShrvzZ9KFKD0K',
'$2a$10$yNc9FGRhno2h8o8la0YYmeE46M4aEx3G6tLLdGl/xrX8cSvtaKTNa',
]
for h in hash:
print(f'{passlib.hash.bcrypt.verify("password", h)=}')
Deno #
import * as bcrypt from "https://deno.land/x/bcrypt/mod.ts";
const hash = [
"$2a$12$Lt0bQqvq3YwsAnCQr6.oNOaUbKW4AGq1.Gi7k.lQwQnsk6k6jDBSS",
"$2b$12$m3e0.QF7FCHGUjsePXGUCeWcXGZZP.SBqabv34..SzpDnw31btRdS",
"$2b$12$5iEjjV6MGrqOOUqC3L5gd.yacxx1/jDo73gfrq1VejeyyHnaPRU9q",
"$2a$10$Kzbor1QTV5cLwCpXIUhkzem5W/yE5ONAY3fA0tPFShrvzZ9KFKD0K",
"$2a$10$yNc9FGRhno2h8o8la0YYmeE46M4aEx3G6tLLdGl/xrX8cSvtaKTNa",
];
for (const h of hash) {
const result = await bcrypt.compare("password", h);
console.log(result)
}