Perlモジュールで暗号化 - Digest::SHA1編
最近では、MD5も次第に研究されてきて、いろいろと弱点も指摘されているようです。 そこで、当然ながら他の暗号方式も考案されてきました。
その1つが、SHA-1(エスエイチエー、Secure Hash Algorithm)です。 MD5方式に比べて、攻撃に強いとされています。
そのSHA-1アルゴリズムへのPerlインターフェースとして、Digest::SHA1モジュールがあります。

7-1. デモ

Digest::SHA1のデモです。文字列をSHA-1形式で変換します。
hex形式 Base64形式
pagetop

7-2. Digest::SHA1モジュール

Digest::SHA-1モジュールも、Digest::MD5と同様に標準モジュールとして採用されています。
データ長は、バイナリ形式では20ビットで、hex形式で40文字、Base64形式で27文字となります。
基本構文は次のとおりです。Digest::MD5とほぼ同じであることが分かります。
関数形式
use Digest::SHA1  qw(sha1 sha1_hex sha1_base64);
 
$digest = sha1($data);
$digest = sha1_hex($data);
$digest = sha1_base64($data);
OO形式
use Digest::SHA1;
 
$ctx = Digest::SHA1->new;
 
$ctx->add($data);
$ctx->addfile(*FILE);
 
$digest = $ctx->digest;
$digest = $ctx->hexdigest;
$digest = $ctx->b64digest;
コード例は次のとおりです。
01use strict;
02 
03# モジュールを宣言
04use Digest::SHA1 qw(sha1_hex);
05 
06# 文字列
07my $str = 'abcd';
08 
09# MD5変換(hex形式)
10my $digest = sha1_hex($str);
11print "$digest\n";
1>  81fe8bfe87576c3ecb22426f8e57847382917acf
hex形式で、上記のとおり40文字で出力されました。
ここで、MD5形式との特徴を確認しておきましょう。一般的に、データ長が長いほど、強度が強いということが言えます。
データ長 hex表記 Base64表記
SHA-1 20ビット 40文字 27文字
MD5 16ビット 32文字 22文字
pagetop

7-3. 暗号として使うには

Digest::SHA-1を暗号ツールとして利用する場合は、第5章の使い方と同じです。
saltをランダムな8文字としたコード例です。
01use strict;
02 
03# モジュールを宣言
04use Digest::SHA1 qw(sha1_hex);
05 
06# 文字列
07my $passwd = '1234';
08 
09# saltの8文字を16進法式でアトランダムに生成
10my @str = ('a' .. 'f', 0 .. 9);
11my $salt;
12for (1 .. 8) {
13    $salt .= $str[int(rand(@str))];
14}
15 
16# SHA1変換(hex形式)
17my $digest = $salt . sha1_hex($salt . $passwd);
18print "$digest\n";
1>  81fe8bfe87576c3ecb22426f8e57847382917acf
次に、照合処理です。
暗号文字の先頭の8文字を抜き出し、SHA-1(hex) 変換して、照合することになります。
01use strict;
02 
03# モジュールを宣言
04use Digest::SHA1 qw(sha1_hex);
05 
06# パスワード
07my $passwd = '1234';
08 
09# 暗号文字
10my $crypt = '81fe8bfe87576c3ecb22426f8e57847382917acf';
11 
12# saltは先頭の8文字を抜き出す
13my $salt = substr($crypt, 0, 8);
14 
15# 判定
16if ($crypt eq ($salt . sha1_hex($salt . $passwd))) {
17    print "OK\n";
18} else {
19    print "NG\n";
20}
上記の暗号/照合コードをサブルーチン化すると、次のようになります(hex形式の場合)。
01use strict;
02 
03# モジュールを宣言
04use Digest::SHA1 qw(sha1_hex);
05 
06# 文字列
07my $passwd = '1234';
08 
09# 暗号
10my $crypt = &encrypt($passwd);
11print "$crypt\n";
12 
13# 照合
14if (&decrypt($crypt, $passwd)) {
15    print "OK\n";
16} else {
17    print "NG\n";
18}
19 
20#-----------------------------------------------------------
21#  Digest::SHA-1 (hex) 暗号化
22#-----------------------------------------------------------
23sub encrypt {
24    my $plain = shift;
25 
26    # saltの8文字を16進でアトランダムに生成
27    my @str = ('a' .. 'f', 0 .. 9);
28    my $salt;
29    for (1 .. 8) {
30        $salt .= $str[int(rand(@str))];
31    }
32 
33    # MD5変換(hex形式)
34    return $salt . sha1_hex($salt . $passwd);
35}
36 
37#-----------------------------------------------------------
38#  Digest::SHA-1 (hex) 照合
39#-----------------------------------------------------------
40sub decrypt {
41    my ($crypt, $plain) = @_;
42 
43    # saltは先頭の8文字を抜き出す
44    my $salt = substr($crypt, 0, 8);
45 
46    # 照合
47    return $crypt eq ($salt . sha1_hex($salt . $plain)) ? 1 : 0;
48}
1>  3e24ac81e6ea852cefd4b7d75496dad4a5ab5bead9669e18
2>  OK
pagetop

7-4. 暗号/照合コード(Base64出力)

Base64形式出力の場合は、次のように記述することができます。
01use strict;
02 
03# モジュールを宣言
04use Digest::SHA1 qw(sha1_base64);
05 
06# 文字列
07my $passwd = '1234';
08 
09# 暗号
10my $crypt = &encrypt($passwd);
11print "$crypt\n";
12 
13# 照合
14if (&decrypt($crypt, $passwd)) {
15    print "OK\n";
16} else {
17    print "NG\n";
18}
19 
20#-----------------------------------------------------------
21#  Digest::SHA-1 (Base64) 暗号化
22#-----------------------------------------------------------
23sub encrypt {
24    my $plain = shift;
25 
26    # saltの8文字をアトランダムに生成
27    my @str = (0 .. 9, 'a' .. 'z', 'A' .. 'Z', '+', '/');
28    my $salt;
29    for (1 .. 8) {
30        $salt .= $str[int(rand(@str))];
31    }
32 
33    # MD5変換(hex形式)
34    return $salt . sha1_base64($salt . $passwd);
35}
36 
37#-----------------------------------------------------------
38#  Digest::SHA-1 (Base64) 照合
39#-----------------------------------------------------------
40sub decrypt {
41    my ($crypt, $plain) = @_;
42 
43    # saltは先頭の8文字を抜き出す
44    my $salt = substr($crypt, 0, 8);
45 
46    # 照合
47    return $crypt eq ($salt . sha1_base64($salt . $plain)) ? 1 : 0;
48}
1>  +SWsMrVFyRMbrKxsIE6QIlJz62X9wzidvzk
2>  OK
pagetop