Perl関数で暗号化 - DES編
Perlの場合には、暗号のための関数として、crypt関数が用意されています。 この場合、暗号化方式は、サーバーのマシンに依存され、DES方式か又はMD5方式になります。
例えば、Linuxでは当初はDES方式のみをサポートしていましたが、最近ではMD5方式もサポートしているようです。 それに対してFreeBSDの場合は当初からMD5をサポートしていました。

2-1. デモ

今回のcrypt関数(DES方式)のデモです。saltの2文字をアトランダムに付加し、パスワードを暗号化します。
pagetop

2-2. DES方式の暗号化

DES方式下でcrypt関数を使用する場合には、まず2文字のsalt(種)を用意します。 saltとは、ここでは暗号を破られにくくするためのものと理解しておいてください。
関数 備考
crypt(passwd, salt) passwd : 暗号化する文字列。8文字以内
salt : 英数字、ドット、スラッシュのいずれかの文字列で、2文字
たとえば、saltの2文字を「xy」とし、暗号化する文字列を「1234」とします。
use strict;

# パスワード
my $passwd = '1234';

# 種
my $salt = 'xy';

# 暗号化
my $crypt = crypt($passwd, $salt);
print "$crypt\n";
>  xyNuGzVs9aAi.
上記のように、必ず13文字の文字列で出力されますが、先頭の2文字はsaltのため、暗号文字は11文字となります。 パスワードが1文字でも、あるいは8文字でも、出力結果はsaltを含めて13文字となります。
ポイント
暗号文字「xyNuGzVs9aAi.」のうち、saltは先頭の2文字「xy」で、本当の暗号文字は「NuGzVs9aAi.」
また、saltについてですが、このsaltの2文字を変えることで、出力結果が変わります。 言い換えると、saltは出力結果としての文字列を変えるために存在するものです。
以下は、saltの2文字を「ab」とし、暗号化する文字列は前回と同様に「1234」とします。
use strict;

# パスワード
my $passwd = '1234';

# 種
my $salt = 'ab';

# 暗号化
my $crypt = crypt($passwd, $salt);
print "$crypt\n";
>  abWMpd9uBwR.g
このように、saltを変えることで出力される暗号文字列を変え、解読されにくいようにしているのです。
このsaltについてですが、いちいち任意の2文字を指定するのは面倒です。 そこで、次のように、アトランダムな2文字を自動で選んで暗号化してみましょう。
use strict;

# パスワード
my $passwd = '1234';

# 種をアトランダムに生成
my @str = (0 .. 9, 'a' .. 'z', 'A' .. 'Z', '.', '/');
my $salt = $str[int(rand(@str))] . $str[int(rand(@str))];

# 暗号化
my $crypt = crypt($passwd, $salt);
print "$crypt\n";
>  WEd.83H.gealA
上記のコード例の場合、saltがたまたま「WE」の2文字になったようで、それに基づく暗号文字が出力されました。
上記のコードは起動する度に、異なった文字列が出力されるはずです。
このDES環境下におけるcrypt関数の特徴としては、指定できる暗号元の文字列が最大8文字までということです。 それ以上を指定しても、9文字以下は無視されるので注意してください。 (例えば、「123456789」を指定しても、最後の「9」は無視されて「12345678」と解釈されます)
最後に、上記のコードをもう少し使いやすいように、サブルーチン化してみましょう。
use strict;

# パスワード
my $passwd = '1234';

# 暗号化
print &encrypt($passwd);

#-----------------------------------------------------------
#  DES暗号化
#-----------------------------------------------------------
sub encrypt {
	my $passwd = shift;

	# salt生成
	my @str = (0 .. 9, 'a' .. 'z', 'A' .. 'Z', '.', '/');
	my $salt = $str[int(rand(@str))] . $str[int(rand(@str))];

	# 暗号化
	return crypt($passwd, $salt);
}
pagetop

2-3. 暗号文字の照合

暗号化された文字を、元の文字列と照合するのは、どうしたらいいのでしょうか?
DESは不可逆式ですから、一旦暗号化すると元に戻すことができません。 そこで、照合したい文字列のほうを同様に暗号化して、比較することになります。
それから、もう一点注意することは、DESで暗号化された文字列は、先頭の2文字にsaltがセットされていますので、先頭の2文字と後に続く文字列を分割する処理が必要です。
ある特定の文字列から指定する文字列を抜き出すには、substr関数を利用すると良いでしょう。
関数 備考
substr(expr, offset, length) 文字列の一部を取り出す。
expr で与えられる文字列のうち offset 文字から length 文字分を返す。
以下は照合のコード例です。
use strict;

# パスワード
my $passwd = '1234';

# 暗号化された文字列
my $crypt = 'WEd.83H.gealA';

# 暗号化された文字列からsaltすなわち先頭の2文字を取得
my $salt = substr($crypt, 0, 2);

# 判定
if ($crypt eq crypt($passwd, $salt)) {
	print "OK\n";
} else {
	print "NG\n";
}
>  OK
無事に照合ができました。
上記のコードをもっと使いやすいように、サブルーチン化してみましょう。
use strict;

# パスワード(元の文字列)
my $passwd = '1234';

# 暗号文字
my $crypt = 'WEd.83H.gealA';

# 照合
if (&decrypt($crypt, $passwd)) {
	print "OK\n";
} else {
	print "NG\n";
}

#-----------------------------------------------------------
#  DES照合
#-----------------------------------------------------------
sub decrypt {
	my ($crypt, $plain) = @_;

	# salt抽出
	my $salt = substr($crypt, 0, 2);

	# 判定
	return $crypt eq crypt($plain, $salt) ? 1 : 0;
}
pagetop

2-4. saltについて

salt(種)について、解説しておきます。
saltは、パスワードを暗号化する際に付与される文字列ですが、不可逆式のパスワードを作成する場合に使用されます。
不可逆式のパスワードは、既に述べたように、一度暗号化すると元の平文のパスワードに戻せない文字列になります。
しかしながら、考えられるパスワードを暗号化した文字列を予め数多く用意しておき、攻撃する暗号文字と比較してパスワードを破る方法があります。 これをレインボー攻撃と呼びます。
このような攻撃に対して、パスワードにsaltを付加して暗号化することで、推測されにくい文字列にして、防御措置を取ることができます。
pagetop