crypt

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 '不一致';
}