passwd スタイルの一方向のハッシュ化
crypt
は名前から想像するような暗号化関数ではなく、ダイジェストを生成するハッシュ関数です。
Linux などの passwd
コマンドで生成されるパスワードのハッシュと同じです。
crypt
には、ダイジェストのもととなるテキストデータ PLAINTEXT と、
SALT と呼ばれる短いデータを引数に与えます。
SALT は 一般的には [./0-9A-Za-z]
からランダムな 2 文字で構成されます。
print crypt 'password', 'AB'; # ABRCL9ijBr2LY
生成されるダイジェストは [./0-9A-Za-z]
から 13 文字で構成されます。
最初の 2 文字は SALT そのものです。それに続く 11 文字が PLAINTEXT に相当する部分です。
crypt
は、同じ PLAINTEXT と SALT を与えると、常に同じダイジェストを返します。
しかし、これら 2 つのうち少しでも変化すると、生成されるダイジェストは大きく変化します。
これが crypt
によって生成されるダイジェストの大きな特徴です。
もう一つの特徴として、crypt
は一方向のダイジェストを生成する点です。
一般的に暗号化といえば復号化できるわけですが、crypt
で生成されたダイジェストから
元の PLAINTEXT に復元することはできません。
以上の特徴から、パスワードの保管方法として良く使われます。 Apache の Basic 認証で使われるユーザーのパスワードも、同じようなダイジェストで保管されています。 ダイジェストから元のパスワードを復元できないわけですから、 仮にパスワードから生成されたダイジェストが漏洩しても、被害を小さくできると期待されます。 ただし、有効なパスワード文字数は 8 文字までです。 それ以降の文字は無視されますので注意してください。
実際に crypt
でダイジェストを生成して、それを使ってパスワード照合を行ってみましょう。
以下のサンプルコードは、パスワード情報のダイジェストを生成します。SALT はランダムに生成します。
# ダイジェストを生成する元のテキストデータ
my $pass = 'password';
# SALT を新規に生成
my @chars = ( '.', '/', 0 .. 9, 'A' .. 'Z', 'a' .. 'z' );
my $salt = $chars[ rand 64 ] . $chars[ rand 64 ];
# ダイジェストを生成
my $digest = crypt $pass, $salt;
ここで生成されたダイジェストを使って、パスワードの照合を行ってみます。
# 入力されたパスワード
my $input = 'password';
# オリジナルのダイジェストの先頭 2 文字から SALT を取得
my $salt_orig = substr( $digest, 0, 2 );
# 入力されたパスワードと SALT からダイジェストを生成
my $digest2 = crypt $input, $salt_orig;
# オリジナルのダイジェストと新たに生成したダイジェストを比較
if ( $digest eq $digest2 ) {
print '一致';
}
else {
print '不一致';
}