●BLF-CRYPTでシャドウパスワードを作成
BLF-CRYPTの生成方法は、サーバ管理用スクリプト作成時に海外のどこかのフォーラムだったかブログだったにあったpythonの例を元にしてperlで書き直したものになります。
ただ、そのサイトを失念して思い出せないため参考文献にはありません。すいません。
流れとしてはmakerandom_octet関数で16Byteの乱数を作って、入力された$passwordとそれをCrypt::Eksblowfishモジュールのbcrypt関数に突っ込んでシャドウパスワードを取得する流れになります。
SHA512-CRYPTと異なりsaltやストレッチ(round)回数による差分はありませんが、ストレッチ回数は1桁の場合は07のように0をつけて必ず2桁で指定します。07の場合は2^7乗になります。
BLF-CRYTはsaltもdigestもシャドウパスワードとして出力する際にBase64で符号化します。そのためsaltはバイナリ文字列でも問題ありません。
ただ、このBase64はMIME::Base64ではなくen_base64というCyrpt::Eksblowfishに添付の専用の関数で出します。
この専用の関数(en_base64/de_base64)は符号化の方法がMIME::Base64と異なるらしく、同じ平文を入れても同じ符号になりません。
※CPANのEksblowfishのドキュメントでは「Bcryptを使うのに便利な関数」という謎の説明がされています。)
Table 1に例を示します。password3がそれです。見た感じシーザ暗号みたいに文字が2文字ほどずれているだけな気がしなくもないです。
$password = "y17";
|
libcryptoが対応していれば、Eksblowfishを使わずともcrypt関数だけで作ることもできます。
●環境と用語
前ページをご覧ください。FreeBSD 12.0Rです。
●ソースコード
こちらからどうぞ。
●必要なモジュール
EksblowfishかBase64が必要です。Eksblowfishモジュールを使わず、crypt関数を使うならBase64が必要です。
いずれも、FreeBSDでバイナリパッケージが用意されており、pkgコマンドでインストール可能です。
【凡例】
1段目:Perlモジュールとしての名前
2段目:FreeBSDのpkg名(2019年06月現在)
3段目:コード内での宣言です。
-
p5-Crypt-Random-1.52
Crypt::Random
p5-Crypt-Random-1.52
use Crypt::Random qw(makerandom_octet); - MIME::Base64;
p5-MIME-Base64-3.15
use MIME::Base64 - Crypt::Eksblowfish::Bcrypt
p5-Crypt-Eksblowfish-0.009_3
use Crypt::Eksblowfish::Bcrypt qw(bcrypt_hash en_base64 bcrypt);
※bcrypt_hashは生成用、bcryptは検証用です。
●BLF-CRYPTのシャドウパスワードの生成例(Eksblowfish版)
パスワードを受け付ける部分などは「## Make encrypted password by BLF-CRYPT」より上にありますので、前々ページを参照ください。
digestをEksblowfishのbcrypt関数で取得して、それにスキームとエンコード回数を組み込んで、saltとdigestのそれぞれをen_base64というBase64(もどき)でエンコードするだけです。
en_base64はEksblowfishに組み込まれている関数です。Eksblowfishはこのen_base64関数を使わないとダメっぽいです。MIME:Base64の方のencode_base64ではうまくdoveadmを通りませんでした。
a## Make encrypted password by BLF-CRYPT |
●BLF-CRYPTのシャドウパスワード生成例(crypt関数版)
ぶっちゃけていうとSHA512-CRYPT同様にcrypt関数でもBLF-CRYPTは生成可能です。ただ、Eksblowfishを入れたくないとかであれば特にメリットはありません(デメリットもありません)。
crypt関数は下記のようになっています。
$shadow_password = crypt(<PLAINTEXT>, <SALT>);
「PLAINTEXT」はここでいうと$password (ユーザが入力したパスワード)です。
「SALT」本コンテンツのsaltと異なり、saltとストレッチ(round)回数をまとめたマジックワードで、BLF-CRYPTの場合は「$2a$ストエレッチ回数(2の階乗で指定)$<Base64をエンコードしたsalt>」となっています。前述のようにSHA512-CRYPTと異なりストレッチ回数による差はありません。
ここではSALTとsaltは別物として扱います。
この2つを入れるとシャドウパスワードが返ってきます。これはどうもすでにBase64化されているようです(青文字部分)。
SALTの中のsaltはBase64でエンコード済みである必要があるみたいです。
## Make encrypted password by BLF-CRYPT |
●BLF-CRYPTの検証例(Eksblowfish版)
Eksblowfishのモジュールを使うと検証が楽です。BLF-CRYPTは$2a$0x$<22文字>にストレッチ回数とsaltが全部入ってます。
そのため正規表現でこの$2a$で始まる部分からsalt部分までを引き抜いてSALTとし、EksblowfishモジュールにはこのSALTと入力された$passowrdから再度digestを取得するbcrypt関数というものがあります。
このbcrypt関数を使えば、saltやストレッチ回数を紐解かずとも一撃でシャドウパスワードを取得できます。まぁ、cryptと同じですね。
取得後はスキームつけてdovecot_passwordとstored_passwordと比較するか、stored_passwordからスキーム剥がしてシャドウパスワード同士で比較するかのどちらかです。簡単です。
ストレッチ回数やsaltを紐解いてまたbcrypt_hashで作り直してもいいかもしれませんが、時間の無駄だと思います。ちなみに紐解けるように(それ用かは存じませんが)ちゃんとde_base64という関数が用意されています。
## Get password and extract salt from stored_password |
このスキームに限ったことではありませんが、エラーチェックはしていません。そのため例えばストレッチ回数の上限は、本当は31ですが99とかの文字列でもチェックなく通ってしまいます。
また$stored_passwordは必ず正しいフォーマットのBLF-CRYPTがくると決め打ちて書いています。
●BLF-CRYPTの検証例(crypt版)
crypt版の検証はさっきと1文字しか変わるところがありません。面白くも何ともありません。## Get digestでシャドウパスワードを求める部分がbcryptからcryptに変わっただけです。まぁ上でやってることがcryptと同じですからね。
どちらでやっても構いませんが、生成のところでcrypt関数でパスワード生成できなかったのであればこちらも使えません。
## Get password and extract salt from stored_password |
●あとがき
今回4つのスキームを紹介しました。実際に私がサーバ上で実装したスキームはSHA512、SSHA512とBLF-CRYPTの3つで、事実上BLF-CRYPT以外は使っていません。
本当はArgon2とかも作って紹介したかったのですが、検証環境を用意するのが面倒なので今回はここまでです。
●参考文献
- Dovecot 2.3.6のソースコード
- Metacpan
殊更に参考にしたサイトは失念しました(コード自体は3年前の2016年に作ったので)。