AES復号化ベンチマーク

AES暗号を復号化する必要があってググってみたところ、以下の記事を発見。
狐の王国 perlによるAESベンチ
さすがに6年も前の記事だし、自分でもちゃんとベンチマークは取ってみよう、と思って調べてみた。

復号化に使えるものとしてこのへんがあるのは変わっていない模様。

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など知らないことがたくさんあって、まずちゃんと復号させるように書くところでだいぶつまずいてしまった…。