Perlでブロック暗号を利用する (BlowfishとCBCモード)

任意長のデータ列に対してブロック暗号を適用するためには,ECB (Electric Code Block; c[i] = E(m[i])) やCBC (Cipher Block Chaining; c[i] = E(m[i] \xor c[i-1]))といったモードを使う必要がある. この記事では,Perl から 8bitブロック暗号 Blowfish をモード CBC で利用する方法を説明する.


CBCモード暗号器の作成

Perl で CBC モードでの暗号化を実現するには,CPAN モジュールの Crypt::CBC を使うと簡単だ. まず,以下のように暗号器を作成する.

use Crypt::CBC;
my $cipher = Crypt::CBC->new(
                 -key     => 'my secret key',
                 -cipher  => 'Crypt::Blowfish',
             );

コンストラクタのオプションの意味は以下のとおり.

  • -keyパスフレーズを指定する.暗号アルゴリズムの鍵として使用される.
  • -cipherは暗号アルゴリズムを指定し,現在 Crypt::DES, Crypt::DES_EDE3, Crypt::IDEA,Crypt::Blowfish, Crypt::CAST5, Crypt::Rijndael が利用可能

一般的に,CBCを利用するためには 初期化ベクタ (IV; 式上のパラメータでいうと c[-1]) を 適当に決める必要がある. デフォルトでは,Crypt::CBCはランダムにsalt値を生成し,それをもとにIV作成(とパスフレーズのハッシュ化)を行っている. saltは暗号データの先頭に付与し,復号処理と共有する.

暗号器の利用

作成した暗号器を使い,データを暗号化する方法は以下の通り. 非常に簡単だ.

# 方法その1
$cipher->start( 'encrypting' );
open( FH, "./BIG_FILE" );
$crypted =. $cipher->crypt( $buf ) while ( read(FH, $buf, 1024) );
$crypted =. $cipher->finish;
    
# 方法その2 (より簡単な方法)
$crypted = $cipher->encrypt( $plaintext );

復号する場合も似たようにやれば良い.

# 方法その1
$cipher->start( 'decrypting' );
open( FH, "./BIG_CRYPT_FILE" );
$plain =. $cipher->crypt( $buf ) while ( read(FH, $buf, 1024) );
$plain =. $cipher->finish;
    
# 方法その2 (より簡単な方法)
$plain = $cipher->decrypt( $crypted_data );

暗号化データをバイナリではなくてテキストとして使用したい場合(例えば e-mail の本文に張り付けるなど),暗号データを16進表現するメソッドが用意されている.

# 暗号化.unpack('H*', $cipher->encrypt( $plaintext )) と等価
$crypted_hex = $cipher->encrypt_hex( $plaintext );
# '53616c7465645f5f7683738451b858c8497fcd081044f63b' のようになる
print $crypted_hex . "\n";
    
# 復号
$plain = $cipher->decrypt_hex( $crypted_hex );

速度に関する備考

Crypt::CBCの perldocには,速度が等価なSSLeayプログラムに比して10倍ほど遅いとの記述がある. 速度を求めるなら直接Cライブラリを叩いたほうがいいかもしれない.