Perl関数で暗号化 - DES/MD5共通編
前々章と前章で、DES環境とMD5環境でのcrypt関数についてそれぞれ解説しました。
DESかMD5かということであれば、Webサーバには、大きく分けて次の4種類があるようです。
(1) DESのみ使用可
(2) MD5のみ使用可
(3) DES/MD5両方使用可
(4) DES/MD5両方使用不可
上記の分類で、(4)のケースは論外なので考慮しないこととして、本章では、(1)から(3)の全てのサーバ環境において使用できる共通式のコードを考えてみたいと思います。

4-1. DES/MD5共通の暗号化

saltについては、DESが2文字固定で、MD5が0〜8文字です。
DESの場合、3文字以上のsaltを指定しても、先頭の2文字だけが有効で3文字以降は無視されます。
MD5の場合は8文字以内ですが、saltは多い方が強度が増すので、できれば最大の8文字まで使用したいところです。
そこで、saltは8文字を指定することにします。DESのみの環境でも3文字目以降は無視されるだけでエラーにはならないはずです。
次に、crypt関数の実行方法の仕方です。DES方式とMD5方式では、saltの指定方法が異なってきます。
DES/MD5共通環境においては、強度面を考慮してMD5方式にしたいところです。
そこで、最初にMD5方式でcrypt関数を実行して、それでだめだったら、DES方式で実行する、という方法にすることにします。
use strict;

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

# 暗号化
print &encrypt($passwd), "\n";

#-----------------------------------------------------------
#  crypt暗号
#-----------------------------------------------------------
sub encrypt {
	my $plain = shift;

	# saltは8文字作成
	my @wd = (0 .. 9, 'a' .. 'z', 'A' .. 'Z', '.', '/');
	my $salt;
	for (1 .. 8) {
		$salt .= $wd[int(rand(@wd))];
	}

	# 最初にMD5方式で実行し、それでだめだったらDES方式で実行
	return crypt($plain, '$1$' . $salt . '$') or crypt($plain, $salt);
}
これで大抵はいいと思うところですが、中には「へそ曲がり」のサーバ環境がありました。
実は、筆者のテスト環境は「Windows7 + Apache2」なのですが、この環境は「DESのみ使用可」です。この環境において、上記のコードを実行すると、MD5方式のcrypt関数をそのまま実行してしまい、先頭の「$1」をsaltと解釈して「$1qmeMiXizJ7A」というような暗号文字を吐き出しました。
まあ、このままでも照合まで正常に処理できるので、悪くはないのですが、saltが「$1」固定となるため、saltの意味を成しません。
そこで、最初のMD5方式のcrypt関数実行の返り値がMD5方式の暗号文字であるかを精査し、OKだったらそのまま採用、NGだったらDES方式のcrypt関数を実行する、ということにしましょう。
以下が(今のところの)完成形です。
use strict;

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

# 暗号化
print &encrypt($passwd), "\n";

#-----------------------------------------------------------
#  crypt暗号
#-----------------------------------------------------------
sub encrypt {
	my $plain = shift;

	# saltは8文字作成
	my @wd = (0 .. 9, 'a' .. 'z', 'A' .. 'Z', '.', '/');
	my $salt;
	for (1 .. 8) {
		$salt .= $wd[int(rand(@wd))];
	}

	# 最初にMD5方式で実行し、MD5式暗号なら返す。NGだったらDES方式で実行して返す
	return crypt($plain, '$1$' . $salt . '$') =~ /^(\$1\$.+)/
		? $1
		: crypt($plain, $salt);
}
上記のコードを「へそ曲がり」環境(DESのみ使用可)で実行したところ、「YwNyzkAW/DVds」というようなDES式の文字列を無事に吐き出しました。
また、DES/MD5両方使用可のサーバで試してみたところ、「$1$IUSph7N4$n/.pTrsRhrb4ZJT7mbEOa1」と正常にMD5式で表示されました。
pagetop

4-2. DES/MD5共通の照合処理

照合の仕方については、難しくはないでしょう。暗号文字の先頭にあるsaltの書式から、MD5式なのかDES方式なのかを判別すればいいことになります。
use strict;

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

# 暗号化された文字列
my $crypt = 'YwNyzkAW/DVds';

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

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

	# saltの書式を判別する
	my $salt = $crypt =~ /^(\$1\$.*\$).+/ ? $1 : substr($crypt, 0, 2);

	# 照合実行
	return crypt($plain, $salt) eq $crypt ? 1 : 0;
}
次章では、Perlモジュールを使った方法について解説しましょう。
pagetop