●SHA512/SSHA512でシャドウパスワードを作成する。
このスキームは脆弱ですので新規に導入するには値しないと思ってますが、最初の実証コードを書いてみる場合には一番簡単なスキームですし、ハッシュさえしておけば大丈夫という思想を持っている方も一定数いて、しぶしぶ保守している方もいると思いますので、一応掲載します。
SHA512の方は簡単で、文字列をハッシュ関数に通すだけです。検証はdoveoct_passwordとその通して得たシャドウパスワードをstored_passwordと比較するだけです。
●環境と用語
前ページをご覧ください。FreeBSD 12.0Rです。
●ソースコード
こちらからどうぞ。
●必要なモジュール
いずれも、FreeBSDでバイナリパッケージが用意されており、pkgコマンドでインストール可能です。
【凡例】
1段目:Perlモジュールとしての名前
2段目:FreeBSDのpkg名(2019年06月現在)
3段目:コード内での宣言です。
- Digest::SHA qw(sha512)
p5-Digest-SHA-6.02
use Digest::SHA qw(sha512); - MIME::Base64;
p5-MIME-Base64-3.15
use MIME::Base64;
-
p5-Crypt-Random-1.52
Crypt::Random
p5-Crypt-Random-1.52
use Crypt::Random qw(makerandom_octet);
●SHA512のシャドウパスワードの生成例
SHA512の例を掲載します。
「## Get User password」から「### Make shadow password with SHA512 hash.」までは、コンソールからユーザのパスワード入力を求める部分です。
モジュール関係を除けばここはスキームが変わっても同じですので次回以降は掲載しません。
#!/usr/bin/env perl
|
$sha2 = Digest::SHA->new(512)で、SHA2クラスのインスタンスを作成します。この時に512に変えて256を指定するとSHA256になります。
あとはその生成したクラスに$sha2->add("平文パスワード")でハッシュしたい文字列を入れて、$sha2->digest関数を呼んで$digestを得ます。
この関数で得た$digestはバイナリ文字列になっていますので、Base64でエンコードするとシャドウパスワードになります。doveadmで得られるシャドウパスワードもBase64でエンコードされた状態です。
Base64エンコードを行うencode_base64()関数は勝手に改行を入れるため、その改行文字を指定する第2引数に空白を入れて改行表示を抑制しています。
最後にBase64エンコードをせず、$digestは$sha2->add("$password")->b64digestで取得して、これをそのまま$shadow_password = $digestとする方法もあります。これでも問題なく認証できます。
違いはシャドウパスワード末尾の「==」があるかないだけです。ただ、doveadmでは「==」の文字がないとverifiedになりません。
|
●SHA512の検証例
これは説明不要ですね。できた$dovecot_passwordと$stored_passwordを比較して一致していればパスワード認証成功です。
●SSHA512のシャドウパスワード生成例
SSHA512の例を掲載します。「
## Make SSHA512 Password」より上の部分はSHA512と同じなので省略します。
SSHA512は($password.$salt)のSHA512ダイジェストに、$saltを連結して、Base64でエンコードした構造になっています。$saltは4バイトです。
やり方ですが、まず、makerandom_octet(Length => 4)関数で4バイトの乱数を作ります。
makerandom_octet関数は指定されたLength Byte分の暗号学的に安全(Cryptographically Secure)なランダムなバイナリ文字列を生成する関数らしいです。4文字の乱数が欲しいならこれが一番簡単で安全だと思います。
簡単ですが、この関数は/dev/randomによるランダムプールを使うらしく、短時間に使いすぎるとブロッキングして出てこなくなるらしいので一度に大量生成する時には不向きです。
あとは$passwordと$saltを連結してSHA512のダイジェスト($digest)を取得します。
digestを取得したら$digestと$saltをこの順で連結して、その後その連結したものをBase64でエンコードして、スキームを頭につけて終わりです。
## Make SSHA512 Password |
Perlの文字列連結は.(ピリオド)で連結すると遅いとどこかのサイトで見たことがありますが、ここでは見やすさを考えてピリオドで連結しています。
興味ないと思いますが、コード中512と書いてある部分をすべて256にするとそのままSSHA256を生成できます。
●SSHA512の検証例
SSHA512ではstored_passowrdからsaltを抽出し、そのsaltとユーザが入力したパスワードからもう一度SSHAのシャドウパスワードを生成することで、パスワードが正しいかを検証します。
ですので、コードの流れとしては、stored_passwordをBase64デコードして、末尾の4バイトからsaltを抽出し、そのsaltとユーザが検証用に入れてきたパスワードからSSHA512を再生成します。
その再生成したシャドウパスワード、stored_passwordが一致すればOKです。
コードの$stored_shadow_passwordは$stored_passwordからスキーム文字列である{SSHA512}を外したものです。
$stored_passwordは最後に比較用に使用するのと、Perlは置き換えに自分自身を参照するので、いったん$stored_shadow_passwordに$stored_passwordを代入してコピーします。
$stored_shadow_password_decoded は $stored_shadow_passwordをBase64でデコードしたものです。
saltはデコードされた$stored_shadow_password_decodedの末尾4byteにくっ付いてますので、substrで切り出します。substrは第2引数にマイナスを指定すると右から指定された文字数分の文字を切り出します。
※この方法ならSSHA256でもコードを変えずに対応できます。
あとは上記で得られたsaltと入力されたパスワードでもう一回SSHA512を作って、最初に入力されたstored (dovecot) passwordと比較一致してパスワードが正当なものかを確認します。
サンプルコードは最初にスキーム付きのSSHA512形式の$dovecot_passwordの入力を求め、次にセットしたパスワードを求めてきます。
最初のプロンプトには{SCHME}で始まる文字列を、2番目のプロンプトには設定しているはずのパスワードを入力してください。
最初に入れた文字列のsaltと2番目のパスワードから無事同じパスワードが生成できるとverfifiedと表示します。
#!/usr/bin/env perl |
●次のセクションでやること。
- SHA512-CRYPTのシャドウパスワード作成例
●参考文献
- なし