AES暗号を復号化する必要があってググってみたところ、以下の記事を発見。
狐の王国 perlによるAESベンチ
さすがに6年も前の記事だし、自分でもちゃんとベンチマークは取ってみよう、と思って調べてみた。
- Crypt::Rijndael - Crypt::CBC compliant Rijndael encryption module - metacpan.org
- Crypt::OpenSSL::AES - A Perl wrapper around OpenSSL's AES library - metacpan.org
- Crypt::GCrypt - Perl interface to the GNU Cryptographic library - metacpan.org
復号化に使えるものとしてこのへんがあるのは変わっていない模様。
Crypt::RijndaelとCrypt::OpenSSL::AESはそのまま使うとちょっと面倒なのでCrypt::ECBを通して利用する(CBCの方が良いのだと思うけど、とりあえずECBで)。一応クラスメソッドから呼ぶ場合とインスタンス化したものを使い回した場合を比較する。Crypt::GCryptはCrypt::ECBからは使えないので通常の使い方で。
適当なデータを暗号化したものとそれに利用した鍵を用意しておき、ただそれを復号化するだけの処理を繰り返す。
#!/usr/bin/env perl use strict; use warnings; use Benchmark qw(cmpthese); use Crypt::ECB; use Crypt::GCrypt; use Crypt::OpenSSL::AES; use Crypt::Rijndael; print <<"INFO" Perl $^V Crypt::ECB $Crypt::ECB::VERSION Crypt::GCrypt $Crypt::GCrypt::VERSION Crypt::OpenSSL::AES $Crypt::OpenSSL::AES::VERSION Crypt::Rijndael $Crypt::Rijndael::VERSION INFO ; my $key = join '', map { sprintf '%x', rand 16 } 1 .. 32; my $plain = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; my $encrypted = Crypt::ECB::encrypt($key, 'Rijndael', $plain, PADDING_AUTO); # Crypt::Rijndael my $rijndael = Crypt::ECB->new($key, 'Rijndael'); $rijndael->padding(PADDING_AUTO); # Crypt::OpenSSL::AES my $openssl = Crypt::ECB->new($key, 'OpenSSL::AES'); $openssl->padding(PADDING_AUTO); # Crypt::GCrypt my $gcrypt = Crypt::GCrypt->new( type => 'cipher', algorithm => 'aes256', mode => 'ecb', ); $gcrypt->setkey($key); # benchmark cmpthese(200000, +{ 'Rijndael 1' => sub { my $decrypted = Crypt::ECB::decrypt($key, 'Rijndael', $encrypted, PADDING_AUTO); die unless $decrypted eq $plain; }, 'Rijndael 2' => sub { my $decrypted = $rijndael->decrypt($encrypted); die unless $decrypted eq $plain; }, 'OpenSSL::AES 1' => sub { my $decrypted = Crypt::ECB::decrypt($key, 'OpenSSL::AES', $encrypted, PADDING_AUTO); die unless $decrypted eq $plain; }, 'OpenSSL::AES 2' => sub { my $decrypted = $openssl->decrypt($encrypted); die unless $decrypted eq $plain; }, 'GCrypt' => sub { $gcrypt->start('decrypting'); my $decrypted = $gcrypt->decrypt($encrypted); $decrypted .= $gcrypt->finish; die unless $decrypted eq $plain; }, }); __END__ Perl v5.16.0 Crypt::ECB 1.45 Crypt::GCrypt 1.25 Crypt::OpenSSL::AES 0.02 Crypt::Rijndael 1.09 Rate Rijndael 1 OpenSSL::AES 1 Rijndael 2 OpenSSL::AES 2 GCrypt Rijndael 1 14399/s -- -2% -68% -69% -96% OpenSSL::AES 1 14717/s 2% -- -68% -69% -96% Rijndael 2 45662/s 217% 210% -- -3% -86% OpenSSL::AES 2 46838/s 225% 218% 3% -- -86% GCrypt 327869/s 2177% 2128% 618% 600% --
GCryptがとても早いようだ。RijndaelとOpenSSL::AESはそれほど大きくは違わない。当然だけどインスタンス化しておいて使った方が良い。
CBCやECBなどの暗号化モード、データサイズやpaddingなど知らないことがたくさんあって、まずちゃんと復号させるように書くところでだいぶつまずいてしまった…。