Perlモジュールで暗号化 - Crypt::RC4編
可逆式の暗号方式で、ストリーム暗号の代表格である「RC4」を紹介しておきます。
RC4は1987年に開発されたストリーム暗号であり、WEP(無線LANの標準仕様)やWinny(ファイル共有ソフト)、SSLやSSH等、広く利用されている暗号化方式です。
特徴として、DESと比較して高速であり、鍵の長さをある程度任意に設定できる点も挙げられています。

10-1. デモ

Crypt::RC4のデモです。文字列をRC4形式に変換します。
暗証キー 秘密鍵 hex形式 Base64形式
pagetop

10-2. Crypt::RC4モジュール

Crypt::RC4モジュールは、PerlでRC4暗号アルゴリズムを利用するためのものです。
モジュールファイルが非常にシンプルにできており、扱いやすいという特性があります。 しかしその反面、hex/Base64出力のための関数などが用意されておらず、RC4モジュールを使った暗号/復号を補完する処理を作りこむ必要があります。
基本構文は次のとおりです。
関数形式
use Crypt::RC4;

$encrypted = RC4( $passphrase, $plaintext );
$decrypt   = RC4( $passphrase, $encrypted );
OO形式
use Crypt::RC4;

$ref = Crypt::RC4->new( $passphrase );
$encrypted = $ref->RC4( $plaintext );
ちなみに、Crypt::RC4は標準モジュールではないため、個別にインストールする必要があります。
ご参考 : 【コラム】Perlモジュールの組み込み
pagetop

10-3. 暗号と復号

暗号化のコードを考える場合、Crypt::RC4モジュールは、バイナリをテキストへ変換するためのhex/Base64変換の関数が用意されていないため、自前で作成する必要があります。
hex形式を扱う場合には、Perlでは、pack/unpack関数を使用します。 構文は次のとおりです。
方式 構文 内容
16進文字列→バイナリ文字列 pack('H2', text) textという16進文字列をバイナリ文字列へ変換して返す
バイナリ文字列→16進文字列 unpack('H2', bin) binというバイナリ文字列を16進文字列へ変換して返す
それから、もう一点注意することがあります。RC4 + hex変換した場合に16進文字列の中に「改行」が混じることがあります。
改行を含む文字列をそのまま保管するのは扱いにくいため、この場合は改行を「n」に置き換えておくことにします(16進数の場合、nは使用しない)。
use strict;

# モジュールを宣言
use Crypt::RC4;

# パスワード
my $passwd = '春はあけぼの';

# 秘密鍵
my $key = '清少納言';

# RC4暗号変換
my $crypt = RC4($key, $passwd);

# hex処理
$crypt =~ s/(.)/unpack('H2', $1)/eg;
$crypt =~ s/\n/n/g;

# 出力
print "$crypt\n";
>  8883f2eb71762aa08868fa6a
次に、復号方法(hex形式)は次のとおりです。
use strict;

# モジュールを宣言
use Crypt::RC4;

# 暗号文字
my $crypt = '8883f2eb71762aa08868fa6a';

# 秘密鍵
my $key = '清少納言';

# 16進をバイナリへ戻す
$crypt =~ s/n/\n/g;
$crypt =~ s/([0-9A-Fa-f]{2})/pack('H2', $1)/eg;

# RC4復号
my $plain = RC4($key, $crypt);
print "$plain\n";
>  春はあけぼの
暗号/復号のためのコード(hex形式)を1つにまとめてみましょう。
use strict;

# モジュールを宣言
use Crypt::RC4;

# パスワード
my $passwd = '春はあけぼの';

# 秘密鍵
my $key = '清少納言';

# RC4暗号
my $crypt = &encrypt($key, $passwd);
print "$crypt\n";

# RC4復号
my $plain = &decrypt($key, $crypt);
print "$plain\n";

#-----------------------------------------------------------
#  RC4暗号
#-----------------------------------------------------------
sub encrypt {
	my ($key, $plain) = @_;

	# RC4暗号変換
	my $crypt = RC4($key, $plain);

	# バイナリを16進へ
	$crypt =~ s/(.)/unpack('H2', $1)/eg;
	$crypt =~ s/\n/n/g;

	# 出力
	return $crypt;
}

#-----------------------------------------------------------
#  RC4復号
#-----------------------------------------------------------
sub decrypt {
	my ($key, $crypt) = @_;

	# バイナリへ戻す
	$crypt =~ s/n/\n/g;
	$crypt =~ s/([0-9A-Fa-f]{2})/pack('H2', $1)/eg;

	# RC4暗号変換
	return RC4($key, $crypt);
}
>  8883f2eb71762aa08868fa6a
>  春はあけぼの
pagetop

10-4. Base64形式の場合

Base64形式でのコードも考えてみます。
Base64に変換するには、標準モジュールであるMIME::Base64モジュールを使用します。
概要
use MIME::Base64;

$encoded = encode_base64('Aladdin:open sesame');
$decoded = decode_base64($encoded);
今回MIME::Base64モジュールの使い方で注意するところは、 encode_base64()関数のところで、デフォルトでは「改行」を含んだ複数の文字列に分割した値を返すため、オプションで改行を含まない1行の文字列を返すように指定します。
その場合、2番目の引数として以下のように空白の文字列を渡します。
encode_base64($str, '')
このことを意識しながら、Base64出力での暗号化のコード例を記述してみます。
hex形式よりコンパクトに書けました。
use strict;

# モジュールを宣言
use Crypt::RC4;
use MIME::Base64;

# パスワード
my $passwd = '明日デート決行';

# 秘密鍵
my $key = '極秘';

# RC4暗号
my $crypt = encode_base64(RC4($key, $passwd), '');
print "$crypt\n";

# RC4復号
print RC4($key, decode_base64($crypt)), "\n";
>  hLOjHFIba2e2xwiJhHE=
>  明日デート決行
pagetop