Perl関数で暗号化 - MD5編
前章では、DES環境下でのcrypt関数について解説しましたが、本章ではMD5環境下でのcrypt関数について見ていきます。
3-1. デモ
今回のcrypt関数(MD5方式)のデモです。saltの8文字をアトランダムに付加し、パスワードを暗号化します。
3-2. MD5方式の場合
MD5方式下でcrypt関数を使用する場合には、$1$ で始まる8文字($1$ を含めて11文字)以内のsalt(種)を用意します。
関数 | 備考 |
---|---|
crypt(passwd, salt) |
passwd : 暗号化する文字列。8文字以内 salt : 英数字、ドット、スラッシュのいずれかの文字列で、0〜8文字を$1$〜$で囲む。 |
たとえば、saltを「12345678」とし、暗号化する文字列を「abcd」とします。
ちなみに、saltの末尾の「$」に限っては、これを省略しても構いません。
ちなみに、saltの末尾の「$」に限っては、これを省略しても構いません。
use strict; # パスワード my $passwd = 'abcd'; # salt my $salt = '$1$12345678$'; # 暗号化 my $crypt = crypt($passwd, $salt); print "$crypt\n";
> $1$12345678$N/3zBznjFuq/Ila9YecQl.
上記の出力内容で、先頭の「$1$12345678$」までがsaltで、それ以降の「N/3zBznjFuq/Ila9YecQl.」が暗号化文字となります。
DES方式と比べて、文字列も長く、強度が増していることが分かります。
次に、saltの8文字を自動化するコード例は次のとおりです。
use strict; # パスワード my $passwd = 'abcd'; # saltの8文字をアトランダムに生成 my @str = (0 .. 9, 'a' .. 'z', 'A' .. 'Z', '.', '/'); my $salt; for (1 .. 8) { $salt .= $str[int(rand(@str))]; } # 暗号化 my $crypt = crypt($passwd, '$1$' . $salt . '$'); print "$crypt\n";
> $1$IHnmFf/z$9numQmChmSOOO1mz8odh/1
上記のコード例では、任意の8文字「
」がsaltになっていますが、起動するたびに異なったsaltが取得され、それに連動して出力結果(暗号文字)も異なります。
上記の暗号化コードを、さらに使いやすいようにサブルーチン化してみます。
use strict; # パスワード my $passwd = 'abcd'; # 暗号化 print &encrypt($passwd); #----------------------------------------------------------- # MD5暗号化 #----------------------------------------------------------- sub encrypt { my $passwd = shift; # salt生成 my @str = (0 .. 9, 'a' .. 'z', 'A' .. 'Z', '.', '/'); my $salt; for (1 .. 8) { $salt .= $str[int(rand(@str))]; } # 暗号化 return crypt($passwd, '$1$' . $salt); }
3-3. 暗号文字の照合
照合の仕方についてはDES方式と同じで、saltの取得方法が異なるだけです。
前章のときは substr関数で抜き出しましたが、今回はsaltの並び方がやや複雑なので、正規表現で抜き出してみましょう。
前章のときは substr関数で抜き出しましたが、今回はsaltの並び方がやや複雑なので、正規表現で抜き出してみましょう。
use strict; # パスワード(元の文字列) my $passwd = 'abcd'; # 暗号化された文字列 my $crypt = '$1$IHnmFf/z$9numQmChmSOOO1mz8odh/1'; # 暗号化された文字列からsaltを正規表現で取得 my $salt = $crypt =~ /^(\$1\$.*\$)/ && $1; # 判定 if ($crypt eq crypt($passwd, $salt)) { print "OK\n"; } else { print "NG\n"; }
> OK
無事に照合ができました。
最後に、もっと使いやすくするために、サブルーチン化します。
use strict; # パスワード my $passwd = 'abcd'; # 暗号文字 my $crypt = '$1$IHnmFf/z$9numQmChmSOOO1mz8odh/1'; # 照合 if (&decrypt($crypt, $passwd)) { print "OK\n"; } else { print "NG\n"; } #----------------------------------------------------------- # MD5照合 #----------------------------------------------------------- sub decrypt { my ($crypt, $plain) = @_; # salt抽出 my $salt = $crypt =~ /^(\$1\$.*\$)/ && $1; # 判定 return $crypt eq crypt($plain, $salt) ? 1 : 0; }