Perl関数で暗号化 - DES/MD5共通編
前々章と前章で、DES環境とMD5環境でのcrypt関数についてそれぞれ解説しました。
DESかMD5かということであれば、Webサーバには、大きく分けて次の4種類があるようです。
DESかMD5かということであれば、Webサーバには、大きく分けて次の4種類があるようです。
(1) DESのみ使用可
(2) MD5のみ使用可
(3) DES/MD5両方使用可
(4) DES/MD5両方使用不可
(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文字まで使用したいところです。
DESの場合、3文字以上のsaltを指定しても、先頭の2文字だけが有効で3文字以降は無視されます。
MD5の場合は8文字以内ですが、saltは多い方が強度が増すので、できれば最大の8文字まで使用したいところです。
そこで、saltは8文字を指定することにします。DESのみの環境でも3文字目以降は無視されるだけでエラーにはならないはずです。
次に、crypt関数の実行方法の仕方です。DES方式とMD5方式では、saltの指定方法が異なってきます。
DES/MD5共通環境においては、強度面を考慮してMD5方式にしたいところです。
DES/MD5共通環境においては、強度面を考慮してMD5方式にしたいところです。
そこで、最初にMD5方式でcrypt関数を実行して、それでだめだったら、DES方式で実行する、という方法にすることにします。
01 | use strict; |
02 |
03 | # パスワード |
04 | my $passwd = 'secret' ; |
05 |
06 | # 暗号化 |
07 | print &encrypt( $passwd ), "\n" ; |
08 |
09 | #----------------------------------------------------------- |
10 | # crypt暗号 |
11 | #----------------------------------------------------------- |
12 | sub encrypt { |
13 | my $plain = shift ; |
14 |
15 | # saltは8文字作成 |
16 | my @wd = (0 .. 9, 'a' .. 'z' , 'A' .. 'Z' , '.' , '/' ); |
17 | my $salt ; |
18 | for (1 .. 8) { |
19 | $salt .= $wd [ int ( rand ( @wd ))]; |
20 | } |
21 |
22 | # 最初にMD5方式で実行し、それでだめだったらDES方式で実行 |
23 | return crypt ( $plain , '$1$' . $salt . '$' ) or crypt ( $plain , $salt ); |
24 | } |
これで大抵はいいと思うところですが、中には「へそ曲がり」のサーバ環境がありました。
実は、筆者のテスト環境は「Windows7 + Apache2」なのですが、この環境は「DESのみ使用可」です。この環境において、上記のコードを実行すると、MD5方式のcrypt関数をそのまま実行してしまい、先頭の「$1」をsaltと解釈して「$1qmeMiXizJ7A」というような暗号文字を吐き出しました。
まあ、このままでも照合まで正常に処理できるので、悪くはないのですが、saltが「$1」固定となるため、saltの意味を成しません。
実は、筆者のテスト環境は「Windows7 + Apache2」なのですが、この環境は「DESのみ使用可」です。この環境において、上記のコードを実行すると、MD5方式のcrypt関数をそのまま実行してしまい、先頭の「$1」をsaltと解釈して「$1qmeMiXizJ7A」というような暗号文字を吐き出しました。
まあ、このままでも照合まで正常に処理できるので、悪くはないのですが、saltが「$1」固定となるため、saltの意味を成しません。
そこで、最初のMD5方式のcrypt関数実行の返り値がMD5方式の暗号文字であるかを精査し、OKだったらそのまま採用、NGだったらDES方式のcrypt関数を実行する、ということにしましょう。
以下が(今のところの)完成形です。
01 | use strict; |
02 |
03 | # パスワード |
04 | my $passwd = 'secret' ; |
05 |
06 | # 暗号化 |
07 | print &encrypt( $passwd ), "\n" ; |
08 |
09 | #----------------------------------------------------------- |
10 | # crypt暗号 |
11 | #----------------------------------------------------------- |
12 | sub encrypt { |
13 | my $plain = shift ; |
14 |
15 | # saltは8文字作成 |
16 | my @wd = (0 .. 9, 'a' .. 'z' , 'A' .. 'Z' , '.' , '/' ); |
17 | my $salt ; |
18 | for (1 .. 8) { |
19 | $salt .= $wd [ int ( rand ( @wd ))]; |
20 | } |
21 |
22 | # 最初にMD5方式で実行し、MD5式暗号なら返す。NGだったらDES方式で実行して返す |
23 | return crypt ( $plain , '$1$' . $salt . '$' ) =~ /^(\ $1 \$.+)/ |
24 | ? $1 |
25 | : crypt ( $plain , $salt ); |
26 | } |
上記のコードを「へそ曲がり」環境(DESのみ使用可)で実行したところ、「YwNyzkAW/DVds」というようなDES式の文字列を無事に吐き出しました。
また、DES/MD5両方使用可のサーバで試してみたところ、「$1$IUSph7N4$n/.pTrsRhrb4ZJT7mbEOa1」と正常にMD5式で表示されました。
また、DES/MD5両方使用可のサーバで試してみたところ、「$1$IUSph7N4$n/.pTrsRhrb4ZJT7mbEOa1」と正常にMD5式で表示されました。
4-2. DES/MD5共通の照合処理
照合の仕方については、難しくはないでしょう。暗号文字の先頭にあるsaltの書式から、MD5式なのかDES方式なのかを判別すればいいことになります。
01 | use strict; |
02 |
03 | # パスワード |
04 | my $passwd = 'secret' ; |
05 |
06 | # 暗号化された文字列 |
07 | my $crypt = 'YwNyzkAW/DVds' ; |
08 |
09 | # 判定 |
10 | if (&decrypt( $crypt , $passwd )) { |
11 | print "OK\n" ; |
12 | } else { |
13 | print "NG\n" ; |
14 | } |
15 |
16 | #----------------------------------------------------------- |
17 | # crypt照合 |
18 | #----------------------------------------------------------- |
19 | sub decrypt { |
20 | my ( $crypt , $plain ) = @_ ; |
21 |
22 | # saltの書式を判別する |
23 | my $salt = $crypt =~ /^(\ $1 \$.*\$).+/ ? $1 : substr ( $crypt , 0, 2); |
24 |
25 | # 照合実行 |
26 | return crypt ( $plain , $salt ) eq $crypt ? 1 : 0; |
27 | } |
次章では、Perlモジュールを使った方法について解説しましょう。